Merge "Revert^2 "Added FuzzableDataspaces.h""
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 8da1352..1c3a4f2 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -11,286 +11,6 @@
# 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
@@ -315,6 +35,8 @@
chmod 0666 /sys/kernel/tracing/events/sched/sched_pi_setprio/enable
chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_process_exit/enable
chmod 0666 /sys/kernel/tracing/events/sched/sched_process_exit/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_process_free/enable
+ chmod 0666 /sys/kernel/tracing/events/sched/sched_process_free/enable
chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_waking/enable
chmod 0666 /sys/kernel/tracing/events/sched/sched_waking/enable
chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_wakeup_new/enable
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 32e680d..e97949e 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1802,8 +1802,8 @@
// Add linker configuration directory
ds.AddDir(LINKERCONFIG_DIR, true);
- /* Dump cgroupfs */
- ds.AddDir(CGROUPFS_DIR, true);
+ /* Dump frozen cgroupfs */
+ dump_frozen_cgroupfs();
if (ds.dump_pool_) {
WAIT_TASK_WITH_CONSENT_CHECK(DUMP_INCIDENT_REPORT_TASK, ds.dump_pool_);
@@ -4169,6 +4169,63 @@
fclose(fp);
}
+void dump_frozen_cgroupfs(const char *dir, int level,
+ int (*dump_from_fd)(const char* title, const char* path, int fd)) {
+ DIR *dirp;
+ struct dirent *d;
+ char *newpath = nullptr;
+
+ dirp = opendir(dir);
+ if (dirp == nullptr) {
+ MYLOGE("%s: %s\n", dir, strerror(errno));
+ return;
+ }
+
+ for (; ((d = readdir(dirp))); free(newpath), newpath = nullptr) {
+ if ((d->d_name[0] == '.')
+ && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
+ || (d->d_name[1] == '\0'))) {
+ continue;
+ }
+ if (d->d_type == DT_DIR) {
+ asprintf(&newpath, "%s/%s/", dir, d->d_name);
+ if (!newpath) {
+ continue;
+ }
+ if (level == 0 && !strncmp(d->d_name, "uid_", 4)) {
+ dump_frozen_cgroupfs(newpath, 1, dump_from_fd);
+ } else if (level == 1 && !strncmp(d->d_name, "pid_", 4)) {
+ char *freezer = nullptr;
+ asprintf(&freezer, "%s/%s", newpath, "cgroup.freeze");
+ if (freezer) {
+ FILE* fp = fopen(freezer, "r");
+ if (fp != NULL) {
+ int frozen;
+ fscanf(fp, "%d", &frozen);
+ if (frozen > 0) {
+ dump_files("", newpath, skip_none, dump_from_fd);
+ }
+ fclose(fp);
+ }
+ free(freezer);
+ }
+ }
+ }
+ }
+ closedir(dirp);
+}
+
+void dump_frozen_cgroupfs() {
+ if (!ds.IsZipping()) {
+ MYLOGD("Not adding cgroupfs because it's not a zipped bugreport\n");
+ return;
+ }
+ MYLOGD("Adding frozen processes from %s\n", CGROUPFS_DIR);
+ DurationReporter duration_reporter("FROZEN CGROUPFS");
+ if (PropertiesHelper::IsDryRun()) return;
+ dump_frozen_cgroupfs(CGROUPFS_DIR, 0, _add_file_from_fd);
+}
+
void Dumpstate::UpdateProgress(int32_t delta_sec) {
if (progress_ == nullptr) {
MYLOGE("UpdateProgress: progress_ not set\n");
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 773e292..852b9a8 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -637,6 +637,9 @@
/* Prints the contents of all the routing tables, both IPv4 and IPv6. */
void dump_route_tables();
+/* Dump subdirectories of cgroupfs if the corresponding process is frozen */
+void dump_frozen_cgroupfs();
+
/* Play a sound via Stagefright */
void play_sound(const char *path);
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 289c2ae..2207405 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -1131,16 +1131,15 @@
}
static int32_t copy_directory_recursive(const char* from, const char* to) {
- char *argv[] = {
- (char*) kCpPath,
- (char*) "-F", /* delete any existing destination file first (--remove-destination) */
- (char*) "-p", /* preserve timestamps, ownership, and permissions */
- (char*) "-R", /* recurse into subdirectories (DEST must be a directory) */
- (char*) "-P", /* Do not follow symlinks [default] */
- (char*) "-d", /* don't dereference symlinks */
- (char*) from,
- (char*) to
- };
+ char* argv[] =
+ {(char*)kCpPath,
+ (char*)"-F", /* delete any existing destination file first (--remove-destination) */
+ (char*)"--preserve=mode,ownership,timestamps,xattr", /* preserve properties */
+ (char*)"-R", /* recurse into subdirectories (DEST must be a directory) */
+ (char*)"-P", /* Do not follow symlinks [default] */
+ (char*)"-d", /* don't dereference symlinks */
+ (char*)from,
+ (char*)to};
LOG(DEBUG) << "Copying " << from << " to " << to;
return logwrap_fork_execvp(ARRAY_SIZE(argv), argv, nullptr, false, LOG_ALOG, false, nullptr);
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 931c5e3..1be3a69 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -191,6 +191,12 @@
}
prebuilt_etc {
+ name: "android.hardware.wifi.direct.prebuilt.xml",
+ src: "android.hardware.wifi.direct.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
name: "android.hardware.wifi.passpoint.prebuilt.xml",
src: "android.hardware.wifi.passpoint.xml",
defaults: ["frameworks_native_data_etc_defaults"],
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index 0389e57..6f579ca 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -209,13 +209,13 @@
/**
* The time in nanoseconds which the frame at given index is expected to be presented.
*/
-int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime(
+int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTimeNanos(
const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33);
/**
* The time in nanoseconds which the frame at given index needs to be ready by.
*/
-int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadline(
+int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos(
const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33);
__END_DECLS
diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h
index 509ee0e..4c83a14 100644
--- a/include/android/multinetwork.h
+++ b/include/android/multinetwork.h
@@ -216,6 +216,61 @@
*/
void android_res_cancel(int nsend_fd) __INTRODUCED_IN(29);
+/*
+ * Set the socket tag and owning UID for traffic statistics on the specified
+ * socket.
+ *
+ * Subsequent calls always replace any existing parameters. The socket tag and
+ * uid (if set) are kept when the socket is sent to another process using binder
+ * IPCs or other mechanisms such as UNIX socket fd passing. Any app can accept
+ * blame for future traffic performed on a socket originally created by another
+ * app by calling this method with its own UID (or calling
+ * android_tag_socket(int sockfd, int tag)). However, only apps holding the
+ * android.Manifest.permission#UPDATE_DEVICE_STATS permission may assign blame
+ * to another UIDs. If unset (default) the socket tag is 0, and the uid is the
+ * socket creator's uid.
+ *
+ * Returns 0 on success, or a negative POSIX error code (see errno.h) on
+ * failure.
+ *
+ * Available since API level 33.
+ */
+int android_tag_socket_with_uid(int sockfd, int tag, uid_t uid) __INTRODUCED_IN(33);
+
+/*
+ * Set the socket tag for traffic statistics on the specified socket.
+ *
+ * This function tags the socket with the caller's UID (accepting blame for
+ * future traffic performed on this socket) even if the socket was originally
+ * opened by another UID or was previously tagged by another UID. Subsequent
+ * calls always replace any existing parameters. The socket tag is kept when the
+ * socket is sent to another process using binder IPCs or other mechanisms such
+ * as UNIX socket fd passing.
+ *
+ * Returns 0 on success, or a negative POSIX error code (see errno.h) on
+ * failure.
+ *
+ * Available since API level 33.
+ */
+int android_tag_socket(int sockfd, int tag) __INTRODUCED_IN(33);
+
+/*
+ * Untag a network socket.
+ *
+ * Future traffic on this socket will no longer be associated with any
+ * previously configured tag and uid. If the socket was created by another UID
+ * or was previously tagged by another UID, calling this function will clear the
+ * statistics parameters, and thus the UID blamed for traffic on the socket will
+ * be the UID that originally created the socket, even if the socket was
+ * subsequently tagged by a different UID.
+ *
+ * Returns 0 on success, or a negative POSIX error code (see errno.h) on
+ * failure.
+ *
+ * Available since API level 33.
+ */
+int android_untag_socket(int sockfd) __INTRODUCED_IN(33);
+
__END_DECLS
#endif // ANDROID_MULTINETWORK_H
diff --git a/include/android/sensor.h b/include/android/sensor.h
index 9dc6983..45e8afc 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -256,6 +256,13 @@
* The hinge angle sensor value is returned in degrees.
*/
ASENSOR_TYPE_HINGE_ANGLE = 36,
+ /**
+ * {@link ASENSOR_TYPE_HEAD_TRACKER}
+ * reporting-mode: continuous
+ *
+ * Measures the orientation and rotational velocity of a user's head.
+ */
+ ASENSOR_TYPE_HEAD_TRACKER = 37,
};
/**
@@ -440,6 +447,38 @@
};
} AAdditionalInfoEvent;
+typedef struct AHeadTrackerEvent {
+ /**
+ * The fields rx, ry, rz are an Euler vector (rotation vector, i.e. a vector
+ * whose direction indicates the axis of rotation and magnitude indicates
+ * the angle to rotate around that axis) representing the transform from
+ * the (arbitrary, possibly slowly drifting) reference frame to the
+ * head frame. Expressed in radians. Magnitude of the vector must be
+ * in the range [0, pi], while the value of individual axes are
+ * in the range [-pi, pi].
+ */
+ float rx;
+ float ry;
+ float rz;
+
+ /**
+ * The fields vx, vy, vz are an Euler vector (rotation vector) representing
+ * the angular velocity of the head (relative to itself), in radians per
+ * second. The direction of this vector indicates the axis of rotation, and
+ * the magnitude indicates the rate of rotation.
+ */
+ float vx;
+ float vy;
+ float vz;
+
+ /**
+ * This value changes each time the reference frame is suddenly and
+ * significantly changed, for example if an orientation filter algorithm
+ * used for determining the orientation has had its state reset.
+ */
+ int32_t discontinuity_count;
+} AHeadTrackerEvent;
+
/**
* Information that describes a sensor event, refer to
* <a href="/reference/android/hardware/SensorEvent">SensorEvent</a> for additional
@@ -476,6 +515,7 @@
AHeartRateEvent heart_rate;
ADynamicSensorEvent dynamic_sensor_meta;
AAdditionalInfoEvent additional_info;
+ AHeadTrackerEvent head_tracker;
};
union {
uint64_t data[8];
diff --git a/include/ftl/concat.h b/include/ftl/concat.h
new file mode 100644
index 0000000..ded48f7
--- /dev/null
+++ b/include/ftl/concat.h
@@ -0,0 +1,84 @@
+/*
+ * 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 <ftl/details/concat.h>
+
+namespace android::ftl {
+
+// Lightweight (not allocating nor sprintf-based) concatenation.
+//
+// std::string_view name = "Volume";
+// ftl::Concat string(ftl::truncated<3>(name), ": ", -3, " dB");
+//
+// assert(string.str() == "Vol: -3 dB");
+// assert(string.c_str()[string.size()] == '\0');
+//
+template <std::size_t, typename... Ts>
+struct Concat;
+
+template <std::size_t N, typename T, typename... Ts>
+struct Concat<N, T, Ts...> : Concat<N + details::StaticString<T>::N, Ts...> {
+ explicit constexpr Concat(T v, Ts... args) { append(v, args...); }
+
+ protected:
+ constexpr Concat() = default;
+
+ constexpr void append(T v, Ts... args) {
+ using Str = details::StaticString<T>;
+ const Str str(v);
+
+ // TODO: Replace with constexpr std::copy in C++20.
+ for (auto it = str.view.begin(); it != str.view.end();) {
+ *this->end_++ = *it++;
+ }
+
+ using Base = Concat<N + Str::N, Ts...>;
+ this->Base::append(args...);
+ }
+};
+
+template <std::size_t N>
+struct Concat<N> {
+ static constexpr std::size_t max_size() { return N; }
+ constexpr std::size_t size() const { return end_ - buffer_; }
+
+ constexpr const char* c_str() const { return buffer_; }
+
+ constexpr std::string_view str() const {
+ // TODO: Replace with {buffer_, end_} in C++20.
+ return {buffer_, size()};
+ }
+
+ protected:
+ constexpr Concat() : end_(buffer_) {}
+ constexpr void append() { *end_ = '\0'; }
+
+ char buffer_[N + 1];
+ char* end_;
+};
+
+// Deduction guide.
+template <typename... Ts>
+Concat(Ts&&...) -> Concat<0, Ts...>;
+
+template <std::size_t N>
+constexpr auto truncated(std::string_view v) {
+ return details::Truncated<N>{v};
+}
+
+} // namespace android::ftl
diff --git a/include/ftl/details/concat.h b/include/ftl/details/concat.h
new file mode 100644
index 0000000..8ce949e
--- /dev/null
+++ b/include/ftl/details/concat.h
@@ -0,0 +1,62 @@
+/*
+ * 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 <functional>
+#include <string_view>
+
+#include <ftl/string.h>
+
+namespace android::ftl::details {
+
+template <typename T, typename = void>
+struct StaticString;
+
+template <typename T>
+struct StaticString<T, std::enable_if_t<std::is_integral_v<T>>> {
+ static constexpr std::size_t N = to_chars_length_v<T>;
+
+ explicit StaticString(T v) : view(to_chars(buffer, v)) {}
+
+ to_chars_buffer_t<T> buffer;
+ const std::string_view view;
+};
+
+template <std::size_t M>
+struct StaticString<const char (&)[M], void> {
+ static constexpr std::size_t N = M - 1;
+
+ explicit constexpr StaticString(const char (&str)[M]) : view(str, N) {}
+
+ const std::string_view view;
+};
+
+template <std::size_t N>
+struct Truncated {
+ std::string_view view;
+};
+
+template <std::size_t M>
+struct StaticString<Truncated<M>, void> {
+ static constexpr std::size_t N = M;
+
+ explicit constexpr StaticString(Truncated<M> str) : view(str.view.substr(0, N)) {}
+
+ const std::string_view view;
+};
+
+} // namespace android::ftl::details
diff --git a/include/input/Input.h b/include/input/Input.h
index ddff144..f4147a0 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -31,10 +31,8 @@
#include <stdint.h>
#include <ui/Transform.h>
#include <utils/BitSet.h>
-#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
#include <utils/Timers.h>
-#include <utils/Vector.h>
#include <array>
#include <limits>
#include <queue>
@@ -88,7 +86,7 @@
*/
AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE = 0x40,
-#ifdef __linux__
+#if defined(__linux__)
/**
* This event was generated or modified by accessibility service.
*/
@@ -799,11 +797,11 @@
// Low-level accessors.
inline const PointerProperties* getPointerProperties() const {
- return mPointerProperties.array();
+ return mPointerProperties.data();
}
inline const nsecs_t* getSampleEventTimes() const { return mSampleEventTimes.data(); }
inline const PointerCoords* getSamplePointerCoords() const {
- return mSamplePointerCoords.array();
+ return mSamplePointerCoords.data();
}
static const char* getLabel(int32_t axis);
@@ -834,9 +832,9 @@
float mRawYCursorPosition;
ui::Transform mRawTransform;
nsecs_t mDownTime;
- Vector<PointerProperties> mPointerProperties;
+ std::vector<PointerProperties> mPointerProperties;
std::vector<nsecs_t> mSampleEventTimes;
- Vector<PointerCoords> mSamplePointerCoords;
+ std::vector<PointerCoords> mSamplePointerCoords;
};
/*
diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h
index 451ca3c..f6f8939 100644
--- a/include/input/KeyCharacterMap.h
+++ b/include/input/KeyCharacterMap.h
@@ -84,7 +84,7 @@
const std::string getLoadFileName() const;
- /* Combines this key character map with an overlay. */
+ /* Combines this key character map with the provided overlay. */
void combine(const KeyCharacterMap& overlay);
/* Gets the keyboard type. */
@@ -144,6 +144,8 @@
bool operator==(const KeyCharacterMap& other) const;
+ bool operator!=(const KeyCharacterMap& other) const;
+
KeyCharacterMap(const KeyCharacterMap& other);
virtual ~KeyCharacterMap();
@@ -230,11 +232,12 @@
KeyedVector<int32_t, Key*> mKeys;
KeyboardType mType;
std::string mLoadFileName;
+ bool mLayoutOverlayApplied;
KeyedVector<int32_t, int32_t> mKeysByScanCode;
KeyedVector<int32_t, int32_t> mKeysByUsageCode;
- KeyCharacterMap();
+ KeyCharacterMap(const std::string& filename);
bool getKey(int32_t keyCode, const Key** outKey) const;
bool getKeyBehavior(int32_t keyCode, int32_t metaState,
@@ -243,8 +246,6 @@
bool findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const;
- static base::Result<std::shared_ptr<KeyCharacterMap>> load(Tokenizer* tokenizer, Format format);
-
static void addKey(Vector<KeyEvent>& outEvents,
int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time);
static void addMetaKeys(Vector<KeyEvent>& outEvents,
@@ -264,6 +265,15 @@
int32_t deviceId, int32_t metaState, nsecs_t time,
int32_t keyCode, int32_t keyMetaState,
int32_t* currentMetaState);
+
+ /* Clears all data stored in this key character map */
+ void clear();
+
+ /* Loads the KeyCharacterMap provided by the tokenizer into this instance. */
+ status_t load(Tokenizer* tokenizer, Format format);
+
+ /* Reloads the data from mLoadFileName and unapplies any overlay. */
+ status_t reloadBaseFromFile();
};
} // namespace android
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 9abe4b5..269b086 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -320,11 +320,6 @@
//
// Note that this is not race-free if the context manager
// dies while this code runs.
- //
- // TODO: add a driver API to wait for context manager, or
- // stop special casing handle 0 for context manager and add
- // a driver API to get a handle to the context manager with
- // proper reference counting.
IPCThreadState* ipc = IPCThreadState::self();
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index f5abb85..7067830 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -93,20 +93,20 @@
// ----------------------------------------------------------------------
-#define DECLARE_META_INTERFACE(INTERFACE) \
-public: \
- static const ::android::String16 descriptor; \
- static ::android::sp<I##INTERFACE> asInterface( \
- const ::android::sp<::android::IBinder>& obj); \
- virtual const ::android::String16& getInterfaceDescriptor() const; \
- I##INTERFACE(); \
- virtual ~I##INTERFACE(); \
- static bool setDefaultImpl(std::unique_ptr<I##INTERFACE> impl); \
- static const std::unique_ptr<I##INTERFACE>& getDefaultImpl(); \
-private: \
- static std::unique_ptr<I##INTERFACE> default_impl; \
-public: \
-
+#define DECLARE_META_INTERFACE(INTERFACE) \
+public: \
+ static const ::android::String16 descriptor; \
+ static ::android::sp<I##INTERFACE> asInterface(const ::android::sp<::android::IBinder>& obj); \
+ virtual const ::android::String16& getInterfaceDescriptor() const; \
+ I##INTERFACE(); \
+ virtual ~I##INTERFACE(); \
+ static bool setDefaultImpl(::android::sp<I##INTERFACE> impl); \
+ static const ::android::sp<I##INTERFACE>& getDefaultImpl(); \
+ \
+private: \
+ static ::android::sp<I##INTERFACE> default_impl; \
+ \
+public:
#define __IINTF_CONCAT(x, y) (x ## y)
@@ -142,8 +142,8 @@
} \
return intr; \
} \
- std::unique_ptr<ITYPE> ITYPE::default_impl; \
- bool ITYPE::setDefaultImpl(std::unique_ptr<ITYPE> impl) { \
+ ::android::sp<ITYPE> ITYPE::default_impl; \
+ bool ITYPE::setDefaultImpl(::android::sp<ITYPE> impl) { \
/* Only one user of this interface can use this function */ \
/* at a time. This is a heuristic to detect if two different */ \
/* users in the same process use this function. */ \
@@ -154,7 +154,7 @@
} \
return false; \
} \
- const std::unique_ptr<ITYPE>& ITYPE::getDefaultImpl() { return ITYPE::default_impl; } \
+ const ::android::sp<ITYPE>& ITYPE::getDefaultImpl() { return ITYPE::default_impl; } \
ITYPE::INAME() {} \
ITYPE::~INAME() {}
diff --git a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
index c903998..2c471c6 100644
--- a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
@@ -163,6 +163,15 @@
const T get() const { return mT; }
/**
+ * Release the underlying resource.
+ */
+ [[nodiscard]] T release() {
+ T a = mT;
+ mT = DEFAULT;
+ return a;
+ }
+
+ /**
* This allows the value in this class to be set from beneath it. If you call this method and
* then change the value of T*, you must take ownership of the value you are replacing and add
* ownership to the object that is put in here.
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 58fa13a..357b454 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -752,6 +752,29 @@
ASSERT_STREQ(IFoo::kIFooDescriptor, AIBinder_Class_getDescriptor(IFoo::kClass));
}
+static void addOne(int* to) {
+ if (!to) return;
+ ++(*to);
+}
+struct FakeResource : public ndk::impl::ScopedAResource<int*, addOne, nullptr> {
+ explicit FakeResource(int* a) : ScopedAResource(a) {}
+};
+
+TEST(NdkBinder_ScopedAResource, GetDelete) {
+ int deleteCount = 0;
+ { FakeResource resource(&deleteCount); }
+ EXPECT_EQ(deleteCount, 1);
+}
+
+TEST(NdkBinder_ScopedAResource, Release) {
+ int deleteCount = 0;
+ {
+ FakeResource resource(&deleteCount);
+ (void)resource.release();
+ }
+ EXPECT_EQ(deleteCount, 0);
+}
+
int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
diff --git a/libs/binder/rust/binder_tokio/lib.rs b/libs/binder/rust/binder_tokio/lib.rs
index 91047be..47dcdc2 100644
--- a/libs/binder/rust/binder_tokio/lib.rs
+++ b/libs/binder/rust/binder_tokio/lib.rs
@@ -29,7 +29,7 @@
//! [`Tokio`]: crate::Tokio
use binder::public_api::{BinderAsyncPool, BoxFuture, Strong};
-use binder::{FromIBinder, StatusCode};
+use binder::{FromIBinder, StatusCode, BinderAsyncRuntime};
use std::future::Future;
/// Retrieve an existing service for a particular interface, sleeping for a few
@@ -120,3 +120,24 @@
}
}
}
+
+/// Wrapper around Tokio runtime types for providing a runtime to a binder server.
+pub struct TokioRuntime<R>(pub R);
+
+impl BinderAsyncRuntime for TokioRuntime<tokio::runtime::Runtime> {
+ fn block_on<F: Future>(&self, future: F) -> F::Output {
+ self.0.block_on(future)
+ }
+}
+
+impl BinderAsyncRuntime for TokioRuntime<std::sync::Arc<tokio::runtime::Runtime>> {
+ fn block_on<F: Future>(&self, future: F) -> F::Output {
+ self.0.block_on(future)
+ }
+}
+
+impl BinderAsyncRuntime for TokioRuntime<tokio::runtime::Handle> {
+ fn block_on<F: Future>(&self, future: F) -> F::Output {
+ self.0.block_on(future)
+ }
+}
diff --git a/libs/binder/rust/src/binder_async.rs b/libs/binder/rust/src/binder_async.rs
index 214c0b5..579f9f9 100644
--- a/libs/binder/rust/src/binder_async.rs
+++ b/libs/binder/rust/src/binder_async.rs
@@ -53,3 +53,9 @@
B: Send + 'a,
E: From<crate::StatusCode>;
}
+
+/// A runtime for executing an async binder server.
+pub trait BinderAsyncRuntime {
+ /// Block on the provided future, running it to completion and returning its output.
+ fn block_on<F: Future>(&self, future: F) -> F::Output;
+}
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index 7c04a72..20d90f7 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -112,7 +112,7 @@
Stability, Strong, ToAsyncInterface, ToSyncInterface, TransactionCode, TransactionFlags, Weak,
FIRST_CALL_TRANSACTION, FLAG_CLEAR_BUF, FLAG_ONEWAY, FLAG_PRIVATE_LOCAL, LAST_CALL_TRANSACTION,
};
-pub use crate::binder_async::{BoxFuture, BinderAsyncPool};
+pub use crate::binder_async::{BoxFuture, BinderAsyncPool, BinderAsyncRuntime};
pub use error::{status_t, ExceptionCode, Result, Status, StatusCode};
pub use native::{add_service, force_lazy_services_persist, is_handling_transaction, register_lazy_service, Binder};
pub use parcel::{BorrowedParcel, Parcel};
diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs
index 206b90c..256fa8b 100644
--- a/libs/binder/rust/src/parcel.rs
+++ b/libs/binder/rust/src/parcel.rs
@@ -496,7 +496,7 @@
{
let start = self.get_data_position();
let parcelable_size: i32 = self.read()?;
- if parcelable_size < 0 {
+ if parcelable_size < 4 {
return Err(StatusCode::BAD_VALUE);
}
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index ca68b99..c2639e7 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -1517,10 +1517,11 @@
auto keepAlive = sp<BBinder>::make();
auto setRpcClientDebugStatus = binder->setRpcClientDebug(std::move(socket), keepAlive);
- if (!android::base::GetBoolProperty("ro.debuggable", false)) {
+ if (!android::base::GetBoolProperty("ro.debuggable", false) ||
+ android::base::GetProperty("ro.build.type", "") == "user") {
ASSERT_EQ(INVALID_OPERATION, setRpcClientDebugStatus)
- << "setRpcClientDebug should return INVALID_OPERATION on non-debuggable builds, "
- "but get "
+ << "setRpcClientDebug should return INVALID_OPERATION on non-debuggable or user "
+ "builds, but get "
<< statusToString(setRpcClientDebugStatus);
GTEST_SKIP();
}
diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp
index 5a80ad0..bc2eb23 100644
--- a/libs/ftl/Android.bp
+++ b/libs/ftl/Android.bp
@@ -16,6 +16,7 @@
srcs: [
"Flags_test.cpp",
"cast_test.cpp",
+ "concat_test.cpp",
"enum_test.cpp",
"future_test.cpp",
"small_map_test.cpp",
diff --git a/libs/ftl/concat_test.cpp b/libs/ftl/concat_test.cpp
new file mode 100644
index 0000000..8ecb1b2
--- /dev/null
+++ b/libs/ftl/concat_test.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ftl/concat.h>
+#include <gtest/gtest.h>
+
+namespace android::test {
+
+// Keep in sync with example usage in header file.
+TEST(Concat, Example) {
+ std::string_view name = "Volume";
+ ftl::Concat string(ftl::truncated<3>(name), ": ", -3, " dB");
+
+ EXPECT_EQ(string.str(), "Vol: -3 dB");
+ EXPECT_EQ(string.c_str()[string.size()], '\0');
+}
+
+namespace {
+
+static_assert(ftl::Concat{"foo"}.str() == "foo");
+static_assert(ftl::Concat{ftl::truncated<3>("foobar")}.str() == "foo");
+
+constexpr ftl::Concat kConcat{"po", "trz", "ebie"};
+
+static_assert(kConcat.size() == 9);
+static_assert(kConcat.max_size() == 9);
+static_assert(kConcat.str() == "potrzebie");
+static_assert(kConcat.str() == std::string_view(kConcat.c_str()));
+
+constexpr auto concat() {
+ return ftl::Concat{ftl::truncated<1>("v???"), ftl::truncated<2>("ee??"),
+ ftl::truncated<3>("ble?"), ftl::truncated<4>("fetz"),
+ ftl::truncated<90>("er")};
+}
+
+static_assert(concat().size() == 12);
+static_assert(concat().max_size() == 100);
+static_assert(concat().str() == "veeblefetzer");
+static_assert(concat().str() == std::string_view(concat().c_str()));
+
+} // namespace
+} // namespace android::test
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 34faf87..dd96683 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -119,16 +119,11 @@
if (needsDisconnect != nullptr) *needsDisconnect = disconnect;
}
-void BLASTBufferItemConsumer::setBlastBufferQueue(BLASTBufferQueue* blastbufferqueue) {
- std::scoped_lock lock(mBufferQueueMutex);
- mBLASTBufferQueue = blastbufferqueue;
-}
-
void BLASTBufferItemConsumer::onSidebandStreamChanged() {
- std::scoped_lock lock(mBufferQueueMutex);
- if (mBLASTBufferQueue != nullptr) {
+ sp<BLASTBufferQueue> bbq = mBLASTBufferQueue.promote();
+ if (bbq != nullptr) {
sp<NativeHandle> stream = getSidebandStream();
- mBLASTBufferQueue->setSidebandStream(stream);
+ bbq->setSidebandStream(stream);
}
}
@@ -148,7 +143,7 @@
mBufferItemConsumer = new BLASTBufferItemConsumer(mConsumer,
GraphicBuffer::USAGE_HW_COMPOSER |
GraphicBuffer::USAGE_HW_TEXTURE,
- 1, false);
+ 1, false, this);
static int32_t id = 0;
mName = name + "#" + std::to_string(id);
auto consumerName = mName + "(BLAST Consumer)" + std::to_string(id);
@@ -157,7 +152,6 @@
mBufferItemConsumer->setName(String8(consumerName.c_str()));
mBufferItemConsumer->setFrameAvailableListener(this);
mBufferItemConsumer->setBufferFreedListener(this);
- mBufferItemConsumer->setBlastBufferQueue(this);
ComposerService::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers);
mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers);
@@ -174,7 +168,6 @@
}
BLASTBufferQueue::~BLASTBufferQueue() {
- mBufferItemConsumer->setBlastBufferQueue(nullptr);
if (mPendingTransactions.empty()) {
return;
}
@@ -197,13 +190,15 @@
SurfaceComposerClient::Transaction t;
const bool surfaceControlChanged = !SurfaceControl::isSameSurface(mSurfaceControl, surface);
+ if (surfaceControlChanged && mSurfaceControl != nullptr) {
+ BQA_LOGD("Updating SurfaceControl without recreating BBQ");
+ }
bool applyTransaction = false;
// Always update the native object even though they might have the same layer handle, so we can
// get the updated transform hint from WM.
mSurfaceControl = surface;
if (surfaceControlChanged) {
- BQA_LOGD("Updating SurfaceControl without recreating BBQ");
t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure,
layer_state_t::eEnableBackpressure);
applyTransaction = true;
@@ -507,8 +502,7 @@
std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */,
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
sp<Fence> fence = bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE;
- t->setBuffer(mSurfaceControl, buffer, fence, bufferItem.mFrameNumber, releaseCallbackId,
- releaseBufferCallback);
+ t->setBuffer(mSurfaceControl, buffer, fence, bufferItem.mFrameNumber, releaseBufferCallback);
t->setDataspace(mSurfaceControl, static_cast<ui::Dataspace>(bufferItem.mDataSpace));
t->setHdrMetadata(mSurfaceControl, bufferItem.mHdrMetadata);
t->setSurfaceDamageRegion(mSurfaceControl, bufferItem.mSurfaceDamage);
@@ -622,7 +616,7 @@
if (bufferData) {
BQA_LOGD("Releasing previous buffer when syncing: framenumber=%" PRIu64,
bufferData->frameNumber);
- releaseBuffer(bufferData->releaseCallbackId, bufferData->acquireFence);
+ releaseBuffer(bufferData->generateReleaseCallbackId(), bufferData->acquireFence);
// Because we just released a buffer, we know there's no need to wait for a free
// buffer.
mayNeedToWaitForBuffer = false;
@@ -1025,7 +1019,6 @@
mBufferItemConsumer->abandon();
mBufferItemConsumer->setFrameAvailableListener(nullptr);
mBufferItemConsumer->setBufferFreedListener(nullptr);
- mBufferItemConsumer->setBlastBufferQueue(nullptr);
}
mBufferItemConsumer = nullptr;
mConsumer = nullptr;
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 7f73013..0227043 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -428,6 +428,94 @@
return static_cast<status_t>(reply.readInt32());
}
+ // TODO(b/213909104) : Add unit tests to verify surface flinger boot time APIs
+ status_t getBootDisplayModeSupport(bool* outSupport) const override {
+ Parcel data, reply;
+ status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ if (error != NO_ERROR) {
+ ALOGE("getBootDisplayModeSupport: failed to write interface token: %d", error);
+ return error;
+ }
+ error = remote()->transact(BnSurfaceComposer::GET_BOOT_DISPLAY_MODE_SUPPORT, data, &reply);
+ if (error != NO_ERROR) {
+ ALOGE("getBootDisplayModeSupport: failed to transact: %d", error);
+ return error;
+ }
+ bool support;
+ error = reply.readBool(&support);
+ if (error != NO_ERROR) {
+ ALOGE("getBootDisplayModeSupport: failed to read support: %d", error);
+ return error;
+ }
+ *outSupport = support;
+ return NO_ERROR;
+ }
+
+ status_t setBootDisplayMode(const sp<IBinder>& display,
+ ui::DisplayModeId displayModeId) override {
+ Parcel data, reply;
+ status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ if (result != NO_ERROR) {
+ ALOGE("setBootDisplayMode failed to writeInterfaceToken: %d", result);
+ return result;
+ }
+ result = data.writeStrongBinder(display);
+ if (result != NO_ERROR) {
+ ALOGE("setBootDisplayMode failed to writeStrongBinder: %d", result);
+ return result;
+ }
+ result = data.writeInt32(displayModeId);
+ if (result != NO_ERROR) {
+ ALOGE("setBootDisplayMode failed to writeIint32: %d", result);
+ return result;
+ }
+ result = remote()->transact(BnSurfaceComposer::SET_BOOT_DISPLAY_MODE, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("setBootDisplayMode failed to transact: %d", result);
+ }
+ return result;
+ }
+
+ status_t clearBootDisplayMode(const sp<IBinder>& display) override {
+ Parcel data, reply;
+ status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ if (result != NO_ERROR) {
+ ALOGE("clearBootDisplayMode failed to writeInterfaceToken: %d", result);
+ return result;
+ }
+ result = data.writeStrongBinder(display);
+ if (result != NO_ERROR) {
+ ALOGE("clearBootDisplayMode failed to writeStrongBinder: %d", result);
+ return result;
+ }
+ result = remote()->transact(BnSurfaceComposer::CLEAR_BOOT_DISPLAY_MODE, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("clearBootDisplayMode failed to transact: %d", result);
+ }
+ return result;
+ }
+
+ status_t getPreferredBootDisplayMode(const sp<IBinder>& display,
+ ui::DisplayModeId* displayModeId) override {
+ Parcel data, reply;
+ status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ if (result != NO_ERROR) {
+ ALOGE("getPreferredBootDisplayMode failed to writeInterfaceToken: %d", result);
+ return result;
+ }
+ result = data.writeStrongBinder(display);
+ if (result != NO_ERROR) {
+ ALOGE("getPreferredBootDisplayMode failed to writeStrongBinder: %d", result);
+ return result;
+ }
+ result = remote()->transact(BnSurfaceComposer::GET_PREFERRED_BOOT_DISPLAY_MODE, data,
+ &reply);
+ if (result == NO_ERROR) {
+ reply.writeInt32(*displayModeId);
+ }
+ return result;
+ }
+
void setAutoLowLatencyMode(const sp<IBinder>& display, bool on) override {
Parcel data, reply;
status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -1134,6 +1222,34 @@
return NO_ERROR;
}
+ status_t getDisplayDecorationSupport(const sp<IBinder>& displayToken,
+ bool* outSupport) const override {
+ Parcel data, reply;
+ status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ if (error != NO_ERROR) {
+ ALOGE("getDisplayDecorationSupport: failed to write interface token: %d", error);
+ return error;
+ }
+ error = data.writeStrongBinder(displayToken);
+ if (error != NO_ERROR) {
+ ALOGE("getDisplayDecorationSupport: failed to write display token: %d", error);
+ return error;
+ }
+ error = remote()->transact(BnSurfaceComposer::GET_DISPLAY_DECORATION_SUPPORT, data, &reply);
+ if (error != NO_ERROR) {
+ ALOGE("getDisplayDecorationSupport: failed to transact: %d", error);
+ return error;
+ }
+ bool support;
+ error = reply.readBool(&support);
+ if (error != NO_ERROR) {
+ ALOGE("getDisplayDecorationSupport: failed to read support: %d", error);
+ return error;
+ }
+ *outSupport = support;
+ return NO_ERROR;
+ }
+
status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
int8_t compatibility, int8_t changeFrameRateStrategy) override {
Parcel data, reply;
@@ -1493,6 +1609,56 @@
result = reply->writeInt32(result);
return result;
}
+ case GET_BOOT_DISPLAY_MODE_SUPPORT: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ bool support = false;
+ status_t result = getBootDisplayModeSupport(&support);
+ if (result == NO_ERROR) {
+ reply->writeBool(support);
+ }
+ return result;
+ }
+ case SET_BOOT_DISPLAY_MODE: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> display = nullptr;
+ status_t result = data.readStrongBinder(&display);
+ if (result != NO_ERROR) {
+ ALOGE("setBootDisplayMode failed to readStrongBinder: %d", result);
+ return result;
+ }
+ ui::DisplayModeId displayModeId;
+ result = data.readInt32(&displayModeId);
+ if (result != NO_ERROR) {
+ ALOGE("setBootDisplayMode failed to readInt32: %d", result);
+ return result;
+ }
+ return setBootDisplayMode(display, displayModeId);
+ }
+ case CLEAR_BOOT_DISPLAY_MODE: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> display = nullptr;
+ status_t result = data.readStrongBinder(&display);
+ if (result != NO_ERROR) {
+ ALOGE("clearBootDisplayMode failed to readStrongBinder: %d", result);
+ return result;
+ }
+ return clearBootDisplayMode(display);
+ }
+ case GET_PREFERRED_BOOT_DISPLAY_MODE: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> display = nullptr;
+ status_t result = data.readStrongBinder(&display);
+ if (result != NO_ERROR) {
+ ALOGE("getPreferredBootDisplayMode failed to readStrongBinder: %d", result);
+ return result;
+ }
+ ui::DisplayModeId displayModeId;
+ result = getPreferredBootDisplayMode(display, &displayModeId);
+ if (result == NO_ERROR) {
+ reply->writeInt32(displayModeId);
+ }
+ return result;
+ }
case SET_AUTO_LOW_LATENCY_MODE: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> display = nullptr;
@@ -2016,6 +2182,19 @@
return setGlobalShadowSettings(ambientColor, spotColor, lightPosY, lightPosZ,
lightRadius);
}
+ case GET_DISPLAY_DECORATION_SUPPORT: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> displayToken;
+ status_t error = data.readNullableStrongBinder(&displayToken);
+ if (error != NO_ERROR) {
+ ALOGE("getDisplayDecorationSupport: failed to read display token: %d", error);
+ return error;
+ }
+ bool support = false;
+ error = getDisplayDecorationSupport(displayToken, &support);
+ reply->writeBool(support);
+ return error;
+ }
case SET_FRAME_RATE: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> binder;
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index ec0573a..27d86bb 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -153,7 +153,8 @@
SAFE_PARCEL(output.writeBool, isTrustedOverlay);
SAFE_PARCEL(output.writeUint32, static_cast<uint32_t>(dropInputMode));
- SAFE_PARCEL(bufferData.write, output);
+ SAFE_PARCEL(output.writeNullableParcelable,
+ bufferData ? std::make_optional<BufferData>(*bufferData) : std::nullopt);
return NO_ERROR;
}
@@ -263,7 +264,9 @@
uint32_t mode;
SAFE_PARCEL(input.readUint32, &mode);
dropInputMode = static_cast<gui::DropInputMode>(mode);
- SAFE_PARCEL(bufferData.read, input);
+ std::optional<BufferData> tmpBufferData;
+ SAFE_PARCEL(input.readParcelable, &tmpBufferData);
+ bufferData = tmpBufferData ? std::make_shared<BufferData>(*tmpBufferData) : nullptr;
return NO_ERROR;
}
@@ -518,7 +521,7 @@
}
bool layer_state_t::hasValidBuffer() const {
- return bufferData.buffer || bufferData.cachedBuffer.isValid();
+ return bufferData && (bufferData->buffer || bufferData->cachedBuffer.isValid());
}
status_t layer_state_t::matrix22_t::write(Parcel& output) const {
@@ -677,64 +680,68 @@
return NO_ERROR;
}
-status_t BufferData::write(Parcel& output) const {
- SAFE_PARCEL(output.writeInt32, flags.get());
+ReleaseCallbackId BufferData::generateReleaseCallbackId() const {
+ return {buffer->getId(), frameNumber};
+}
+
+status_t BufferData::writeToParcel(Parcel* output) const {
+ SAFE_PARCEL(output->writeInt32, flags.get());
if (buffer) {
- SAFE_PARCEL(output.writeBool, true);
- SAFE_PARCEL(output.write, *buffer);
+ SAFE_PARCEL(output->writeBool, true);
+ SAFE_PARCEL(output->write, *buffer);
} else {
- SAFE_PARCEL(output.writeBool, false);
+ SAFE_PARCEL(output->writeBool, false);
}
if (acquireFence) {
- SAFE_PARCEL(output.writeBool, true);
- SAFE_PARCEL(output.write, *acquireFence);
+ SAFE_PARCEL(output->writeBool, true);
+ SAFE_PARCEL(output->write, *acquireFence);
} else {
- SAFE_PARCEL(output.writeBool, false);
+ SAFE_PARCEL(output->writeBool, false);
}
- SAFE_PARCEL(output.writeUint64, frameNumber);
- SAFE_PARCEL(output.writeStrongBinder, IInterface::asBinder(releaseBufferListener));
- SAFE_PARCEL(output.writeStrongBinder, releaseBufferEndpoint);
+ SAFE_PARCEL(output->writeUint64, frameNumber);
+ SAFE_PARCEL(output->writeStrongBinder, IInterface::asBinder(releaseBufferListener));
+ SAFE_PARCEL(output->writeStrongBinder, releaseBufferEndpoint);
- SAFE_PARCEL(output.writeStrongBinder, cachedBuffer.token.promote());
- SAFE_PARCEL(output.writeUint64, cachedBuffer.id);
+ SAFE_PARCEL(output->writeStrongBinder, cachedBuffer.token.promote());
+ SAFE_PARCEL(output->writeUint64, cachedBuffer.id);
return NO_ERROR;
}
-status_t BufferData::read(const Parcel& input) {
+status_t BufferData::readFromParcel(const Parcel* input) {
int32_t tmpInt32;
- SAFE_PARCEL(input.readInt32, &tmpInt32);
+ SAFE_PARCEL(input->readInt32, &tmpInt32);
flags = Flags<BufferDataChange>(tmpInt32);
bool tmpBool = false;
- SAFE_PARCEL(input.readBool, &tmpBool);
+ SAFE_PARCEL(input->readBool, &tmpBool);
if (tmpBool) {
buffer = new GraphicBuffer();
- SAFE_PARCEL(input.read, *buffer);
+ SAFE_PARCEL(input->read, *buffer);
}
- SAFE_PARCEL(input.readBool, &tmpBool);
+ SAFE_PARCEL(input->readBool, &tmpBool);
if (tmpBool) {
acquireFence = new Fence();
- SAFE_PARCEL(input.read, *acquireFence);
+ SAFE_PARCEL(input->read, *acquireFence);
}
- SAFE_PARCEL(input.readUint64, &frameNumber);
+ SAFE_PARCEL(input->readUint64, &frameNumber);
sp<IBinder> tmpBinder = nullptr;
- SAFE_PARCEL(input.readNullableStrongBinder, &tmpBinder);
+ SAFE_PARCEL(input->readNullableStrongBinder, &tmpBinder);
if (tmpBinder) {
releaseBufferListener = checked_interface_cast<ITransactionCompletedListener>(tmpBinder);
}
- SAFE_PARCEL(input.readNullableStrongBinder, &releaseBufferEndpoint);
+ SAFE_PARCEL(input->readNullableStrongBinder, &releaseBufferEndpoint);
tmpBinder = nullptr;
- SAFE_PARCEL(input.readNullableStrongBinder, &tmpBinder);
+ SAFE_PARCEL(input->readNullableStrongBinder, &tmpBinder);
cachedBuffer.token = tmpBinder;
- SAFE_PARCEL(input.readUint64, &cachedBuffer.id);
+ SAFE_PARCEL(input->readUint64, &cachedBuffer.id);
return NO_ERROR;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index cf04ec8..b4f6cd5 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -728,18 +728,18 @@
return;
}
- auto listener = state.bufferData.releaseBufferListener;
+ auto listener = state.bufferData->releaseBufferListener;
sp<Fence> fence =
- state.bufferData.acquireFence ? state.bufferData.acquireFence : Fence::NO_FENCE;
- if (state.bufferData.releaseBufferEndpoint ==
+ state.bufferData->acquireFence ? state.bufferData->acquireFence : Fence::NO_FENCE;
+ if (state.bufferData->releaseBufferEndpoint ==
IInterface::asBinder(TransactionCompletedListener::getIInstance())) {
// if the callback is in process, run on a different thread to avoid any lock contigency
// issues in the client.
SurfaceComposerClient::getDefault()
- ->mReleaseCallbackThread.addReleaseCallback(state.bufferData.releaseCallbackId,
- fence);
+ ->mReleaseCallbackThread
+ .addReleaseCallback(state.bufferData->generateReleaseCallbackId(), fence);
} else {
- listener->onReleaseBuffer(state.bufferData.releaseCallbackId, fence, UINT_MAX);
+ listener->onReleaseBuffer(state.bufferData->generateReleaseCallbackId(), fence, UINT_MAX);
}
}
@@ -839,7 +839,8 @@
layer_state_t* s = &(mComposerStates[handle].state);
if (!(s->what & layer_state_t::eBufferChanged)) {
continue;
- } else if (s->bufferData.flags.test(BufferData::BufferDataChange::cachedBufferChanged)) {
+ } else if (s->bufferData &&
+ s->bufferData->flags.test(BufferData::BufferDataChange::cachedBufferChanged)) {
// If eBufferChanged and eCachedBufferChanged are both trued then that means
// we already cached the buffer in a previous call to cacheBuffers, perhaps
// from writeToParcel on a Transaction that was merged in to this one.
@@ -848,22 +849,22 @@
// Don't try to cache a null buffer. Sending null buffers is cheap so we shouldn't waste
// time trying to cache them.
- if (!s->bufferData.buffer) {
+ if (!s->bufferData || !s->bufferData->buffer) {
continue;
}
uint64_t cacheId = 0;
- status_t ret = BufferCache::getInstance().getCacheId(s->bufferData.buffer, &cacheId);
+ status_t ret = BufferCache::getInstance().getCacheId(s->bufferData->buffer, &cacheId);
if (ret == NO_ERROR) {
// Cache-hit. Strip the buffer and send only the id.
- s->bufferData.buffer = nullptr;
+ s->bufferData->buffer = nullptr;
} else {
// Cache-miss. Include the buffer and send the new cacheId.
- cacheId = BufferCache::getInstance().cache(s->bufferData.buffer);
+ cacheId = BufferCache::getInstance().cache(s->bufferData->buffer);
}
- s->bufferData.flags |= BufferData::BufferDataChange::cachedBufferChanged;
- s->bufferData.cachedBuffer.token = BufferCache::getInstance().getToken();
- s->bufferData.cachedBuffer.id = cacheId;
+ s->bufferData->flags |= BufferData::BufferDataChange::cachedBufferChanged;
+ s->bufferData->cachedBuffer.token = BufferCache::getInstance().getToken();
+ s->bufferData->cachedBuffer.id = cacheId;
// If we have more buffers than the size of the cache, we should stop caching so we don't
// evict other buffers in this transaction
@@ -1322,23 +1323,22 @@
return *this;
}
-std::optional<BufferData> SurfaceComposerClient::Transaction::getAndClearBuffer(
+std::shared_ptr<BufferData> SurfaceComposerClient::Transaction::getAndClearBuffer(
const sp<SurfaceControl>& sc) {
layer_state_t* s = getLayerState(sc);
if (!s) {
- return std::nullopt;
+ return nullptr;
}
if (!(s->what & layer_state_t::eBufferChanged)) {
- return std::nullopt;
+ return nullptr;
}
- BufferData bufferData = s->bufferData;
+ std::shared_ptr<BufferData> bufferData = std::move(s->bufferData);
TransactionCompletedListener::getInstance()->removeReleaseBufferCallback(
- bufferData.releaseCallbackId);
- BufferData emptyBufferData;
+ bufferData->generateReleaseCallbackId());
s->what &= ~layer_state_t::eBufferChanged;
- s->bufferData = emptyBufferData;
+ s->bufferData = nullptr;
mContainsBuffer = false;
return bufferData;
@@ -1347,7 +1347,7 @@
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffer(
const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer,
const std::optional<sp<Fence>>& fence, const std::optional<uint64_t>& frameNumber,
- const ReleaseCallbackId& id, ReleaseBufferCallback callback) {
+ ReleaseBufferCallback callback) {
layer_state_t* s = getLayerState(sc);
if (!s) {
mStatus = BAD_INDEX;
@@ -1356,24 +1356,24 @@
releaseBufferIfOverwriting(*s);
- BufferData bufferData;
- bufferData.buffer = buffer;
+ std::shared_ptr<BufferData> bufferData = std::make_shared<BufferData>();
+ bufferData->buffer = buffer;
if (frameNumber) {
- bufferData.frameNumber = *frameNumber;
- bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged;
+ bufferData->frameNumber = *frameNumber;
+ bufferData->flags |= BufferData::BufferDataChange::frameNumberChanged;
}
if (fence) {
- bufferData.acquireFence = *fence;
- bufferData.flags |= BufferData::BufferDataChange::fenceChanged;
+ bufferData->acquireFence = *fence;
+ bufferData->flags |= BufferData::BufferDataChange::fenceChanged;
}
- bufferData.releaseBufferEndpoint =
+ bufferData->releaseBufferEndpoint =
IInterface::asBinder(TransactionCompletedListener::getIInstance());
if (mIsAutoTimestamp) {
mDesiredPresentTime = systemTime();
}
- setReleaseBufferCallback(&bufferData, id, callback);
+ setReleaseBufferCallback(bufferData.get(), callback);
s->what |= layer_state_t::eBufferChanged;
- s->bufferData = bufferData;
+ s->bufferData = std::move(bufferData);
registerSurfaceControlForCallback(sc);
mContainsBuffer = true;
@@ -1381,7 +1381,6 @@
}
void SurfaceComposerClient::Transaction::setReleaseBufferCallback(BufferData* bufferData,
- const ReleaseCallbackId& id,
ReleaseBufferCallback callback) {
if (!callback) {
return;
@@ -1394,9 +1393,8 @@
}
bufferData->releaseBufferListener = TransactionCompletedListener::getIInstance();
- bufferData->releaseCallbackId = id;
auto listener = TransactionCompletedListener::getInstance();
- listener->setReleaseBufferCallback(id, callback);
+ listener->setReleaseBufferCallback(bufferData->generateReleaseCallbackId(), callback);
}
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDataspace(
@@ -2077,6 +2075,25 @@
return ComposerService::getComposerService()->setActiveColorMode(display, colorMode);
}
+status_t SurfaceComposerClient::getBootDisplayModeSupport(bool* support) {
+ return ComposerService::getComposerService()->getBootDisplayModeSupport(support);
+}
+
+status_t SurfaceComposerClient::setBootDisplayMode(const sp<IBinder>& display,
+ ui::DisplayModeId displayModeId) {
+ return ComposerService::getComposerService()->setBootDisplayMode(display, displayModeId);
+}
+
+status_t SurfaceComposerClient::clearBootDisplayMode(const sp<IBinder>& display) {
+ return ComposerService::getComposerService()->clearBootDisplayMode(display);
+}
+
+status_t SurfaceComposerClient::getPreferredBootDisplayMode(const sp<IBinder>& display,
+ ui::DisplayModeId* displayModeId) {
+ return ComposerService::getComposerService()->getPreferredBootDisplayMode(display,
+ displayModeId);
+}
+
void SurfaceComposerClient::setAutoLowLatencyMode(const sp<IBinder>& display, bool on) {
ComposerService::getComposerService()->setAutoLowLatencyMode(display, on);
}
@@ -2218,6 +2235,12 @@
lightRadius);
}
+bool SurfaceComposerClient::getDisplayDecorationSupport(const sp<IBinder>& displayToken) {
+ bool support = false;
+ ComposerService::getComposerService()->getDisplayDecorationSupport(displayToken, &support);
+ return support;
+}
+
int SurfaceComposerClient::getGPUContextPriority() {
return ComposerService::getComposerService()->getGPUContextPriority();
}
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 8b2310d..f77cfe6 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -38,11 +38,11 @@
class BLASTBufferItemConsumer : public BufferItemConsumer {
public:
BLASTBufferItemConsumer(const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage,
- int bufferCount, bool controlledByApp)
+ int bufferCount, bool controlledByApp, wp<BLASTBufferQueue> bbq)
: BufferItemConsumer(consumer, consumerUsage, bufferCount, controlledByApp),
+ mBLASTBufferQueue(std::move(bbq)),
mCurrentlyConnected(false),
- mPreviouslyConnected(false),
- mBLASTBufferQueue(nullptr) {}
+ mPreviouslyConnected(false) {}
void onDisconnect() override;
void addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
@@ -53,21 +53,20 @@
CompositorTiming compositorTiming, nsecs_t latchTime,
nsecs_t dequeueReadyTime) REQUIRES(mMutex);
void getConnectionEvents(uint64_t frameNumber, bool* needsDisconnect);
- void setBlastBufferQueue(BLASTBufferQueue* blastbufferqueue) REQUIRES(mMutex);
protected:
void onSidebandStreamChanged() override REQUIRES(mMutex);
private:
+ const wp<BLASTBufferQueue> mBLASTBufferQueue;
+
uint64_t mCurrentFrameNumber = 0;
Mutex mMutex;
- std::mutex mBufferQueueMutex;
ConsumerFrameEventHistory mFrameEventHistory GUARDED_BY(mMutex);
std::queue<uint64_t> mDisconnectEvents GUARDED_BY(mMutex);
bool mCurrentlyConnected GUARDED_BY(mMutex);
bool mPreviouslyConnected GUARDED_BY(mMutex);
- BLASTBufferQueue* mBLASTBufferQueue GUARDED_BY(mBufferQueueMutex);
};
class BLASTBufferQueue
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 2546e4c..f37580c 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -224,6 +224,35 @@
ui::ColorMode colorMode) = 0;
/**
+ * Sets the user-preferred display mode that a device should boot in.
+ */
+ virtual status_t setBootDisplayMode(const sp<IBinder>& display, ui::DisplayModeId) = 0;
+
+ /**
+ * Clears the user-preferred display mode. The device should now boot in system preferred
+ * display mode.
+ */
+ virtual status_t clearBootDisplayMode(const sp<IBinder>& display) = 0;
+
+ /**
+ * Gets the display mode in which the device boots if there is no user-preferred display mode.
+ */
+ virtual status_t getPreferredBootDisplayMode(const sp<IBinder>& display,
+ ui::DisplayModeId*) = 0;
+
+ /**
+ * Gets whether boot time display mode operations are supported on the device.
+ *
+ * outSupport
+ * An output parameter for whether boot time display mode operations are supported.
+ *
+ * Returns NO_ERROR upon success. Otherwise,
+ * NAME_NOT_FOUND if the display is invalid, or
+ * BAD_VALUE if the output parameter is invalid.
+ */
+ virtual status_t getBootDisplayModeSupport(bool* outSupport) const = 0;
+
+ /**
* Switches Auto Low Latency Mode on/off on the connected display, if it is
* available. This should only be called if the display supports Auto Low
* Latency Mode as reported in #getDynamicDisplayInfo.
@@ -508,6 +537,22 @@
float lightRadius) = 0;
/*
+ * Gets whether a display supports DISPLAY_DECORATION layers.
+ *
+ * displayToken
+ * The token of the display.
+ * outSupport
+ * An output parameter for whether the display supports
+ * DISPLAY_DECORATION layers.
+ *
+ * Returns NO_ERROR upon success. Otherwise,
+ * NAME_NOT_FOUND if the display is invalid, or
+ * BAD_VALUE if the output parameter is invalid.
+ */
+ virtual status_t getDisplayDecorationSupport(const sp<IBinder>& displayToken,
+ bool* outSupport) const = 0;
+
+ /*
* Sets the intended frame rate for a surface. See ANativeWindow_setFrameRate() for more info.
*/
virtual status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
@@ -628,6 +673,11 @@
ADD_WINDOW_INFOS_LISTENER,
REMOVE_WINDOW_INFOS_LISTENER,
GET_PRIMARY_PHYSICAL_DISPLAY_ID,
+ GET_DISPLAY_DECORATION_SUPPORT,
+ GET_BOOT_DISPLAY_MODE_SUPPORT,
+ SET_BOOT_DISPLAY_MODE,
+ CLEAR_BOOT_DISPLAY_MODE,
+ GET_PREFERRED_BOOT_DISPLAY_MODE,
// Always append new enum to the end.
};
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index a0d3162..968ace9 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -58,7 +58,22 @@
bool isValid() const { return token != nullptr; }
};
-struct BufferData {
+class BufferData : public Parcelable {
+public:
+ virtual ~BufferData() = default;
+ virtual bool hasBuffer() const { return buffer != nullptr; }
+ virtual bool hasSameBuffer(const BufferData& other) const {
+ return buffer == other.buffer && frameNumber == other.frameNumber;
+ }
+ virtual uint32_t getWidth() const { return buffer->getWidth(); }
+ virtual uint32_t getHeight() const { return buffer->getHeight(); }
+ Rect getBounds() const {
+ return {0, 0, static_cast<int32_t>(getWidth()), static_cast<int32_t>(getHeight())};
+ }
+ virtual uint64_t getId() const { return buffer->getId(); }
+ virtual PixelFormat getPixelFormat() const { return buffer->getPixelFormat(); }
+ virtual uint64_t getUsage() const { return buffer->getUsage(); }
+
enum class BufferDataChange : uint32_t {
fenceChanged = 0x01,
frameNumberChanged = 0x02,
@@ -77,12 +92,6 @@
// buffer id to identify the buffer.
sp<ITransactionCompletedListener> releaseBufferListener = nullptr;
- // Keeps track of the release callback id associated with the listener. This
- // is not sent to the server since the id can be reconstructed there. This
- // is used to remove the old callback from the client process map if it is
- // overwritten by another setBuffer call.
- ReleaseCallbackId releaseCallbackId = ReleaseCallbackId::INVALID_ID;
-
// Stores which endpoint the release information should be sent to. We don't want to send the
// releaseCallbackId and release fence to all listeners so we store which listener the setBuffer
// was called with.
@@ -92,8 +101,12 @@
client_cache_t cachedBuffer;
- status_t write(Parcel& output) const;
- status_t read(const Parcel& input);
+ // Generates the release callback id based on the buffer id and frame number.
+ // This is used as an identifier when release callbacks are invoked.
+ ReleaseCallbackId generateReleaseCallbackId() const;
+
+ status_t writeToParcel(Parcel* parcel) const override;
+ status_t readFromParcel(const Parcel* parcel) override;
};
/*
@@ -207,7 +220,7 @@
uint32_t transform;
bool transformToDisplayInverse;
Rect crop;
- BufferData bufferData;
+ std::shared_ptr<BufferData> bufferData = nullptr;
ui::Dataspace dataspace;
HdrMetadata hdrMetadata;
Region surfaceDamageRegion;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 17b4846..c192323 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -167,6 +167,15 @@
static status_t setActiveColorMode(const sp<IBinder>& display,
ui::ColorMode colorMode);
+ // Gets if boot display mode operations are supported on a device
+ static status_t getBootDisplayModeSupport(bool* support);
+ // Sets the user-preferred display mode that a device should boot in
+ static status_t setBootDisplayMode(const sp<IBinder>& display, ui::DisplayModeId);
+ // Clears the user-preferred display mode
+ static status_t clearBootDisplayMode(const sp<IBinder>& display);
+ // Gets the display mode in which the device boots if there is no user-preferred display mode
+ static status_t getPreferredBootDisplayMode(const sp<IBinder>& display, ui::DisplayModeId*);
+
// Switches on/off Auto Low Latency Mode on the connected display. This should only be
// called if the connected display supports Auto Low Latency Mode as reported by
// #getAutoLowLatencyModeSupport
@@ -272,6 +281,16 @@
static status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
float lightPosY, float lightPosZ, float lightRadius);
+ /*
+ * Returns whether a display supports DISPLAY_DECORATION layers.
+ *
+ * displayToken
+ * The token of the display.
+ *
+ * Returns whether a display supports DISPLAY_DECORATION layers.
+ */
+ static bool getDisplayDecorationSupport(const sp<IBinder>& displayToken);
+
// ------------------------------------------------------------------------
// surface creation / destruction
@@ -416,7 +435,7 @@
void cacheBuffers();
void registerSurfaceControlForCallback(const sp<SurfaceControl>& sc);
- void setReleaseBufferCallback(BufferData*, const ReleaseCallbackId&, ReleaseBufferCallback);
+ void setReleaseBufferCallback(BufferData*, ReleaseBufferCallback);
public:
Transaction();
@@ -490,9 +509,8 @@
Transaction& setBuffer(const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer,
const std::optional<sp<Fence>>& fence = std::nullopt,
const std::optional<uint64_t>& frameNumber = std::nullopt,
- const ReleaseCallbackId& id = ReleaseCallbackId::INVALID_ID,
ReleaseBufferCallback callback = nullptr);
- std::optional<BufferData> getAndClearBuffer(const sp<SurfaceControl>& sc);
+ std::shared_ptr<BufferData> getAndClearBuffer(const sp<SurfaceControl>& sc);
Transaction& setDataspace(const sp<SurfaceControl>& sc, ui::Dataspace dataspace);
Transaction& setHdrMetadata(const sp<SurfaceControl>& sc, const HdrMetadata& hdrMetadata);
Transaction& setSurfaceDamageRegion(const sp<SurfaceControl>& sc,
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index d6ac3f9..999874b 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -755,6 +755,15 @@
}
status_t setActiveColorMode(const sp<IBinder>& /*display*/,
ColorMode /*colorMode*/) override { return NO_ERROR; }
+ status_t getBootDisplayModeSupport(bool* /*outSupport*/) const override { return NO_ERROR; }
+ status_t setBootDisplayMode(const sp<IBinder>& /*display*/, ui::DisplayModeId /*id*/) override {
+ return NO_ERROR;
+ }
+ status_t clearBootDisplayMode(const sp<IBinder>& /*display*/) override { return NO_ERROR; }
+ status_t getPreferredBootDisplayMode(const sp<IBinder>& /*display*/,
+ ui::DisplayModeId* /*id*/) override {
+ return NO_ERROR;
+ }
void setAutoLowLatencyMode(const sp<IBinder>& /*display*/, bool /*on*/) override {}
void setGameContentType(const sp<IBinder>& /*display*/, bool /*on*/) override {}
@@ -882,6 +891,11 @@
return NO_ERROR;
}
+ status_t getDisplayDecorationSupport(const sp<IBinder>& /*displayToken*/,
+ bool* /*outSupport*/) const override {
+ return NO_ERROR;
+ }
+
status_t setFrameRate(const sp<IGraphicBufferProducer>& /*surface*/, float /*frameRate*/,
int8_t /*compatibility*/, int8_t /*changeFrameRateStrategy*/) override {
return NO_ERROR;
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 84dba84..3073d94 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -456,7 +456,8 @@
mRawTransform = rawTransform;
mDownTime = downTime;
mPointerProperties.clear();
- mPointerProperties.appendArray(pointerProperties, pointerCount);
+ mPointerProperties.insert(mPointerProperties.end(), &pointerProperties[0],
+ &pointerProperties[pointerCount]);
mSampleEventTimes.clear();
mSamplePointerCoords.clear();
addSample(eventTime, pointerCoords);
@@ -490,8 +491,10 @@
mSamplePointerCoords.clear();
size_t pointerCount = other->getPointerCount();
size_t historySize = other->getHistorySize();
- mSamplePointerCoords.appendArray(other->mSamplePointerCoords.array()
- + (historySize * pointerCount), pointerCount);
+ mSamplePointerCoords
+ .insert(mSamplePointerCoords.end(),
+ &other->mSamplePointerCoords[historySize * pointerCount],
+ &other->mSamplePointerCoords[historySize * pointerCount + pointerCount]);
}
}
@@ -499,7 +502,8 @@
int64_t eventTime,
const PointerCoords* pointerCoords) {
mSampleEventTimes.push_back(eventTime);
- mSamplePointerCoords.appendArray(pointerCoords, getPointerCount());
+ mSamplePointerCoords.insert(mSamplePointerCoords.end(), &pointerCoords[0],
+ &pointerCoords[getPointerCount()]);
}
int MotionEvent::getSurfaceRotation() const {
@@ -569,7 +573,7 @@
ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const {
size_t pointerCount = mPointerProperties.size();
for (size_t i = 0; i < pointerCount; i++) {
- if (mPointerProperties.itemAt(i).id == pointerId) {
+ if (mPointerProperties[i].id == pointerId) {
return i;
}
}
@@ -591,8 +595,7 @@
size_t numSamples = mSamplePointerCoords.size();
for (size_t i = 0; i < numSamples; i++) {
- mSamplePointerCoords.editItemAt(i).scale(globalScaleFactor, globalScaleFactor,
- globalScaleFactor);
+ mSamplePointerCoords[i].scale(globalScaleFactor, globalScaleFactor, globalScaleFactor);
}
}
@@ -686,15 +689,15 @@
mDownTime = parcel->readInt64();
mPointerProperties.clear();
- mPointerProperties.setCapacity(pointerCount);
+ mPointerProperties.reserve(pointerCount);
mSampleEventTimes.clear();
mSampleEventTimes.reserve(sampleCount);
mSamplePointerCoords.clear();
- mSamplePointerCoords.setCapacity(sampleCount * pointerCount);
+ mSamplePointerCoords.reserve(sampleCount * pointerCount);
for (size_t i = 0; i < pointerCount; i++) {
- mPointerProperties.push();
- PointerProperties& properties = mPointerProperties.editTop();
+ mPointerProperties.push_back({});
+ PointerProperties& properties = mPointerProperties.back();
properties.id = parcel->readInt32();
properties.toolType = parcel->readInt32();
}
@@ -703,8 +706,8 @@
sampleCount--;
mSampleEventTimes.push_back(parcel->readInt64());
for (size_t i = 0; i < pointerCount; i++) {
- mSamplePointerCoords.push();
- status_t status = mSamplePointerCoords.editTop().readFromParcel(parcel);
+ mSamplePointerCoords.push_back({});
+ status_t status = mSamplePointerCoords.back().readFromParcel(parcel);
if (status) {
return status;
}
@@ -750,12 +753,12 @@
parcel->writeInt64(mDownTime);
for (size_t i = 0; i < pointerCount; i++) {
- const PointerProperties& properties = mPointerProperties.itemAt(i);
+ const PointerProperties& properties = mPointerProperties[i];
parcel->writeInt32(properties.id);
parcel->writeInt32(properties.toolType);
}
- const PointerCoords* pc = mSamplePointerCoords.array();
+ const PointerCoords* pc = mSamplePointerCoords.data();
for (size_t h = 0; h < sampleCount; h++) {
parcel->writeInt64(mSampleEventTimes[h]);
for (size_t i = 0; i < pointerCount; i++) {
diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp
index 3baeb55..2039fa6 100644
--- a/libs/input/KeyCharacterMap.cpp
+++ b/libs/input/KeyCharacterMap.cpp
@@ -86,10 +86,13 @@
// --- KeyCharacterMap ---
-KeyCharacterMap::KeyCharacterMap() : mType(KeyboardType::UNKNOWN) {}
+KeyCharacterMap::KeyCharacterMap(const std::string& filename)
+ : mType(KeyboardType::UNKNOWN), mLoadFileName(filename) {}
KeyCharacterMap::KeyCharacterMap(const KeyCharacterMap& other)
: mType(other.mType),
+ mLoadFileName(other.mLoadFileName),
+ mLayoutOverlayApplied(other.mLayoutOverlayApplied),
mKeysByScanCode(other.mKeysByScanCode),
mKeysByUsageCode(other.mKeysByUsageCode) {
for (size_t i = 0; i < other.mKeys.size(); i++) {
@@ -98,16 +101,19 @@
}
KeyCharacterMap::~KeyCharacterMap() {
- for (size_t i = 0; i < mKeys.size(); i++) {
- Key* key = mKeys.editValueAt(i);
- delete key;
- }
+ clear();
}
bool KeyCharacterMap::operator==(const KeyCharacterMap& other) const {
if (mType != other.mType) {
return false;
}
+ if (mLoadFileName != other.mLoadFileName) {
+ return false;
+ }
+ if (mLayoutOverlayApplied != other.mLayoutOverlayApplied) {
+ return false;
+ }
if (mKeys.size() != other.mKeys.size() ||
mKeysByScanCode.size() != other.mKeysByScanCode.size() ||
mKeysByUsageCode.size() != other.mKeysByUsageCode.size()) {
@@ -146,6 +152,10 @@
return true;
}
+bool KeyCharacterMap::operator!=(const KeyCharacterMap& other) const {
+ return !(*this == other);
+}
+
base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::load(const std::string& filename,
Format format) {
Tokenizer* tokenizer;
@@ -153,12 +163,18 @@
if (status) {
return Errorf("Error {} opening key character map file {}.", status, filename.c_str());
}
- std::unique_ptr<Tokenizer> t(tokenizer);
- auto ret = load(t.get(), format);
- if (ret.ok()) {
- (*ret)->mLoadFileName = filename;
+ std::shared_ptr<KeyCharacterMap> map =
+ std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(filename));
+ if (!map.get()) {
+ ALOGE("Error allocating key character map.");
+ return Errorf("Error allocating key character map.");
}
- return ret;
+ std::unique_ptr<Tokenizer> t(tokenizer);
+ status = map->load(t.get(), format);
+ if (status == OK) {
+ return map;
+ }
+ return Errorf("Load KeyCharacterMap failed {}.", status);
}
base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::loadContents(
@@ -169,40 +185,67 @@
ALOGE("Error %d opening key character map.", status);
return Errorf("Error {} opening key character map.", status);
}
- std::unique_ptr<Tokenizer> t(tokenizer);
- auto ret = load(t.get(), format);
- if (ret.ok()) {
- (*ret)->mLoadFileName = filename;
- }
- return ret;
-}
-
-base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::load(Tokenizer* tokenizer,
- Format format) {
- status_t status = OK;
- std::shared_ptr<KeyCharacterMap> map = std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap());
+ std::shared_ptr<KeyCharacterMap> map =
+ std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(filename));
if (!map.get()) {
ALOGE("Error allocating key character map.");
return Errorf("Error allocating key character map.");
}
+ std::unique_ptr<Tokenizer> t(tokenizer);
+ status = map->load(t.get(), format);
+ if (status == OK) {
+ return map;
+ }
+ return Errorf("Load KeyCharacterMap failed {}.", status);
+}
+
+status_t KeyCharacterMap::load(Tokenizer* tokenizer, Format format) {
+ status_t status = OK;
#if DEBUG_PARSER_PERFORMANCE
nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
#endif
- Parser parser(map.get(), tokenizer, format);
+ Parser parser(this, tokenizer, format);
status = parser.parse();
#if DEBUG_PARSER_PERFORMANCE
nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
tokenizer->getFilename().string(), tokenizer->getLineNumber(), elapsedTime / 1000000.0);
#endif
- if (status == OK) {
- return map;
+ if (status != OK) {
+ ALOGE("Loading KeyCharacterMap failed with status %s", statusToString(status).c_str());
}
+ return status;
+}
- return Errorf("Load KeyCharacterMap failed {}.", status);
+void KeyCharacterMap::clear() {
+ mKeysByScanCode.clear();
+ mKeysByUsageCode.clear();
+ for (size_t i = 0; i < mKeys.size(); i++) {
+ Key* key = mKeys.editValueAt(i);
+ delete key;
+ }
+ mKeys.clear();
+ mLayoutOverlayApplied = false;
+ mType = KeyboardType::UNKNOWN;
+}
+
+status_t KeyCharacterMap::reloadBaseFromFile() {
+ clear();
+ Tokenizer* tokenizer;
+ status_t status = Tokenizer::open(String8(mLoadFileName.c_str()), &tokenizer);
+ if (status) {
+ ALOGE("Error %s opening key character map file %s.", statusToString(status).c_str(),
+ mLoadFileName.c_str());
+ return status;
+ }
+ std::unique_ptr<Tokenizer> t(tokenizer);
+ return load(t.get(), KeyCharacterMap::Format::BASE);
}
void KeyCharacterMap::combine(const KeyCharacterMap& overlay) {
+ if (mLayoutOverlayApplied) {
+ reloadBaseFromFile();
+ }
for (size_t i = 0; i < overlay.mKeys.size(); i++) {
int32_t keyCode = overlay.mKeys.keyAt(i);
Key* key = overlay.mKeys.valueAt(i);
@@ -224,7 +267,7 @@
mKeysByUsageCode.replaceValueFor(overlay.mKeysByUsageCode.keyAt(i),
overlay.mKeysByUsageCode.valueAt(i));
}
- mLoadFileName = overlay.mLoadFileName;
+ mLayoutOverlayApplied = true;
}
KeyCharacterMap::KeyboardType KeyCharacterMap::getKeyboardType() const {
@@ -636,8 +679,11 @@
ALOGE("%s: Null parcel", __func__);
return nullptr;
}
- std::shared_ptr<KeyCharacterMap> map = std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap());
+ std::string loadFileName = parcel->readCString();
+ std::shared_ptr<KeyCharacterMap> map =
+ std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(loadFileName));
map->mType = static_cast<KeyCharacterMap::KeyboardType>(parcel->readInt32());
+ map->mLayoutOverlayApplied = parcel->readBool();
size_t numKeys = parcel->readInt32();
if (parcel->errorCheck()) {
return nullptr;
@@ -687,6 +733,30 @@
return nullptr;
}
}
+ size_t numKeysByScanCode = parcel->readInt32();
+ if (parcel->errorCheck()) {
+ return nullptr;
+ }
+ for (size_t i = 0; i < numKeysByScanCode; i++) {
+ int32_t key = parcel->readInt32();
+ int32_t value = parcel->readInt32();
+ map->mKeysByScanCode.add(key, value);
+ if (parcel->errorCheck()) {
+ return nullptr;
+ }
+ }
+ size_t numKeysByUsageCode = parcel->readInt32();
+ if (parcel->errorCheck()) {
+ return nullptr;
+ }
+ for (size_t i = 0; i < numKeysByUsageCode; i++) {
+ int32_t key = parcel->readInt32();
+ int32_t value = parcel->readInt32();
+ map->mKeysByUsageCode.add(key, value);
+ if (parcel->errorCheck()) {
+ return nullptr;
+ }
+ }
return map;
}
@@ -695,7 +765,9 @@
ALOGE("%s: Null parcel", __func__);
return;
}
+ parcel->writeCString(mLoadFileName.c_str());
parcel->writeInt32(static_cast<int32_t>(mType));
+ parcel->writeBool(mLayoutOverlayApplied);
size_t numKeys = mKeys.size();
parcel->writeInt32(numKeys);
@@ -715,6 +787,18 @@
}
parcel->writeInt32(0);
}
+ size_t numKeysByScanCode = mKeysByScanCode.size();
+ parcel->writeInt32(numKeysByScanCode);
+ for (size_t i = 0; i < numKeysByScanCode; i++) {
+ parcel->writeInt32(mKeysByScanCode.keyAt(i));
+ parcel->writeInt32(mKeysByScanCode.valueAt(i));
+ }
+ size_t numKeysByUsageCode = mKeysByUsageCode.size();
+ parcel->writeInt32(numKeysByUsageCode);
+ for (size_t i = 0; i < numKeysByUsageCode; i++) {
+ parcel->writeInt32(mKeysByUsageCode.keyAt(i));
+ parcel->writeInt32(mKeysByUsageCode.valueAt(i));
+ }
}
#endif // __linux__
diff --git a/libs/input/android/os/IInputConstants.aidl b/libs/input/android/os/IInputConstants.aidl
index 63bf23d..829bbdd 100644
--- a/libs/input/android/os/IInputConstants.aidl
+++ b/libs/input/android/os/IInputConstants.aidl
@@ -25,13 +25,6 @@
// android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS.
const int UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS = 5000; // 5 seconds
- // Compatibility changes.
- /**
- * TODO(b/157929241): remove this before closing the bug. This is needed temporarily
- * to identify apps that are using this flag.
- */
- const long BLOCK_FLAG_SLIPPERY = 157929241;
-
// Indicate invalid battery capacity
const int INVALID_BATTERY_CAPACITY = -1;
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 18ab1cb..6ffe851 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -37,6 +37,7 @@
"libui",
"libutils",
],
+ data: ["data/*.kcm"],
test_suites: ["device-tests"],
}
@@ -59,5 +60,5 @@
"libbinder",
"libui",
"libbase",
- ]
+ ],
}
diff --git a/libs/input/tests/InputDevice_test.cpp b/libs/input/tests/InputDevice_test.cpp
index f8f2f4e..61e88df 100644
--- a/libs/input/tests/InputDevice_test.cpp
+++ b/libs/input/tests/InputDevice_test.cpp
@@ -20,6 +20,7 @@
#include <input/InputDevice.h>
#include <input/KeyLayoutMap.h>
#include <input/Keyboard.h>
+#include "android-base/file.h"
namespace android {
@@ -82,4 +83,53 @@
ASSERT_EQ(*map, *mKeyMap.keyCharacterMap);
}
+TEST_F(InputDeviceKeyMapTest, keyCharacterMapWithOverlayParcelingTest) {
+ Parcel parcel;
+ std::string overlayPath = base::GetExecutableDirectory() + "/data/german.kcm";
+ base::Result<std::shared_ptr<KeyCharacterMap>> overlay =
+ KeyCharacterMap::load(overlayPath, KeyCharacterMap::Format::OVERLAY);
+ ASSERT_TRUE(overlay.ok()) << "Cannot load KeyCharacterMap at " << overlayPath;
+ mKeyMap.keyCharacterMap->combine(*overlay->get());
+ mKeyMap.keyCharacterMap->writeToParcel(&parcel);
+ parcel.setDataPosition(0);
+ std::shared_ptr<KeyCharacterMap> map = KeyCharacterMap::readFromParcel(&parcel);
+ ASSERT_EQ(*map, *mKeyMap.keyCharacterMap);
+}
+
+TEST_F(InputDeviceKeyMapTest, keyCharacteMapApplyMultipleOverlaysTest) {
+ std::string frenchOverlayPath = base::GetExecutableDirectory() + "/data/french.kcm";
+ std::string englishOverlayPath = base::GetExecutableDirectory() + "/data/english_us.kcm";
+ std::string germanOverlayPath = base::GetExecutableDirectory() + "/data/german.kcm";
+ base::Result<std::shared_ptr<KeyCharacterMap>> frenchOverlay =
+ KeyCharacterMap::load(frenchOverlayPath, KeyCharacterMap::Format::OVERLAY);
+ ASSERT_TRUE(frenchOverlay.ok()) << "Cannot load KeyCharacterMap at " << frenchOverlayPath;
+ base::Result<std::shared_ptr<KeyCharacterMap>> englishOverlay =
+ KeyCharacterMap::load(englishOverlayPath, KeyCharacterMap::Format::OVERLAY);
+ ASSERT_TRUE(englishOverlay.ok()) << "Cannot load KeyCharacterMap at " << englishOverlayPath;
+ base::Result<std::shared_ptr<KeyCharacterMap>> germanOverlay =
+ KeyCharacterMap::load(germanOverlayPath, KeyCharacterMap::Format::OVERLAY);
+ ASSERT_TRUE(germanOverlay.ok()) << "Cannot load KeyCharacterMap at " << germanOverlayPath;
+
+ // Apply the French overlay
+ mKeyMap.keyCharacterMap->combine(*frenchOverlay->get());
+ // Copy the result for later
+ std::shared_ptr<KeyCharacterMap> frenchOverlaidKeyCharacterMap =
+ std::make_shared<KeyCharacterMap>(*mKeyMap.keyCharacterMap);
+
+ // Apply the English overlay
+ mKeyMap.keyCharacterMap->combine(*englishOverlay->get());
+ // Verify that the result is different from the French overlay result
+ ASSERT_NE(*mKeyMap.keyCharacterMap, *frenchOverlaidKeyCharacterMap);
+
+ // Apply the German overlay
+ mKeyMap.keyCharacterMap->combine(*germanOverlay->get());
+ // Verify that the result is different from the French overlay result
+ ASSERT_NE(*mKeyMap.keyCharacterMap, *frenchOverlaidKeyCharacterMap);
+
+ // Apply the French overlay
+ mKeyMap.keyCharacterMap->combine(*frenchOverlay->get());
+ // Verify that the result is the same like after applying it initially
+ ASSERT_EQ(*mKeyMap.keyCharacterMap, *frenchOverlaidKeyCharacterMap);
+}
+
} // namespace android
diff --git a/libs/input/tests/data/english_us.kcm b/libs/input/tests/data/english_us.kcm
new file mode 100644
index 0000000..d0ef027
--- /dev/null
+++ b/libs/input/tests/data/english_us.kcm
@@ -0,0 +1,311 @@
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# English (US) keyboard layout.
+# Unlike the default (generic) keyboard layout, English (US) does not contain any
+# special ALT characters.
+#
+
+type OVERLAY
+
+### ROW 1
+
+key GRAVE {
+ label: '`'
+ base: '`'
+ shift: '~'
+}
+
+key 1 {
+ label: '1'
+ base: '1'
+ shift: '!'
+}
+
+key 2 {
+ label: '2'
+ base: '2'
+ shift: '@'
+}
+
+key 3 {
+ label: '3'
+ base: '3'
+ shift: '#'
+}
+
+key 4 {
+ label: '4'
+ base: '4'
+ shift: '$'
+}
+
+key 5 {
+ label: '5'
+ base: '5'
+ shift: '%'
+}
+
+key 6 {
+ label: '6'
+ base: '6'
+ shift: '^'
+}
+
+key 7 {
+ label: '7'
+ base: '7'
+ shift: '&'
+}
+
+key 8 {
+ label: '8'
+ base: '8'
+ shift: '*'
+}
+
+key 9 {
+ label: '9'
+ base: '9'
+ shift: '('
+}
+
+key 0 {
+ label: '0'
+ base: '0'
+ shift: ')'
+}
+
+key MINUS {
+ label: '-'
+ base: '-'
+ shift: '_'
+}
+
+key EQUALS {
+ label: '='
+ base: '='
+ shift: '+'
+}
+
+### ROW 2
+
+key Q {
+ label: 'Q'
+ base: 'q'
+ shift, capslock: 'Q'
+}
+
+key W {
+ label: 'W'
+ base: 'w'
+ shift, capslock: 'W'
+}
+
+key E {
+ label: 'E'
+ base: 'e'
+ shift, capslock: 'E'
+}
+
+key R {
+ label: 'R'
+ base: 'r'
+ shift, capslock: 'R'
+}
+
+key T {
+ label: 'T'
+ base: 't'
+ shift, capslock: 'T'
+}
+
+key Y {
+ label: 'Y'
+ base: 'y'
+ shift, capslock: 'Y'
+}
+
+key U {
+ label: 'U'
+ base: 'u'
+ shift, capslock: 'U'
+}
+
+key I {
+ label: 'I'
+ base: 'i'
+ shift, capslock: 'I'
+}
+
+key O {
+ label: 'O'
+ base: 'o'
+ shift, capslock: 'O'
+}
+
+key P {
+ label: 'P'
+ base: 'p'
+ shift, capslock: 'P'
+}
+
+key LEFT_BRACKET {
+ label: '['
+ base: '['
+ shift: '{'
+}
+
+key RIGHT_BRACKET {
+ label: ']'
+ base: ']'
+ shift: '}'
+}
+
+key BACKSLASH {
+ label: '\\'
+ base: '\\'
+ shift: '|'
+}
+
+### ROW 3
+
+key A {
+ label: 'A'
+ base: 'a'
+ shift, capslock: 'A'
+}
+
+key S {
+ label: 'S'
+ base: 's'
+ shift, capslock: 'S'
+}
+
+key D {
+ label: 'D'
+ base: 'd'
+ shift, capslock: 'D'
+}
+
+key F {
+ label: 'F'
+ base: 'f'
+ shift, capslock: 'F'
+}
+
+key G {
+ label: 'G'
+ base: 'g'
+ shift, capslock: 'G'
+}
+
+key H {
+ label: 'H'
+ base: 'h'
+ shift, capslock: 'H'
+}
+
+key J {
+ label: 'J'
+ base: 'j'
+ shift, capslock: 'J'
+}
+
+key K {
+ label: 'K'
+ base: 'k'
+ shift, capslock: 'K'
+}
+
+key L {
+ label: 'L'
+ base: 'l'
+ shift, capslock: 'L'
+}
+
+key SEMICOLON {
+ label: ';'
+ base: ';'
+ shift: ':'
+}
+
+key APOSTROPHE {
+ label: '\''
+ base: '\''
+ shift: '"'
+}
+
+### ROW 4
+
+key Z {
+ label: 'Z'
+ base: 'z'
+ shift, capslock: 'Z'
+}
+
+key X {
+ label: 'X'
+ base: 'x'
+ shift, capslock: 'X'
+}
+
+key C {
+ label: 'C'
+ base: 'c'
+ shift, capslock: 'C'
+}
+
+key V {
+ label: 'V'
+ base: 'v'
+ shift, capslock: 'V'
+}
+
+key B {
+ label: 'B'
+ base: 'b'
+ shift, capslock: 'B'
+}
+
+key N {
+ label: 'N'
+ base: 'n'
+ shift, capslock: 'N'
+}
+
+key M {
+ label: 'M'
+ base: 'm'
+ shift, capslock: 'M'
+}
+
+key COMMA {
+ label: ','
+ base: ','
+ shift: '<'
+}
+
+key PERIOD {
+ label: '.'
+ base: '.'
+ shift: '>'
+}
+
+key SLASH {
+ label: '/'
+ base: '/'
+ shift: '?'
+}
\ No newline at end of file
diff --git a/libs/input/tests/data/french.kcm b/libs/input/tests/data/french.kcm
new file mode 100644
index 0000000..db69ea0
--- /dev/null
+++ b/libs/input/tests/data/french.kcm
@@ -0,0 +1,336 @@
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# French keyboard layout, AZERTY style.
+#
+
+type OVERLAY
+
+map key 16 A
+map key 17 Z
+map key 30 Q
+map key 39 M
+map key 44 W
+map key 50 COMMA
+map key 51 SEMICOLON
+map key 86 PLUS
+
+### ROW 1
+
+key GRAVE {
+ label: '\u00b2'
+ base: '\u00b2'
+}
+
+key 1 {
+ label: '1'
+ base: '&'
+ shift: '1'
+}
+
+key 2 {
+ label: '2'
+ base: '\u00e9'
+ shift: '2'
+ ralt: '~'
+}
+
+key 3 {
+ label: '3'
+ base: '"'
+ shift: '3'
+ ralt: '#'
+}
+
+key 4 {
+ label: '4'
+ base: '\''
+ shift: '4'
+ ralt: '{'
+}
+
+key 5 {
+ label: '5'
+ base: '('
+ shift: '5'
+ ralt: '['
+}
+
+key 6 {
+ label: '6'
+ base: '-'
+ shift: '6'
+ ralt: '|'
+}
+
+key 7 {
+ label: '7'
+ base: '\u00e8'
+ shift: '7'
+ ralt: '`'
+}
+
+key 8 {
+ label: '8'
+ base: '_'
+ shift: '8'
+ ralt: '\\'
+}
+
+key 9 {
+ label: '9'
+ base: '\u00e7'
+ shift: '9'
+ ralt: '^'
+}
+
+key 0 {
+ label: '0'
+ base: '\u00e0'
+ shift: '0'
+ ralt: '@'
+}
+
+key MINUS {
+ label: ')'
+ base: ')'
+ shift: '\u00b0'
+ ralt: ']'
+}
+
+key EQUALS {
+ label: '='
+ base: '='
+ shift: '+'
+ ralt: '}'
+}
+
+### ROW 2
+
+key A {
+ label: 'A'
+ base: 'a'
+ shift, capslock: 'A'
+}
+
+key Z {
+ label: 'Z'
+ base: 'z'
+ shift, capslock: 'Z'
+}
+
+key E {
+ label: 'E'
+ base: 'e'
+ shift, capslock: 'E'
+ ralt: '\u20ac'
+}
+
+key R {
+ label: 'R'
+ base: 'r'
+ shift, capslock: 'R'
+}
+
+key T {
+ label: 'T'
+ base: 't'
+ shift, capslock: 'T'
+}
+
+key Y {
+ label: 'Y'
+ base: 'y'
+ shift, capslock: 'Y'
+}
+
+key U {
+ label: 'U'
+ base: 'u'
+ shift, capslock: 'U'
+}
+
+key I {
+ label: 'I'
+ base: 'i'
+ shift, capslock: 'I'
+}
+
+key O {
+ label: 'O'
+ base: 'o'
+ shift, capslock: 'O'
+}
+
+key P {
+ label: 'P'
+ base: 'p'
+ shift, capslock: 'P'
+}
+
+key LEFT_BRACKET {
+ label: '\u02c6'
+ base: '\u0302'
+ shift: '\u0308'
+}
+
+key RIGHT_BRACKET {
+ label: '$'
+ base: '$'
+ shift: '\u00a3'
+ ralt: '\u00a4'
+}
+
+### ROW 3
+
+key Q {
+ label: 'Q'
+ base: 'q'
+ shift, capslock: 'Q'
+}
+
+key S {
+ label: 'S'
+ base: 's'
+ shift, capslock: 'S'
+}
+
+key D {
+ label: 'D'
+ base: 'd'
+ shift, capslock: 'D'
+}
+
+key F {
+ label: 'F'
+ base: 'f'
+ shift, capslock: 'F'
+}
+
+key G {
+ label: 'G'
+ base: 'g'
+ shift, capslock: 'G'
+}
+
+key H {
+ label: 'H'
+ base: 'h'
+ shift, capslock: 'H'
+}
+
+key J {
+ label: 'J'
+ base: 'j'
+ shift, capslock: 'J'
+}
+
+key K {
+ label: 'K'
+ base: 'k'
+ shift, capslock: 'K'
+}
+
+key L {
+ label: 'L'
+ base: 'l'
+ shift, capslock: 'L'
+}
+
+key M {
+ label: 'M'
+ base: 'm'
+ shift, capslock: 'M'
+}
+
+key APOSTROPHE {
+ label: '\u00f9'
+ base: '\u00f9'
+ shift: '%'
+}
+
+key BACKSLASH {
+ label: '*'
+ base: '*'
+ shift: '\u00b5'
+}
+
+### ROW 4
+
+key PLUS {
+ label: '<'
+ base: '<'
+ shift: '>'
+}
+
+key W {
+ label: 'W'
+ base: 'w'
+ shift, capslock: 'W'
+}
+
+key X {
+ label: 'X'
+ base: 'x'
+ shift, capslock: 'X'
+}
+
+key C {
+ label: 'C'
+ base: 'c'
+ shift, capslock: 'C'
+}
+
+key V {
+ label: 'V'
+ base: 'v'
+ shift, capslock: 'V'
+}
+
+key B {
+ label: 'B'
+ base: 'b'
+ shift, capslock: 'B'
+}
+
+key N {
+ label: 'N'
+ base: 'n'
+ shift, capslock: 'N'
+}
+
+key COMMA {
+ label: ','
+ base: ','
+ shift: '?'
+}
+
+key SEMICOLON {
+ label: ';'
+ base: ';'
+ shift: '.'
+}
+
+key PERIOD {
+ label: ':'
+ base: ':'
+ shift: '/'
+}
+
+key SLASH {
+ label: '!'
+ base: '!'
+ shift: '\u00a7'
+}
\ No newline at end of file
diff --git a/libs/input/tests/data/german.kcm b/libs/input/tests/data/german.kcm
new file mode 100644
index 0000000..2fbc5e5
--- /dev/null
+++ b/libs/input/tests/data/german.kcm
@@ -0,0 +1,336 @@
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# German keyboard layout, QWERTZ style.
+#
+
+type OVERLAY
+
+map key 12 SLASH # � ? \
+map key 21 Z
+map key 44 Y
+map key 53 MINUS # - _
+map key 86 PLUS # < > |
+
+map key usage 32 A # for testing purposes only
+map key usage 67 B # for testing purposes only
+
+### ROW 1
+
+key GRAVE {
+ label: '^'
+ base: '^'
+ shift: '\u00b0'
+}
+
+key 1 {
+ label: '1'
+ base: '1'
+ shift: '!'
+}
+
+key 2 {
+ label: '2'
+ base: '2'
+ shift: '"'
+ ralt: '\u00b2'
+}
+
+key 3 {
+ label: '3'
+ base: '3'
+ shift: '\u00a7'
+ ralt: '\u00b3'
+}
+
+key 4 {
+ label: '4'
+ base: '4'
+ shift: '$'
+}
+
+key 5 {
+ label: '5'
+ base: '5'
+ shift: '%'
+}
+
+key 6 {
+ label: '6'
+ base: '6'
+ shift: '&'
+}
+
+key 7 {
+ label: '7'
+ base: '7'
+ shift: '/'
+ ralt: '{'
+}
+
+key 8 {
+ label: '8'
+ base: '8'
+ shift: '('
+ ralt: '['
+}
+
+key 9 {
+ label: '9'
+ base: '9'
+ shift: ')'
+ ralt: ']'
+}
+
+key 0 {
+ label: '0'
+ base: '0'
+ shift: '='
+ ralt: '}'
+}
+
+key SLASH {
+ label: '\u00df'
+ base: '\u00df'
+ shift: '?'
+ ralt: '\\'
+}
+
+key EQUALS {
+ label: '\u00b4'
+ base: '\u0301'
+ shift: '\u0300'
+}
+
+### ROW 2
+
+key Q {
+ label: 'Q'
+ base: 'q'
+ shift, capslock: 'Q'
+ ralt: '@'
+}
+
+key W {
+ label: 'W'
+ base: 'w'
+ shift, capslock: 'W'
+}
+
+key E {
+ label: 'E'
+ base: 'e'
+ shift, capslock: 'E'
+ ralt: '\u20ac'
+}
+
+key R {
+ label: 'R'
+ base: 'r'
+ shift, capslock: 'R'
+}
+
+key T {
+ label: 'T'
+ base: 't'
+ shift, capslock: 'T'
+}
+
+key Z {
+ label: 'Z'
+ base: 'z'
+ shift, capslock: 'Z'
+}
+
+key U {
+ label: 'U'
+ base: 'u'
+ shift, capslock: 'U'
+}
+
+key I {
+ label: 'I'
+ base: 'i'
+ shift, capslock: 'I'
+}
+
+key O {
+ label: 'O'
+ base: 'o'
+ shift, capslock: 'O'
+}
+
+key P {
+ label: 'P'
+ base: 'p'
+ shift, capslock: 'P'
+}
+
+key LEFT_BRACKET {
+ label: '\u00dc'
+ base: '\u00fc'
+ shift, capslock: '\u00dc'
+}
+
+key RIGHT_BRACKET {
+ label: '+'
+ base: '+'
+ shift: '*'
+ ralt: '~'
+}
+
+### ROW 3
+
+key A {
+ label: 'A'
+ base: 'a'
+ shift, capslock: 'A'
+}
+
+key S {
+ label: 'S'
+ base: 's'
+ shift, capslock: 'S'
+}
+
+key D {
+ label: 'D'
+ base: 'd'
+ shift, capslock: 'D'
+}
+
+key F {
+ label: 'F'
+ base: 'f'
+ shift, capslock: 'F'
+}
+
+key G {
+ label: 'G'
+ base: 'g'
+ shift, capslock: 'G'
+}
+
+key H {
+ label: 'H'
+ base: 'h'
+ shift, capslock: 'H'
+}
+
+key J {
+ label: 'J'
+ base: 'j'
+ shift, capslock: 'J'
+}
+
+key K {
+ label: 'K'
+ base: 'k'
+ shift, capslock: 'K'
+}
+
+key L {
+ label: 'L'
+ base: 'l'
+ shift, capslock: 'L'
+}
+
+key SEMICOLON {
+ label: '\u00d6'
+ base: '\u00f6'
+ shift, capslock: '\u00d6'
+}
+
+key APOSTROPHE {
+ label: '\u00c4'
+ base: '\u00e4'
+ shift, capslock: '\u00c4'
+}
+
+key BACKSLASH {
+ label: '#'
+ base: '#'
+ shift: '\''
+}
+
+### ROW 4
+
+key PLUS {
+ label: '<'
+ base: '<'
+ shift: '>'
+ ralt: '|'
+}
+
+key Y {
+ label: 'Y'
+ base: 'y'
+ shift, capslock: 'Y'
+}
+
+key X {
+ label: 'X'
+ base: 'x'
+ shift, capslock: 'X'
+}
+
+key C {
+ label: 'C'
+ base: 'c'
+ shift, capslock: 'C'
+}
+
+key V {
+ label: 'V'
+ base: 'v'
+ shift, capslock: 'V'
+}
+
+key B {
+ label: 'B'
+ base: 'b'
+ shift, capslock: 'B'
+}
+
+key N {
+ label: 'N'
+ base: 'n'
+ shift, capslock: 'N'
+}
+
+key M {
+ label: 'M'
+ base: 'm'
+ shift, capslock: 'M'
+ ralt: '\u00b5'
+}
+
+key COMMA {
+ label: ','
+ base: ','
+ shift: ';'
+}
+
+key PERIOD {
+ label: '.'
+ base: '.'
+ shift: ':'
+}
+
+key MINUS {
+ label: '-'
+ base: '-'
+ shift: '_'
+}
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index fc9680b..84daea0 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -556,13 +556,13 @@
const AChoreographerFrameCallbackData* data, size_t index) {
return AChoreographerFrameCallbackData_getFrameTimelineVsyncId(data, index);
}
-int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentTime(
+int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentTimeNanos(
const AChoreographerFrameCallbackData* data, size_t index) {
- return AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime(data, index);
+ return AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTimeNanos(data, index);
}
-int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineDeadline(
+int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineDeadlineNanos(
const AChoreographerFrameCallbackData* data, size_t index) {
- return AChoreographerFrameCallbackData_getFrameTimelineDeadline(data, index);
+ return AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos(data, index);
}
int64_t AChoreographer_getFrameInterval(const AChoreographer* choreographer) {
@@ -653,7 +653,7 @@
LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds");
return frameCallbackData->frameTimelines[index].id;
}
-int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime(
+int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTimeNanos(
const AChoreographerFrameCallbackData* data, size_t index) {
const ChoreographerFrameCallbackDataImpl* frameCallbackData =
AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
@@ -662,7 +662,7 @@
LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds");
return frameCallbackData->frameTimelines[index].expectedPresentTime;
}
-int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadline(
+int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos(
const AChoreographerFrameCallbackData* data, size_t index) {
const ChoreographerFrameCallbackDataImpl* frameCallbackData =
AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
diff --git a/libs/nativedisplay/include-private/private/android/choreographer.h b/libs/nativedisplay/include-private/private/android/choreographer.h
index 4aa7e69..0a1fcbe 100644
--- a/libs/nativedisplay/include-private/private/android/choreographer.h
+++ b/libs/nativedisplay/include-private/private/android/choreographer.h
@@ -67,9 +67,9 @@
const AChoreographerFrameCallbackData* data);
int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineVsyncId(
const AChoreographerFrameCallbackData* data, size_t index);
-int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentTime(
+int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentTimeNanos(
const AChoreographerFrameCallbackData* data, size_t index);
-int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineDeadline(
+int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineDeadlineNanos(
const AChoreographerFrameCallbackData* data, size_t index);
} // namespace android
diff --git a/libs/nativedisplay/libnativedisplay.map.txt b/libs/nativedisplay/libnativedisplay.map.txt
index 4dbfde8..b1b6498 100644
--- a/libs/nativedisplay/libnativedisplay.map.txt
+++ b/libs/nativedisplay/libnativedisplay.map.txt
@@ -12,8 +12,8 @@
AChoreographerFrameCallbackData_getFrameTimelinesLength; # apex # introduced=33
AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex; # apex # introduced=33
AChoreographerFrameCallbackData_getFrameTimelineVsyncId; # apex # introduced=33
- AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime; # apex # introduced=33
- AChoreographerFrameCallbackData_getFrameTimelineDeadline; # apex # introduced=33
+ AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTimeNanos; # apex # introduced=33
+ AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos; # apex # introduced=33
AChoreographer_create; # apex # introduced=30
AChoreographer_destroy; # apex # introduced=30
AChoreographer_getFd; # apex # introduced=30
@@ -40,8 +40,8 @@
android::AChoreographerFrameCallbackData_routeGetFrameTimelinesLength*;
android::AChoreographerFrameCallbackData_routeGetPreferredFrameTimelineIndex*;
android::AChoreographerFrameCallbackData_routeGetFrameTimelineVsyncId*;
- android::AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentTime*;
- android::AChoreographerFrameCallbackData_routeGetFrameTimelineDeadline*;
+ android::AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentTimeNanos*;
+ android::AChoreographerFrameCallbackData_routeGetFrameTimelineDeadlineNanos*;
android::AChoreographer_signalRefreshRateCallbacks*;
android::AChoreographer_getFrameInterval*;
android::ADisplay_acquirePhysicalDisplays*;
diff --git a/libs/renderengine/ExternalTexture.cpp b/libs/renderengine/ExternalTexture.cpp
index eabff58..84771c0 100644
--- a/libs/renderengine/ExternalTexture.cpp
+++ b/libs/renderengine/ExternalTexture.cpp
@@ -14,30 +14,32 @@
* limitations under the License.
*/
-#include <renderengine/ExternalTexture.h>
#include <renderengine/RenderEngine.h>
+#include <renderengine/impl/ExternalTexture.h>
#include <ui/GraphicBuffer.h>
#include "log/log_main.h"
-namespace android::renderengine {
+namespace android::renderengine::impl {
-ExternalTexture::ExternalTexture(const sp<GraphicBuffer>& buffer, RenderEngine& renderEngine,
- uint32_t usage)
+ExternalTexture::ExternalTexture(const sp<GraphicBuffer>& buffer,
+ renderengine::RenderEngine& renderEngine, uint32_t usage)
: mBuffer(buffer), mRenderEngine(renderEngine) {
LOG_ALWAYS_FATAL_IF(buffer == nullptr,
"Attempted to bind a null buffer to an external texture!");
// GLESRenderEngine has a separate texture cache for output buffers,
- if (usage == Usage::WRITEABLE &&
- (mRenderEngine.getRenderEngineType() == RenderEngine::RenderEngineType::GLES ||
- mRenderEngine.getRenderEngineType() == RenderEngine::RenderEngineType::THREADED)) {
+ if (usage == WRITEABLE &&
+ (mRenderEngine.getRenderEngineType() ==
+ renderengine::RenderEngine::RenderEngineType::GLES ||
+ mRenderEngine.getRenderEngineType() ==
+ renderengine::RenderEngine::RenderEngineType::THREADED)) {
return;
}
- mRenderEngine.mapExternalTextureBuffer(mBuffer, usage & Usage::WRITEABLE);
+ mRenderEngine.mapExternalTextureBuffer(mBuffer, usage & WRITEABLE);
}
ExternalTexture::~ExternalTexture() {
mRenderEngine.unmapExternalTextureBuffer(mBuffer);
}
-} // namespace android::renderengine
+} // namespace android::renderengine::impl
diff --git a/libs/renderengine/benchmark/RenderEngineBench.cpp b/libs/renderengine/benchmark/RenderEngineBench.cpp
index 6c8f8e8..ead97cf 100644
--- a/libs/renderengine/benchmark/RenderEngineBench.cpp
+++ b/libs/renderengine/benchmark/RenderEngineBench.cpp
@@ -22,6 +22,7 @@
#include <renderengine/ExternalTexture.h>
#include <renderengine/LayerSettings.h>
#include <renderengine/RenderEngine.h>
+#include <renderengine/impl/ExternalTexture.h>
#include <mutex>
@@ -115,15 +116,15 @@
uint32_t height,
uint64_t extraUsageFlags = 0,
std::string name = "output") {
- return std::make_shared<ExternalTexture>(new GraphicBuffer(width, height,
- HAL_PIXEL_FORMAT_RGBA_8888, 1,
- GRALLOC_USAGE_HW_RENDER |
- GRALLOC_USAGE_HW_TEXTURE |
- extraUsageFlags,
- std::move(name)),
- re,
- ExternalTexture::Usage::READABLE |
- ExternalTexture::Usage::WRITEABLE);
+ return std::make_shared<
+ impl::ExternalTexture>(new GraphicBuffer(width, height, HAL_PIXEL_FORMAT_RGBA_8888, 1,
+ GRALLOC_USAGE_HW_RENDER |
+ GRALLOC_USAGE_HW_TEXTURE |
+ extraUsageFlags,
+ std::move(name)),
+ re,
+ impl::ExternalTexture::Usage::READABLE |
+ impl::ExternalTexture::Usage::WRITEABLE);
}
static std::shared_ptr<ExternalTexture> copyBuffer(RenderEngine& re,
diff --git a/libs/renderengine/include/renderengine/ExternalTexture.h b/libs/renderengine/include/renderengine/ExternalTexture.h
index 07f0833..621a209 100644
--- a/libs/renderengine/include/renderengine/ExternalTexture.h
+++ b/libs/renderengine/include/renderengine/ExternalTexture.h
@@ -33,28 +33,22 @@
*/
class ExternalTexture {
public:
- // Usage specifies the rendering intent for the buffer.
- enum Usage : uint32_t {
- // When a buffer is not READABLE but is WRITEABLE, then GLESRenderEngine will use that as a
- // hint to load the buffer into a separate cache
- READABLE = 1 << 0,
+ ExternalTexture() = default;
+ virtual ~ExternalTexture() = default;
- // The buffer needs to be mapped as a 2D texture if set, otherwise must be mapped as an
- // external texture
- WRITEABLE = 1 << 1,
- };
- // Creates an ExternalTexture for the provided buffer and RenderEngine instance, with the given
- // usage hint of type Usage.
- ExternalTexture(const sp<GraphicBuffer>& buffer, RenderEngine& renderEngine, uint32_t usage);
-
- ~ExternalTexture();
+ virtual bool hasSameBuffer(const ExternalTexture& other) const = 0;
+ virtual uint32_t getWidth() const = 0;
+ virtual uint32_t getHeight() const = 0;
+ virtual uint64_t getId() const = 0;
+ virtual PixelFormat getPixelFormat() const = 0;
+ virtual uint64_t getUsage() const = 0;
// Retrieves the buffer that is bound to this texture.
- const sp<GraphicBuffer>& getBuffer() const { return mBuffer; }
+ virtual const sp<GraphicBuffer>& getBuffer() const = 0;
-private:
- sp<GraphicBuffer> mBuffer;
- RenderEngine& mRenderEngine;
+ Rect getBounds() const {
+ return {0, 0, static_cast<int32_t>(getWidth()), static_cast<int32_t>(getHeight())};
+ }
DISALLOW_COPY_AND_ASSIGN(ExternalTexture);
};
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index b9cc648..faa84fc 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -76,6 +76,7 @@
namespace impl {
class RenderEngine;
+class ExternalTexture;
}
enum class Protection {
@@ -189,6 +190,10 @@
static void validateInputBufferUsage(const sp<GraphicBuffer>&);
static void validateOutputBufferUsage(const sp<GraphicBuffer>&);
+ // Allows flinger to get the render engine thread id for power management with ADPF
+ // Returns the tid of the renderengine thread if it's threaded, and std::nullopt otherwise
+ virtual std::optional<pid_t> getRenderEngineTid() const { return std::nullopt; }
+
protected:
RenderEngine() : RenderEngine(RenderEngineType::GLES) {}
@@ -224,7 +229,7 @@
// avoid any thread synchronization that may be required by directly calling postRenderCleanup.
virtual bool canSkipPostRenderCleanup() const = 0;
- friend class ExternalTexture;
+ friend class impl::ExternalTexture;
friend class threaded::RenderEngineThreaded;
friend class RenderEngineTest_cleanupPostRender_cleansUpOnce_Test;
const RenderEngineType mRenderEngineType;
diff --git a/libs/renderengine/include/renderengine/impl/ExternalTexture.h b/libs/renderengine/include/renderengine/impl/ExternalTexture.h
new file mode 100644
index 0000000..c0e24f0
--- /dev/null
+++ b/libs/renderengine/include/renderengine/impl/ExternalTexture.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/macros.h>
+#include <renderengine/ExternalTexture.h>
+#include <ui/GraphicBuffer.h>
+
+namespace android::renderengine::impl {
+
+class RenderEngine;
+
+class ExternalTexture : public android::renderengine::ExternalTexture {
+public:
+ // Usage specifies the rendering intent for the buffer.
+ enum Usage : uint32_t {
+ // When a buffer is not READABLE but is WRITEABLE, then GLESRenderEngine will use that as a
+ // hint to load the buffer into a separate cache
+ READABLE = 1 << 0,
+
+ // The buffer needs to be mapped as a 2D texture if set, otherwise must be mapped as an
+ // external texture
+ WRITEABLE = 1 << 1,
+ };
+
+ // Creates an ExternalTexture for the provided buffer and RenderEngine instance, with the given
+ // usage hint of type Usage.
+ ExternalTexture(const sp<GraphicBuffer>& buffer,
+ android::renderengine::RenderEngine& renderEngine, uint32_t usage);
+ ~ExternalTexture();
+ const sp<GraphicBuffer>& getBuffer() const override { return mBuffer; };
+ uint32_t getWidth() const override { return getBuffer()->getWidth(); }
+ uint32_t getHeight() const override { return getBuffer()->getHeight(); }
+ uint64_t getId() const override { return getBuffer()->getId(); }
+ PixelFormat getPixelFormat() const override { return getBuffer()->getPixelFormat(); }
+ uint64_t getUsage() const override { return getBuffer()->getUsage(); }
+ bool hasSameBuffer(const renderengine::ExternalTexture& other) const override {
+ return getBuffer() == other.getBuffer();
+ }
+
+private:
+ sp<GraphicBuffer> mBuffer;
+ android::renderengine::RenderEngine& mRenderEngine;
+};
+
+} // namespace android::renderengine::impl
diff --git a/libs/renderengine/include/renderengine/mock/FakeExternalTexture.h b/libs/renderengine/include/renderengine/mock/FakeExternalTexture.h
new file mode 100644
index 0000000..974e0fd
--- /dev/null
+++ b/libs/renderengine/include/renderengine/mock/FakeExternalTexture.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <renderengine/ExternalTexture.h>
+
+namespace android {
+namespace renderengine {
+namespace mock {
+
+class FakeExternalTexture : public renderengine::ExternalTexture {
+ const sp<GraphicBuffer> mNullBuffer = nullptr;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ uint64_t mId;
+ PixelFormat mPixelFormat;
+ uint64_t mUsage;
+
+public:
+ FakeExternalTexture(uint32_t width, uint32_t height, uint64_t id, PixelFormat pixelFormat,
+ uint64_t usage)
+ : mWidth(width), mHeight(height), mId(id), mPixelFormat(pixelFormat), mUsage(usage) {}
+ const sp<GraphicBuffer>& getBuffer() const { return mNullBuffer; }
+ bool hasSameBuffer(const renderengine::ExternalTexture& other) const override {
+ return getId() == other.getId();
+ }
+ uint32_t getWidth() const override { return mWidth; }
+ uint32_t getHeight() const override { return mHeight; }
+ uint64_t getId() const override { return mId; }
+ PixelFormat getPixelFormat() const override { return mPixelFormat; }
+ uint64_t getUsage() const override { return mUsage; }
+ ~FakeExternalTexture() = default;
+};
+
+} // namespace mock
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp
index b18a872..a3a1969 100644
--- a/libs/renderengine/skia/Cache.cpp
+++ b/libs/renderengine/skia/Cache.cpp
@@ -19,6 +19,7 @@
#include "android-base/unique_fd.h"
#include "renderengine/DisplaySettings.h"
#include "renderengine/LayerSettings.h"
+#include "renderengine/impl/ExternalTexture.h"
#include "ui/GraphicBuffer.h"
#include "ui/GraphicTypes.h"
#include "ui/PixelFormat.h"
@@ -365,8 +366,8 @@
1, usage, "primeShaderCache_dst");
const auto dstTexture =
- std::make_shared<ExternalTexture>(dstBuffer, *renderengine,
- ExternalTexture::Usage::WRITEABLE);
+ std::make_shared<impl::ExternalTexture>(dstBuffer, *renderengine,
+ impl::ExternalTexture::Usage::WRITEABLE);
// This buffer will be the source for the call to drawImageLayers. Draw
// something to it as a placeholder for what an app draws. We should draw
// something, but the details are not important. Make use of the shadow layer drawing step
@@ -375,10 +376,10 @@
new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888,
1, usage, "drawImageLayer_src");
- const auto srcTexture =
- std::make_shared<ExternalTexture>(srcBuffer, *renderengine,
- ExternalTexture::Usage::READABLE |
- ExternalTexture::Usage::WRITEABLE);
+ const auto srcTexture = std::make_shared<
+ impl::ExternalTexture>(srcBuffer, *renderengine,
+ impl::ExternalTexture::Usage::READABLE |
+ impl::ExternalTexture::Usage::WRITEABLE);
drawHolePunchLayer(renderengine, display, dstTexture);
drawSolidLayers(renderengine, display, dstTexture);
@@ -398,8 +399,8 @@
new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888,
1, usageExternal, "primeShaderCache_external");
const auto externalTexture =
- std::make_shared<ExternalTexture>(externalBuffer, *renderengine,
- ExternalTexture::Usage::READABLE);
+ std::make_shared<impl::ExternalTexture>(externalBuffer, *renderengine,
+ impl::ExternalTexture::Usage::READABLE);
std::vector<const std::shared_ptr<ExternalTexture>> textures =
{srcTexture, externalTexture};
@@ -412,8 +413,8 @@
status_t error = f16ExternalBuffer->initCheck();
if (!error) {
const auto f16ExternalTexture =
- std::make_shared<ExternalTexture>(f16ExternalBuffer, *renderengine,
- ExternalTexture::Usage::READABLE);
+ std::make_shared<impl::ExternalTexture>(f16ExternalBuffer, *renderengine,
+ impl::ExternalTexture::Usage::READABLE);
textures.push_back(f16ExternalTexture);
}
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index eb2b2dc..2a25b0b 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -26,6 +26,7 @@
#include <gtest/gtest.h>
#include <renderengine/ExternalTexture.h>
#include <renderengine/RenderEngine.h>
+#include <renderengine/impl/ExternalTexture.h>
#include <sync/sync.h>
#include <system/graphics-base-v1.0.h>
#include <tonemap/tonemap.h>
@@ -178,7 +179,7 @@
public:
std::shared_ptr<renderengine::ExternalTexture> allocateDefaultBuffer() {
return std::make_shared<
- renderengine::
+ renderengine::impl::
ExternalTexture>(new GraphicBuffer(DEFAULT_DISPLAY_WIDTH,
DEFAULT_DISPLAY_HEIGHT,
HAL_PIXEL_FORMAT_RGBA_8888, 1,
@@ -188,15 +189,16 @@
GRALLOC_USAGE_HW_TEXTURE,
"output"),
*mRE,
- renderengine::ExternalTexture::Usage::READABLE |
- renderengine::ExternalTexture::Usage::WRITEABLE);
+ renderengine::impl::ExternalTexture::Usage::READABLE |
+ renderengine::impl::ExternalTexture::Usage::
+ WRITEABLE);
}
// Allocates a 1x1 buffer to fill with a solid color
std::shared_ptr<renderengine::ExternalTexture> allocateSourceBuffer(uint32_t width,
uint32_t height) {
return std::make_shared<
- renderengine::
+ renderengine::impl::
ExternalTexture>(new GraphicBuffer(width, height,
HAL_PIXEL_FORMAT_RGBA_8888, 1,
GRALLOC_USAGE_SW_READ_OFTEN |
@@ -204,8 +206,9 @@
GRALLOC_USAGE_HW_TEXTURE,
"input"),
*mRE,
- renderengine::ExternalTexture::Usage::READABLE |
- renderengine::ExternalTexture::Usage::WRITEABLE);
+ renderengine::impl::ExternalTexture::Usage::READABLE |
+ renderengine::impl::ExternalTexture::Usage::
+ WRITEABLE);
}
std::shared_ptr<renderengine::ExternalTexture> allocateAndFillSourceBuffer(uint32_t width,
@@ -2439,16 +2442,17 @@
};
auto buf = std::make_shared<
- renderengine::ExternalTexture>(new GraphicBuffer(kGreyLevels, 1,
- HAL_PIXEL_FORMAT_RGBA_8888, 1,
- GRALLOC_USAGE_SW_READ_OFTEN |
- GRALLOC_USAGE_SW_WRITE_OFTEN |
- GRALLOC_USAGE_HW_RENDER |
- GRALLOC_USAGE_HW_TEXTURE,
- "input"),
- *mRE,
- renderengine::ExternalTexture::Usage::READABLE |
- renderengine::ExternalTexture::Usage::WRITEABLE);
+ renderengine::impl::
+ ExternalTexture>(new GraphicBuffer(kGreyLevels, 1, HAL_PIXEL_FORMAT_RGBA_8888,
+ 1,
+ GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_SW_WRITE_OFTEN |
+ GRALLOC_USAGE_HW_RENDER |
+ GRALLOC_USAGE_HW_TEXTURE,
+ "input"),
+ *mRE,
+ renderengine::impl::ExternalTexture::Usage::READABLE |
+ renderengine::impl::ExternalTexture::Usage::WRITEABLE);
ASSERT_EQ(0, buf->getBuffer()->initCheck());
{
@@ -2472,16 +2476,17 @@
}
mBuffer = std::make_shared<
- renderengine::ExternalTexture>(new GraphicBuffer(kGreyLevels, 1,
- HAL_PIXEL_FORMAT_RGBA_8888, 1,
- GRALLOC_USAGE_SW_READ_OFTEN |
- GRALLOC_USAGE_SW_WRITE_OFTEN |
- GRALLOC_USAGE_HW_RENDER |
- GRALLOC_USAGE_HW_TEXTURE,
- "output"),
- *mRE,
- renderengine::ExternalTexture::Usage::READABLE |
- renderengine::ExternalTexture::Usage::WRITEABLE);
+ renderengine::impl::
+ ExternalTexture>(new GraphicBuffer(kGreyLevels, 1, HAL_PIXEL_FORMAT_RGBA_8888,
+ 1,
+ GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_SW_WRITE_OFTEN |
+ GRALLOC_USAGE_HW_RENDER |
+ GRALLOC_USAGE_HW_TEXTURE,
+ "output"),
+ *mRE,
+ renderengine::impl::ExternalTexture::Usage::READABLE |
+ renderengine::impl::ExternalTexture::Usage::WRITEABLE);
ASSERT_EQ(0, mBuffer->getBuffer()->initCheck());
const renderengine::LayerSettings layer{
diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
index db7e12b..9685189 100644
--- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp
+++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
@@ -17,6 +17,7 @@
#include <cutils/properties.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <renderengine/impl/ExternalTexture.h>
#include <renderengine/mock/RenderEngine.h>
#include "../threaded/RenderEngineThreaded.h"
@@ -174,9 +175,10 @@
renderengine::DisplaySettings settings;
std::vector<renderengine::LayerSettings> layers;
std::shared_ptr<renderengine::ExternalTexture> buffer = std::make_shared<
- renderengine::ExternalTexture>(new GraphicBuffer(), *mRenderEngine,
- renderengine::ExternalTexture::Usage::READABLE |
- renderengine::ExternalTexture::Usage::WRITEABLE);
+ renderengine::impl::
+ ExternalTexture>(new GraphicBuffer(), *mRenderEngine,
+ renderengine::impl::ExternalTexture::Usage::READABLE |
+ renderengine::impl::ExternalTexture::Usage::WRITEABLE);
base::unique_fd bufferFence;
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp
index 08fc814..a7176d3 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.cpp
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -389,6 +389,20 @@
mCondition.notify_one();
}
+std::optional<pid_t> RenderEngineThreaded::getRenderEngineTid() const {
+ std::promise<pid_t> tidPromise;
+ std::future<pid_t> tidFuture = tidPromise.get_future();
+ {
+ std::lock_guard lock(mThreadMutex);
+ mFunctionCalls.push([&tidPromise](renderengine::RenderEngine& instance) {
+ tidPromise.set_value(gettid());
+ });
+ }
+
+ mCondition.notify_one();
+ return std::make_optional(tidFuture.get());
+}
+
} // namespace threaded
} // namespace renderengine
} // namespace android
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h
index 0159cfa..1ba72dd 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.h
+++ b/libs/renderengine/threaded/RenderEngineThreaded.h
@@ -66,6 +66,7 @@
int getContextPriority() override;
bool supportsBackgroundBlur() override;
void onActiveDisplaySizeChanged(ui::Size size) override;
+ std::optional<pid_t> getRenderEngineTid() const override;
protected:
void mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, bool isRenderable) override;
diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp
index 0a49008..da88e85 100644
--- a/libs/sensor/Sensor.cpp
+++ b/libs/sensor/Sensor.cpp
@@ -276,6 +276,10 @@
mStringType = SENSOR_STRING_TYPE_HINGE_ANGLE;
mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
break;
+ case SENSOR_TYPE_HEAD_TRACKER:
+ mStringType = SENSOR_STRING_TYPE_HEAD_TRACKER;
+ mFlags |= SENSOR_FLAG_CONTINUOUS_MODE;
+ break;
default:
// Only pipe the stringType, requiredPermission and flags for custom sensors.
if (halVersion > SENSORS_DEVICE_API_VERSION_1_0 && hwSensor.stringType) {
@@ -468,7 +472,15 @@
}
void Sensor::setId(int32_t id) {
- mUuid.i64[0] = id;
+ mId = id;
+}
+
+int32_t Sensor::getId() const {
+ return mId;
+}
+
+void Sensor::anonymizeUuid() {
+ mUuid.i64[0] = mId;
mUuid.i64[1] = 0;
}
@@ -485,17 +497,14 @@
}
}
-int32_t Sensor::getId() const {
- return int32_t(mUuid.i64[0]);
-}
-
size_t Sensor::getFlattenedSize() const {
size_t fixedSize =
sizeof(mVersion) + sizeof(mHandle) + sizeof(mType) +
sizeof(mMinValue) + sizeof(mMaxValue) + sizeof(mResolution) +
sizeof(mPower) + sizeof(mMinDelay) + sizeof(mFifoMaxEventCount) +
sizeof(mFifoMaxEventCount) + sizeof(mRequiredPermissionRuntime) +
- sizeof(mRequiredAppOp) + sizeof(mMaxDelay) + sizeof(mFlags) + sizeof(mUuid);
+ sizeof(mRequiredAppOp) + sizeof(mMaxDelay) + sizeof(mFlags) +
+ sizeof(mUuid) + sizeof(mId);
size_t variableSize =
sizeof(uint32_t) + FlattenableUtils::align<4>(mName.length()) +
@@ -529,18 +538,8 @@
FlattenableUtils::write(buffer, size, mRequiredAppOp);
FlattenableUtils::write(buffer, size, mMaxDelay);
FlattenableUtils::write(buffer, size, mFlags);
- if (mUuid.i64[1] != 0) {
- // We should never hit this case with our current API, but we
- // could via a careless API change. If that happens,
- // this code will keep us from leaking our UUID (while probably
- // breaking dynamic sensors). See b/29547335.
- ALOGW("Sensor with UUID being flattened; sending 0. Expect "
- "bad dynamic sensor behavior");
- uuid_t tmpUuid; // default constructor makes this 0.
- FlattenableUtils::write(buffer, size, tmpUuid);
- } else {
- FlattenableUtils::write(buffer, size, mUuid);
- }
+ FlattenableUtils::write(buffer, size, mUuid);
+ FlattenableUtils::write(buffer, size, mId);
return NO_ERROR;
}
@@ -580,7 +579,7 @@
size_t fixedSize2 =
sizeof(mRequiredPermissionRuntime) + sizeof(mRequiredAppOp) + sizeof(mMaxDelay) +
- sizeof(mFlags) + sizeof(mUuid);
+ sizeof(mFlags) + sizeof(mUuid) + sizeof(mId);
if (size < fixedSize2) {
return NO_MEMORY;
}
@@ -590,6 +589,7 @@
FlattenableUtils::read(buffer, size, mMaxDelay);
FlattenableUtils::read(buffer, size, mFlags);
FlattenableUtils::read(buffer, size, mUuid);
+ FlattenableUtils::read(buffer, size, mId);
return NO_ERROR;
}
diff --git a/libs/sensor/include/sensor/Sensor.h b/libs/sensor/include/sensor/Sensor.h
index 374b68f..bae8a13 100644
--- a/libs/sensor/include/sensor/Sensor.h
+++ b/libs/sensor/include/sensor/Sensor.h
@@ -96,11 +96,8 @@
bool isDirectChannelTypeSupported(int32_t sharedMemType) const;
int32_t getReportingMode() const;
- // Note that after setId() has been called, getUuid() no longer
- // returns the UUID.
- // TODO(b/29547335): Remove getUuid(), add getUuidIndex(), and
- // make sure setId() doesn't change the UuidIndex.
const uuid_t& getUuid() const;
+ void anonymizeUuid();
int32_t getId() const;
void setId(int32_t id);
@@ -132,10 +129,8 @@
int32_t mRequiredAppOp;
int32_t mMaxDelay;
uint32_t mFlags;
- // TODO(b/29547335): Get rid of this field and replace with an index.
- // The index will be into a separate global vector of UUIDs.
- // Also add an mId field (and change flatten/unflatten appropriately).
uuid_t mUuid;
+ int32_t mId;
static void flattenString8(void*& buffer, size_t& size, const String8& string8);
static bool unflattenString8(void const*& buffer, size_t& size, String8& outputString8);
};
diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp
index 8ac08fb..3fc99bb 100644
--- a/libs/ui/Gralloc4.cpp
+++ b/libs/ui/Gralloc4.cpp
@@ -941,9 +941,10 @@
}
double allocationSizeKiB = static_cast<double>(allocationSize) / 1024;
- *outDump << "+ name:" << name << ", id:" << bufferId << ", size:" << allocationSizeKiB
- << "KiB, w/h:" << width << "x" << height << ", usage: 0x" << std::hex << usage
- << std::dec << ", req fmt:" << static_cast<int32_t>(pixelFormatRequested)
+ *outDump << "+ name:" << name << ", id:" << bufferId << ", size:" << std::fixed
+ << allocationSizeKiB << "KiB, w/h:" << width << "x" << height << ", usage: 0x"
+ << std::hex << usage << std::dec
+ << ", req fmt:" << static_cast<int32_t>(pixelFormatRequested)
<< ", fourcc/mod:" << pixelFormatFourCC << "/" << pixelFormatModifier
<< ", dataspace: 0x" << std::hex << static_cast<uint32_t>(dataspace) << std::dec
<< ", compressed: ";
diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp
index b9b6a19..5b4ee21 100644
--- a/services/gpuservice/Android.bp
+++ b/services/gpuservice/Android.bp
@@ -31,6 +31,7 @@
"libcutils",
"libgfxstats",
"libgpumem",
+ "libgpuwork",
"libgpumemtracer",
"libgraphicsenv",
"liblog",
diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp
index 52d5d4f..7b9782f 100644
--- a/services/gpuservice/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -25,6 +25,7 @@
#include <binder/PermissionCache.h>
#include <cutils/properties.h>
#include <gpumem/GpuMem.h>
+#include <gpuwork/GpuWork.h>
#include <gpustats/GpuStats.h>
#include <private/android_filesystem_config.h>
#include <tracing/GpuMemTracer.h>
@@ -50,13 +51,20 @@
GpuService::GpuService()
: mGpuMem(std::make_shared<GpuMem>()),
+ mGpuWork(std::make_shared<gpuwork::GpuWork>()),
mGpuStats(std::make_unique<GpuStats>()),
mGpuMemTracer(std::make_unique<GpuMemTracer>()) {
- std::thread asyncInitThread([this]() {
+
+ std::thread gpuMemAsyncInitThread([this]() {
mGpuMem->initialize();
mGpuMemTracer->initialize(mGpuMem);
});
- asyncInitThread.detach();
+ gpuMemAsyncInitThread.detach();
+
+ std::thread gpuWorkAsyncInitThread([this]() {
+ mGpuWork->initialize();
+ });
+ gpuWorkAsyncInitThread.detach();
};
void GpuService::setGpuStats(const std::string& driverPackageName,
@@ -124,6 +132,7 @@
bool dumpDriverInfo = false;
bool dumpMem = false;
bool dumpStats = false;
+ bool dumpWork = false;
size_t numArgs = args.size();
if (numArgs) {
@@ -134,9 +143,11 @@
dumpDriverInfo = true;
} else if (args[index] == String16("--gpumem")) {
dumpMem = true;
+ } else if (args[index] == String16("--gpuwork")) {
+ dumpWork = true;
}
}
- dumpAll = !(dumpDriverInfo || dumpMem || dumpStats);
+ dumpAll = !(dumpDriverInfo || dumpMem || dumpStats || dumpWork);
}
if (dumpAll || dumpDriverInfo) {
@@ -151,6 +162,10 @@
mGpuStats->dump(args, &result);
result.append("\n");
}
+ if (dumpAll || dumpWork) {
+ mGpuWork->dump(args, &result);
+ result.append("\n");
+ }
}
write(fd, result.c_str(), result.size());
diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h
index 409084b..d7313d1 100644
--- a/services/gpuservice/GpuService.h
+++ b/services/gpuservice/GpuService.h
@@ -28,6 +28,10 @@
namespace android {
+namespace gpuwork {
+class GpuWork;
+}
+
class GpuMem;
class GpuStats;
class GpuMemTracer;
@@ -77,6 +81,7 @@
* Attributes
*/
std::shared_ptr<GpuMem> mGpuMem;
+ std::shared_ptr<gpuwork::GpuWork> mGpuWork;
std::unique_ptr<GpuStats> mGpuStats;
std::unique_ptr<GpuMemTracer> mGpuMemTracer;
std::mutex mLock;
diff --git a/services/gpuservice/OWNERS b/services/gpuservice/OWNERS
index ac300d0..0ff65bf 100644
--- a/services/gpuservice/OWNERS
+++ b/services/gpuservice/OWNERS
@@ -1,2 +1,6 @@
chrisforbes@google.com
lpy@google.com
+alecmouri@google.com
+lfy@google.com
+paulthomson@google.com
+pbaiget@google.com
diff --git a/services/gpuservice/gpuwork/Android.bp b/services/gpuservice/gpuwork/Android.bp
new file mode 100644
index 0000000..89b31a6
--- /dev/null
+++ b/services/gpuservice/gpuwork/Android.bp
@@ -0,0 +1,61 @@
+// Copyright 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_library_shared {
+ name: "libgpuwork",
+ srcs: [
+ "GpuWork.cpp",
+ ],
+ header_libs: [
+ "gpu_work_structs",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libbpf_bcc",
+ "libbpf_android",
+ "libcutils",
+ "liblog",
+ "libstatslog",
+ "libstatspull",
+ "libutils",
+ ],
+ export_include_dirs: [
+ "include",
+ ],
+ export_header_lib_headers: [
+ "gpu_work_structs",
+ ],
+ export_shared_lib_headers: [
+ "libbase",
+ "libbpf_android",
+ "libstatspull",
+ ],
+ cppflags: [
+ "-Wall",
+ "-Werror",
+ "-Wformat",
+ "-Wthread-safety",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+ required: [
+ "bpfloader",
+ "gpu_work.o",
+ ],
+}
diff --git a/services/gpuservice/gpuwork/GpuWork.cpp b/services/gpuservice/gpuwork/GpuWork.cpp
new file mode 100644
index 0000000..e7b1cd4
--- /dev/null
+++ b/services/gpuservice/gpuwork/GpuWork.cpp
@@ -0,0 +1,504 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "GpuWork"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "gpuwork/GpuWork.h"
+
+#include <android-base/stringprintf.h>
+#include <binder/PermissionCache.h>
+#include <bpf/WaitForProgsLoaded.h>
+#include <libbpf.h>
+#include <libbpf_android.h>
+#include <log/log.h>
+#include <random>
+#include <stats_event.h>
+#include <statslog.h>
+#include <unistd.h>
+#include <utils/Timers.h>
+#include <utils/Trace.h>
+
+#include <bit>
+#include <chrono>
+#include <cstdint>
+#include <limits>
+#include <map>
+#include <mutex>
+#include <unordered_map>
+#include <vector>
+
+#include "gpuwork/gpu_work.h"
+
+#define MS_IN_NS (1000000)
+
+namespace android {
+namespace gpuwork {
+
+namespace {
+
+// Gets a BPF map from |mapPath|.
+template <class Key, class Value>
+bool getBpfMap(const char* mapPath, bpf::BpfMap<Key, Value>* out) {
+ errno = 0;
+ auto map = bpf::BpfMap<Key, Value>(mapPath);
+ if (!map.isValid()) {
+ ALOGW("Failed to create bpf map from %s [%d(%s)]", mapPath, errno, strerror(errno));
+ return false;
+ }
+ *out = std::move(map);
+ return true;
+}
+
+template <typename SourceType>
+inline int32_t cast_int32(SourceType) = delete;
+
+template <typename SourceType>
+inline int32_t bitcast_int32(SourceType) = delete;
+
+template <>
+inline int32_t bitcast_int32<uint32_t>(uint32_t source) {
+ int32_t result;
+ memcpy(&result, &source, sizeof(result));
+ return result;
+}
+
+template <>
+inline int32_t cast_int32<uint64_t>(uint64_t source) {
+ if (source > std::numeric_limits<int32_t>::max()) {
+ return std::numeric_limits<int32_t>::max();
+ }
+ return static_cast<int32_t>(source);
+}
+
+template <>
+inline int32_t cast_int32<long long>(long long source) {
+ if (source > std::numeric_limits<int32_t>::max()) {
+ return std::numeric_limits<int32_t>::max();
+ } else if (source < std::numeric_limits<int32_t>::min()) {
+ return std::numeric_limits<int32_t>::min();
+ }
+ return static_cast<int32_t>(source);
+}
+
+} // namespace
+
+using base::StringAppendF;
+
+GpuWork::~GpuWork() {
+ // If we created our clearer thread, then we must stop it and join it.
+ if (mMapClearerThread.joinable()) {
+ // Tell the thread to terminate.
+ {
+ std::scoped_lock<std::mutex> lock(mMutex);
+ mIsTerminating = true;
+ mIsTerminatingConditionVariable.notify_all();
+ }
+
+ // Now, we can join it.
+ mMapClearerThread.join();
+ }
+
+ {
+ std::scoped_lock<std::mutex> lock(mMutex);
+ if (mStatsdRegistered) {
+ AStatsManager_clearPullAtomCallback(android::util::GPU_FREQ_TIME_IN_STATE_PER_UID);
+ }
+ }
+
+ bpf_detach_tracepoint("power", "gpu_work_period");
+}
+
+void GpuWork::initialize() {
+ // Make sure BPF programs are loaded.
+ bpf::waitForProgsLoaded();
+
+ waitForPermissions();
+
+ // Get the BPF maps before trying to attach the BPF program; if we can't get
+ // the maps then there is no point in attaching the BPF program.
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ if (!getBpfMap("/sys/fs/bpf/map_gpu_work_gpu_work_map", &mGpuWorkMap)) {
+ return;
+ }
+
+ if (!getBpfMap("/sys/fs/bpf/map_gpu_work_gpu_work_global_data", &mGpuWorkGlobalDataMap)) {
+ return;
+ }
+
+ mPreviousMapClearTimePoint = std::chrono::steady_clock::now();
+ }
+
+ // Attach the tracepoint ONLY if we got the map above.
+ if (!attachTracepoint("/sys/fs/bpf/prog_gpu_work_tracepoint_power_gpu_work_period", "power",
+ "gpu_work_period")) {
+ return;
+ }
+
+ // Create the map clearer thread, and store it to |mMapClearerThread|.
+ std::thread thread([this]() { periodicallyClearMap(); });
+
+ mMapClearerThread.swap(thread);
+
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ AStatsManager_setPullAtomCallback(int32_t{android::util::GPU_FREQ_TIME_IN_STATE_PER_UID},
+ nullptr, GpuWork::pullAtomCallback, this);
+ mStatsdRegistered = true;
+ }
+
+ ALOGI("Initialized!");
+
+ mInitialized.store(true);
+}
+
+void GpuWork::dump(const Vector<String16>& /* args */, std::string* result) {
+ if (!mInitialized.load()) {
+ result->append("GPU time in state information is not available.\n");
+ return;
+ }
+
+ // Ordered map ensures output data is sorted by UID.
+ std::map<Uid, UidTrackingInfo> dumpMap;
+
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ if (!mGpuWorkMap.isValid()) {
+ result->append("GPU time in state map is not available.\n");
+ return;
+ }
+
+ // Iteration of BPF hash maps can be unreliable (no data races, but elements
+ // may be repeated), as the map is typically being modified by other
+ // threads. The buckets are all preallocated. Our eBPF program only updates
+ // entries (in-place) or adds entries. |GpuWork| only iterates or clears the
+ // map while holding |mMutex|. Given this, we should be able to iterate over
+ // all elements reliably. In the worst case, we might see elements more than
+ // once.
+
+ // Note that userspace reads of BPF maps make a copy of the value, and
+ // thus the returned value is not being concurrently accessed by the BPF
+ // program (no atomic reads needed below).
+
+ mGpuWorkMap.iterateWithValue([&dumpMap](const Uid& key, const UidTrackingInfo& value,
+ const android::bpf::BpfMap<Uid, UidTrackingInfo>&)
+ -> base::Result<void> {
+ dumpMap[key] = value;
+ return {};
+ });
+ }
+
+ // Find the largest frequency where some UID has spent time in that frequency.
+ size_t largestFrequencyWithTime = 0;
+ for (const auto& uidToUidInfo : dumpMap) {
+ for (size_t i = largestFrequencyWithTime + 1; i < kNumTrackedFrequencies; ++i) {
+ if (uidToUidInfo.second.frequency_times_ns[i] > 0) {
+ largestFrequencyWithTime = i;
+ }
+ }
+ }
+
+ // Dump time in state information.
+ // E.g.
+ // uid/freq: 0MHz 50MHz 100MHz ...
+ // 1000: 0 0 0 0 ...
+ // 1003: 0 0 3456 0 ...
+ // [errors:3]1006: 0 0 3456 0 ...
+
+ // Header.
+ result->append("GPU time in frequency state in ms.\n");
+ result->append("uid/freq: 0MHz");
+ for (size_t i = 1; i <= largestFrequencyWithTime; ++i) {
+ StringAppendF(result, " %zuMHz", i * 50);
+ }
+ result->append("\n");
+
+ for (const auto& uidToUidInfo : dumpMap) {
+ if (uidToUidInfo.second.error_count) {
+ StringAppendF(result, "[errors:%" PRIu32 "]", uidToUidInfo.second.error_count);
+ }
+ StringAppendF(result, "%" PRIu32 ":", uidToUidInfo.first);
+ for (size_t i = 0; i <= largestFrequencyWithTime; ++i) {
+ StringAppendF(result, " %" PRIu64,
+ uidToUidInfo.second.frequency_times_ns[i] / MS_IN_NS);
+ }
+ result->append("\n");
+ }
+}
+
+bool GpuWork::attachTracepoint(const char* programPath, const char* tracepointGroup,
+ const char* tracepointName) {
+ errno = 0;
+ base::unique_fd fd(bpf::retrieveProgram(programPath));
+ if (fd < 0) {
+ ALOGW("Failed to retrieve pinned program from %s [%d(%s)]", programPath, errno,
+ strerror(errno));
+ return false;
+ }
+
+ // Attach the program to the tracepoint. The tracepoint is automatically enabled.
+ errno = 0;
+ int count = 0;
+ while (bpf_attach_tracepoint(fd.get(), tracepointGroup, tracepointName) < 0) {
+ if (++count > kGpuWaitTimeoutSeconds) {
+ ALOGW("Failed to attach bpf program to %s/%s tracepoint [%d(%s)]", tracepointGroup,
+ tracepointName, errno, strerror(errno));
+ return false;
+ }
+ // Retry until GPU driver loaded or timeout.
+ sleep(1);
+ errno = 0;
+ }
+
+ return true;
+}
+
+AStatsManager_PullAtomCallbackReturn GpuWork::pullAtomCallback(int32_t atomTag,
+ AStatsEventList* data,
+ void* cookie) {
+ ATRACE_CALL();
+
+ GpuWork* gpuWork = reinterpret_cast<GpuWork*>(cookie);
+ if (atomTag == android::util::GPU_FREQ_TIME_IN_STATE_PER_UID) {
+ return gpuWork->pullFrequencyAtoms(data);
+ }
+
+ return AStatsManager_PULL_SKIP;
+}
+
+AStatsManager_PullAtomCallbackReturn GpuWork::pullFrequencyAtoms(AStatsEventList* data) {
+ ATRACE_CALL();
+
+ if (!data || !mInitialized.load()) {
+ return AStatsManager_PULL_SKIP;
+ }
+
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ if (!mGpuWorkMap.isValid()) {
+ return AStatsManager_PULL_SKIP;
+ }
+
+ std::unordered_map<Uid, UidTrackingInfo> uidInfos;
+
+ // Iteration of BPF hash maps can be unreliable (no data races, but elements
+ // may be repeated), as the map is typically being modified by other
+ // threads. The buckets are all preallocated. Our eBPF program only updates
+ // entries (in-place) or adds entries. |GpuWork| only iterates or clears the
+ // map while holding |mMutex|. Given this, we should be able to iterate over
+ // all elements reliably. In the worst case, we might see elements more than
+ // once.
+
+ // Note that userspace reads of BPF maps make a copy of the value, and thus
+ // the returned value is not being concurrently accessed by the BPF program
+ // (no atomic reads needed below).
+
+ mGpuWorkMap.iterateWithValue(
+ [&uidInfos](const Uid& key, const UidTrackingInfo& value,
+ const android::bpf::BpfMap<Uid, UidTrackingInfo>&) -> base::Result<void> {
+ uidInfos[key] = value;
+ return {};
+ });
+
+ ALOGI("pullFrequencyAtoms: uidInfos.size() == %zu", uidInfos.size());
+
+ // Get a list of just the UIDs; the order does not matter.
+ std::vector<Uid> uids;
+ for (const auto& pair : uidInfos) {
+ uids.push_back(pair.first);
+ }
+
+ std::random_device device;
+ std::default_random_engine random_engine(device());
+
+ // If we have more than |kNumSampledUids| UIDs, choose |kNumSampledUids|
+ // random UIDs. We swap them to the front of the list. Given the list
+ // indices 0..i..n-1, we have the following inclusive-inclusive ranges:
+ // - [0, i-1] == the randomly chosen elements.
+ // - [i, n-1] == the remaining unchosen elements.
+ if (uids.size() > kNumSampledUids) {
+ for (size_t i = 0; i < kNumSampledUids; ++i) {
+ std::uniform_int_distribution<size_t> uniform_dist(i, uids.size() - 1);
+ size_t random_index = uniform_dist(random_engine);
+ std::swap(uids[i], uids[random_index]);
+ }
+ // Only keep the front |kNumSampledUids| elements.
+ uids.resize(kNumSampledUids);
+ }
+
+ ALOGI("pullFrequencyAtoms: uids.size() == %zu", uids.size());
+
+ auto now = std::chrono::steady_clock::now();
+
+ int32_t duration = cast_int32(
+ std::chrono::duration_cast<std::chrono::seconds>(now - mPreviousMapClearTimePoint)
+ .count());
+
+ for (const Uid uid : uids) {
+ const UidTrackingInfo& info = uidInfos[uid];
+ ALOGI("pullFrequencyAtoms: adding stats for UID %" PRIu32, uid);
+ android::util::addAStatsEvent(data, int32_t{android::util::GPU_FREQ_TIME_IN_STATE_PER_UID},
+ // uid
+ bitcast_int32(uid),
+ // time_duration_seconds
+ int32_t{duration},
+ // max_freq_mhz
+ int32_t{1000},
+ // freq_0_mhz_time_millis
+ cast_int32(info.frequency_times_ns[0] / 1000000),
+ // freq_50_mhz_time_millis
+ cast_int32(info.frequency_times_ns[1] / 1000000),
+ // ... etc. ...
+ cast_int32(info.frequency_times_ns[2] / 1000000),
+ cast_int32(info.frequency_times_ns[3] / 1000000),
+ cast_int32(info.frequency_times_ns[4] / 1000000),
+ cast_int32(info.frequency_times_ns[5] / 1000000),
+ cast_int32(info.frequency_times_ns[6] / 1000000),
+ cast_int32(info.frequency_times_ns[7] / 1000000),
+ cast_int32(info.frequency_times_ns[8] / 1000000),
+ cast_int32(info.frequency_times_ns[9] / 1000000),
+ cast_int32(info.frequency_times_ns[10] / 1000000),
+ cast_int32(info.frequency_times_ns[11] / 1000000),
+ cast_int32(info.frequency_times_ns[12] / 1000000),
+ cast_int32(info.frequency_times_ns[13] / 1000000),
+ cast_int32(info.frequency_times_ns[14] / 1000000),
+ cast_int32(info.frequency_times_ns[15] / 1000000),
+ cast_int32(info.frequency_times_ns[16] / 1000000),
+ cast_int32(info.frequency_times_ns[17] / 1000000),
+ cast_int32(info.frequency_times_ns[18] / 1000000),
+ cast_int32(info.frequency_times_ns[19] / 1000000),
+ // freq_1000_mhz_time_millis
+ cast_int32(info.frequency_times_ns[20] / 1000000));
+ }
+ clearMap();
+ return AStatsManager_PULL_SUCCESS;
+}
+
+void GpuWork::periodicallyClearMap() {
+ std::unique_lock<std::mutex> lock(mMutex);
+
+ auto previousTime = std::chrono::steady_clock::now();
+
+ while (true) {
+ if (mIsTerminating) {
+ break;
+ }
+ auto nextTime = std::chrono::steady_clock::now();
+ auto differenceSeconds =
+ std::chrono::duration_cast<std::chrono::seconds>(nextTime - previousTime);
+ if (differenceSeconds.count() > kMapClearerWaitDurationSeconds) {
+ // It has been >1 hour, so clear the map, if needed.
+ clearMapIfNeeded();
+ // We only update |previousTime| if we actually checked the map.
+ previousTime = nextTime;
+ }
+ // Sleep for ~1 hour. It does not matter if we don't check the map for 2
+ // hours.
+ mIsTerminatingConditionVariable.wait_for(lock,
+ std::chrono::seconds{
+ kMapClearerWaitDurationSeconds});
+ }
+}
+
+void GpuWork::clearMapIfNeeded() {
+ if (!mInitialized.load() || !mGpuWorkMap.isValid() || !mGpuWorkGlobalDataMap.isValid()) {
+ ALOGW("Map clearing could not occur because we are not initialized properly");
+ return;
+ }
+
+ base::Result<GlobalData> globalData = mGpuWorkGlobalDataMap.readValue(0);
+ if (!globalData.ok()) {
+ ALOGW("Could not read BPF global data map entry");
+ return;
+ }
+
+ // Note that userspace reads of BPF maps make a copy of the value, and thus
+ // the return value is not being concurrently accessed by the BPF program
+ // (no atomic reads needed below).
+
+ uint64_t numEntries = globalData.value().num_map_entries;
+
+ // If the map is <=75% full, we do nothing.
+ if (numEntries <= (kMaxTrackedUids / 4) * 3) {
+ return;
+ }
+
+ clearMap();
+}
+
+void GpuWork::clearMap() {
+ if (!mInitialized.load() || !mGpuWorkMap.isValid() || !mGpuWorkGlobalDataMap.isValid()) {
+ ALOGW("Map clearing could not occur because we are not initialized properly");
+ return;
+ }
+
+ base::Result<GlobalData> globalData = mGpuWorkGlobalDataMap.readValue(0);
+ if (!globalData.ok()) {
+ ALOGW("Could not read BPF global data map entry");
+ return;
+ }
+
+ // Iterating BPF maps to delete keys is tricky. If we just repeatedly call
+ // |getFirstKey()| and delete that, we may loop forever (or for a long time)
+ // because our BPF program might be repeatedly re-adding UID keys. Also,
+ // even if we limit the number of elements we try to delete, we might only
+ // delete new entries, leaving old entries in the map. If we delete a key A
+ // and then call |getNextKey(A)|, the first key in the map is returned, so
+ // we have the same issue.
+ //
+ // Thus, we instead get the next key and then delete the previous key. We
+ // also limit the number of deletions we try, just in case.
+
+ base::Result<Uid> key = mGpuWorkMap.getFirstKey();
+
+ for (size_t i = 0; i < kMaxTrackedUids; ++i) {
+ if (!key.ok()) {
+ break;
+ }
+ base::Result<Uid> previousKey = key;
+ key = mGpuWorkMap.getNextKey(previousKey.value());
+ mGpuWorkMap.deleteValue(previousKey.value());
+ }
+
+ // Reset our counter; |globalData| is a copy of the data, so we have to use
+ // |writeValue|.
+ globalData.value().num_map_entries = 0;
+ mGpuWorkGlobalDataMap.writeValue(0, globalData.value(), BPF_ANY);
+
+ // Update |mPreviousMapClearTimePoint| so we know when we started collecting
+ // the stats.
+ mPreviousMapClearTimePoint = std::chrono::steady_clock::now();
+}
+
+void GpuWork::waitForPermissions() {
+ const String16 permissionRegisterStatsPullAtom(kPermissionRegisterStatsPullAtom);
+ int count = 0;
+ while (!PermissionCache::checkPermission(permissionRegisterStatsPullAtom, getpid(), getuid())) {
+ if (++count > kPermissionsWaitTimeoutSeconds) {
+ ALOGW("Timed out waiting for android.permission.REGISTER_STATS_PULL_ATOM");
+ return;
+ }
+ // Retry.
+ sleep(1);
+ }
+}
+
+} // namespace gpuwork
+} // namespace android
diff --git a/services/gpuservice/gpuwork/bpfprogs/Android.bp b/services/gpuservice/gpuwork/bpfprogs/Android.bp
new file mode 100644
index 0000000..b3c4eff
--- /dev/null
+++ b/services/gpuservice/gpuwork/bpfprogs/Android.bp
@@ -0,0 +1,35 @@
+// Copyright 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+bpf {
+ name: "gpu_work.o",
+ srcs: ["gpu_work.c"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wformat",
+ "-Wthread-safety",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+}
+
+cc_library_headers {
+ name: "gpu_work_structs",
+ export_include_dirs: ["include"],
+}
diff --git a/services/gpuservice/gpuwork/bpfprogs/gpu_work.c b/services/gpuservice/gpuwork/bpfprogs/gpu_work.c
new file mode 100644
index 0000000..a0e1b22
--- /dev/null
+++ b/services/gpuservice/gpuwork/bpfprogs/gpu_work.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "include/gpuwork/gpu_work.h"
+
+#include <linux/bpf.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef MOCK_BPF
+#include <test/mock_bpf_helpers.h>
+#else
+#include <bpf_helpers.h>
+#endif
+
+#define S_IN_NS (1000000000)
+#define MHZ_IN_KHZS (1000)
+
+typedef uint32_t Uid;
+
+// A map from UID to |UidTrackingInfo|.
+DEFINE_BPF_MAP_GRW(gpu_work_map, HASH, Uid, UidTrackingInfo, kMaxTrackedUids, AID_GRAPHICS);
+
+// A map containing a single entry of |GlobalData|.
+DEFINE_BPF_MAP_GRW(gpu_work_global_data, ARRAY, uint32_t, GlobalData, 1, AID_GRAPHICS);
+
+// GpuUidWorkPeriodEvent defines the structure of a kernel tracepoint under the
+// tracepoint system (also referred to as the group) "power" and name
+// "gpu_work_period". In summary, the kernel tracepoint should be
+// "power/gpu_work_period", available at:
+//
+// /sys/kernel/tracing/events/power/gpu_work_period/
+//
+// GpuUidWorkPeriodEvent defines a non-overlapping, non-zero period of time when
+// work was running on the GPU for a given application (identified by its UID;
+// the persistent, unique ID of the application) from |start_time_ns| to
+// |end_time_ns|. Drivers should issue this tracepoint as soon as possible
+// (within 1 second) after |end_time_ns|. For a given UID, periods must not
+// overlap, but periods from different UIDs can overlap (and should overlap, if
+// and only if that is how the work was executed). The period includes
+// information such as |frequency_khz|, the frequency that the GPU was running
+// at during the period, and |includes_compute_work|, whether the work included
+// compute shader work (not just graphics work). GPUs may have multiple
+// frequencies that can be adjusted, but the driver should report the frequency
+// that most closely estimates power usage (e.g. the frequency of shader cores,
+// not a scheduling unit).
+//
+// If any information changes while work from the UID is running on the GPU
+// (e.g. the GPU frequency changes, or the work starts/stops including compute
+// work) then the driver must conceptually end the period, issue the tracepoint,
+// start tracking a new period, and eventually issue a second tracepoint when
+// the work completes or when the information changes again. In this case, the
+// |end_time_ns| of the first period must equal the |start_time_ns| of the
+// second period. The driver may also end and start a new period (without a
+// gap), even if no information changes. For example, this might be convenient
+// if there is a collection of work from a UID running on the GPU for a long
+// time; ending and starting a period as individual parts of the work complete
+// allows the consumer of the tracepoint to be updated about the ongoing work.
+//
+// For a given UID, the tracepoints must be emitted in order; that is, the
+// |start_time_ns| of each subsequent tracepoint for a given UID must be
+// monotonically increasing.
+typedef struct {
+ // Actual fields start at offset 8.
+ uint64_t reserved;
+
+ // The UID of the process (i.e. persistent, unique ID of the Android app)
+ // that submitted work to the GPU.
+ uint32_t uid;
+
+ // The GPU frequency during the period. GPUs may have multiple frequencies
+ // that can be adjusted, but the driver should report the frequency that
+ // would most closely estimate power usage (e.g. the frequency of shader
+ // cores, not a scheduling unit).
+ uint32_t frequency_khz;
+
+ // The start time of the period in nanoseconds. The clock must be
+ // CLOCK_MONOTONIC, as returned by the ktime_get_ns(void) function.
+ uint64_t start_time_ns;
+
+ // The end time of the period in nanoseconds. The clock must be
+ // CLOCK_MONOTONIC, as returned by the ktime_get_ns(void) function.
+ uint64_t end_time_ns;
+
+ // Flags about the work. Reserved for future use.
+ uint64_t flags;
+
+ // The maximum GPU frequency allowed during the period according to the
+ // thermal throttling policy. Must be 0 if no thermal throttling was
+ // enforced during the period. The value must relate to |frequency_khz|; in
+ // other words, if |frequency_khz| is the frequency of the GPU shader cores,
+ // then |thermally_throttled_max_frequency_khz| must be the maximum allowed
+ // frequency of the GPU shader cores (not the maximum allowed frequency of
+ // some other part of the GPU).
+ //
+ // Note: Unlike with other fields of this struct, if the
+ // |thermally_throttled_max_frequency_khz| value conceptually changes while
+ // work from a UID is running on the GPU then the GPU driver does NOT need
+ // to accurately report this by ending the period and starting to track a
+ // new period; instead, the GPU driver may report any one of the
+ // |thermally_throttled_max_frequency_khz| values that was enforced during
+ // the period. The motivation for this relaxation is that we assume the
+ // maximum frequency will not be changing rapidly, and so capturing the
+ // exact point at which the change occurs is unnecessary.
+ uint32_t thermally_throttled_max_frequency_khz;
+
+} GpuUidWorkPeriodEvent;
+
+_Static_assert(offsetof(GpuUidWorkPeriodEvent, uid) == 8 &&
+ offsetof(GpuUidWorkPeriodEvent, frequency_khz) == 12 &&
+ offsetof(GpuUidWorkPeriodEvent, start_time_ns) == 16 &&
+ offsetof(GpuUidWorkPeriodEvent, end_time_ns) == 24 &&
+ offsetof(GpuUidWorkPeriodEvent, flags) == 32 &&
+ offsetof(GpuUidWorkPeriodEvent, thermally_throttled_max_frequency_khz) == 40,
+ "Field offsets of struct GpuUidWorkPeriodEvent must not be changed because they "
+ "must match the tracepoint field offsets found via adb shell cat "
+ "/sys/kernel/tracing/events/power/gpu_work_period/format");
+
+DEFINE_BPF_PROG("tracepoint/power/gpu_work_period", AID_ROOT, AID_GRAPHICS, tp_gpu_work_period)
+(GpuUidWorkPeriodEvent* const args) {
+ // Note: In BPF programs, |__sync_fetch_and_add| is translated to an atomic
+ // add.
+
+ const uint32_t uid = args->uid;
+
+ // Get |UidTrackingInfo| for |uid|.
+ UidTrackingInfo* uid_tracking_info = bpf_gpu_work_map_lookup_elem(&uid);
+ if (!uid_tracking_info) {
+ // There was no existing entry, so we add a new one.
+ UidTrackingInfo initial_info;
+ __builtin_memset(&initial_info, 0, sizeof(initial_info));
+ if (0 == bpf_gpu_work_map_update_elem(&uid, &initial_info, BPF_NOEXIST)) {
+ // We added an entry to the map, so we increment our entry counter in
+ // |GlobalData|.
+ const uint32_t zero = 0;
+ // Get the |GlobalData|.
+ GlobalData* global_data = bpf_gpu_work_global_data_lookup_elem(&zero);
+ // Getting the global data never fails because it is an |ARRAY| map,
+ // but we need to keep the verifier happy.
+ if (global_data) {
+ __sync_fetch_and_add(&global_data->num_map_entries, 1);
+ }
+ }
+ uid_tracking_info = bpf_gpu_work_map_lookup_elem(&uid);
+ if (!uid_tracking_info) {
+ // This should never happen, unless entries are getting deleted at
+ // this moment. If so, we just give up.
+ return 0;
+ }
+ }
+
+ // The period duration must be non-zero.
+ if (args->start_time_ns >= args->end_time_ns) {
+ __sync_fetch_and_add(&uid_tracking_info->error_count, 1);
+ return 0;
+ }
+
+ // The frequency must not be 0.
+ if (args->frequency_khz == 0) {
+ __sync_fetch_and_add(&uid_tracking_info->error_count, 1);
+ return 0;
+ }
+
+ // Calculate the frequency index: see |UidTrackingInfo.frequency_times_ns|.
+ // Round to the nearest 50MHz bucket.
+ uint32_t frequency_index =
+ ((args->frequency_khz / MHZ_IN_KHZS) + (kFrequencyGranularityMhz / 2)) /
+ kFrequencyGranularityMhz;
+ if (frequency_index >= kNumTrackedFrequencies) {
+ frequency_index = kNumTrackedFrequencies - 1;
+ }
+
+ // Never round down to 0MHz, as this is a special bucket (see below) and not
+ // an actual operating point.
+ if (frequency_index == 0) {
+ frequency_index = 1;
+ }
+
+ // Update time in state.
+ __sync_fetch_and_add(&uid_tracking_info->frequency_times_ns[frequency_index],
+ args->end_time_ns - args->start_time_ns);
+
+ if (uid_tracking_info->previous_end_time_ns > args->start_time_ns) {
+ // This must not happen because per-UID periods must not overlap and
+ // must be emitted in order.
+ __sync_fetch_and_add(&uid_tracking_info->error_count, 1);
+ } else {
+ // The period appears to have been emitted after the previous, as
+ // expected, so we can calculate the gap between this and the previous
+ // period.
+ const uint64_t gap_time = args->start_time_ns - uid_tracking_info->previous_end_time_ns;
+
+ // Update |previous_end_time_ns|.
+ uid_tracking_info->previous_end_time_ns = args->end_time_ns;
+
+ // Update the special 0MHz frequency time, which stores the gaps between
+ // periods, but only if the gap is < 1 second.
+ if (gap_time > 0 && gap_time < S_IN_NS) {
+ __sync_fetch_and_add(&uid_tracking_info->frequency_times_ns[0], gap_time);
+ }
+ }
+
+ return 0;
+}
+
+LICENSE("Apache 2.0");
diff --git a/services/gpuservice/gpuwork/bpfprogs/include/gpuwork/gpu_work.h b/services/gpuservice/gpuwork/bpfprogs/include/gpuwork/gpu_work.h
new file mode 100644
index 0000000..4fe8464
--- /dev/null
+++ b/services/gpuservice/gpuwork/bpfprogs/include/gpuwork/gpu_work.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+#include <type_traits>
+
+namespace android {
+namespace gpuwork {
+#endif
+
+typedef struct {
+ // The end time of the previous period from this UID in nanoseconds.
+ uint64_t previous_end_time_ns;
+
+ // The time spent at each GPU frequency while running GPU work from the UID,
+ // in nanoseconds. Array index i stores the time for frequency i*50 MHz. So
+ // index 0 is 0Mhz, index 1 is 50MHz, index 2 is 100MHz, etc., up to index
+ // |kNumTrackedFrequencies|.
+ uint64_t frequency_times_ns[21];
+
+ // The number of times we received |GpuUidWorkPeriodEvent| events in an
+ // unexpected order. See |GpuUidWorkPeriodEvent|.
+ uint32_t error_count;
+
+} UidTrackingInfo;
+
+typedef struct {
+ // We cannot query the number of entries in BPF map |gpu_work_map|. We track
+ // the number of entries (approximately) using a counter so we can check if
+ // the map is nearly full.
+ uint64_t num_map_entries;
+} GlobalData;
+
+static const uint32_t kMaxTrackedUids = 512;
+static const uint32_t kFrequencyGranularityMhz = 50;
+static const uint32_t kNumTrackedFrequencies = 21;
+
+#ifdef __cplusplus
+static_assert(kNumTrackedFrequencies ==
+ std::extent<decltype(UidTrackingInfo::frequency_times_ns)>::value);
+
+} // namespace gpuwork
+} // namespace android
+#endif
diff --git a/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h b/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h
new file mode 100644
index 0000000..b6f493d
--- /dev/null
+++ b/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <bpf/BpfMap.h>
+#include <stats_pull_atom_callback.h>
+#include <utils/Mutex.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+#include <condition_variable>
+#include <cstdint>
+#include <functional>
+#include <thread>
+
+#include "gpuwork/gpu_work.h"
+
+namespace android {
+namespace gpuwork {
+
+class GpuWork {
+public:
+ using Uid = uint32_t;
+
+ GpuWork() = default;
+ ~GpuWork();
+
+ void initialize();
+
+ // Dumps the GPU time in frequency state information.
+ void dump(const Vector<String16>& args, std::string* result);
+
+private:
+ // Attaches tracepoint |tracepoint_group|/|tracepoint_name| to BPF program at path
+ // |program_path|. The tracepoint is also enabled.
+ static bool attachTracepoint(const char* program_path, const char* tracepoint_group,
+ const char* tracepoint_name);
+
+ // Native atom puller callback registered in statsd.
+ static AStatsManager_PullAtomCallbackReturn pullAtomCallback(int32_t atomTag,
+ AStatsEventList* data,
+ void* cookie);
+
+ AStatsManager_PullAtomCallbackReturn pullFrequencyAtoms(AStatsEventList* data);
+
+ // Periodically calls |clearMapIfNeeded| to clear the |mGpuWorkMap| map, if
+ // needed.
+ //
+ // Thread safety analysis is skipped because we need to use
+ // |std::unique_lock|, which is not currently supported by thread safety
+ // analysis.
+ void periodicallyClearMap() NO_THREAD_SAFETY_ANALYSIS;
+
+ // Checks whether the |mGpuWorkMap| map is nearly full and, if so, clears
+ // it.
+ void clearMapIfNeeded() REQUIRES(mMutex);
+
+ // Clears the |mGpuWorkMap| map.
+ void clearMap() REQUIRES(mMutex);
+
+ // Waits for required permissions to become set. This seems to be needed
+ // because platform service permissions might not be set when a service
+ // first starts. See b/214085769.
+ void waitForPermissions();
+
+ // Indicates whether our eBPF components have been initialized.
+ std::atomic<bool> mInitialized = false;
+
+ // A thread that periodically checks whether |mGpuWorkMap| is nearly full
+ // and, if so, clears it.
+ std::thread mMapClearerThread;
+
+ // Mutex for |mGpuWorkMap| and a few other fields.
+ std::mutex mMutex;
+
+ // BPF map for per-UID GPU work.
+ bpf::BpfMap<Uid, UidTrackingInfo> mGpuWorkMap GUARDED_BY(mMutex);
+
+ // BPF map containing a single element for global data.
+ bpf::BpfMap<uint32_t, GlobalData> mGpuWorkGlobalDataMap GUARDED_BY(mMutex);
+
+ // When true, we are being destructed, so |mMapClearerThread| should stop.
+ bool mIsTerminating GUARDED_BY(mMutex);
+
+ // A condition variable for |mIsTerminating|.
+ std::condition_variable mIsTerminatingConditionVariable GUARDED_BY(mMutex);
+
+ // 30 second timeout for trying to attach a BPF program to a tracepoint.
+ static constexpr int kGpuWaitTimeoutSeconds = 30;
+
+ // The wait duration for the map clearer thread; the thread checks the map
+ // every ~1 hour.
+ static constexpr uint32_t kMapClearerWaitDurationSeconds = 60 * 60;
+
+ // Whether our |pullAtomCallback| function is registered.
+ bool mStatsdRegistered GUARDED_BY(mMutex) = false;
+
+ // The number of randomly chosen (i.e. sampled) UIDs to log stats for.
+ static constexpr int kNumSampledUids = 10;
+
+ // The previous time point at which |mGpuWorkMap| was cleared.
+ std::chrono::steady_clock::time_point mPreviousMapClearTimePoint GUARDED_BY(mMutex);
+
+ // Permission to register a statsd puller.
+ static constexpr char16_t kPermissionRegisterStatsPullAtom[] =
+ u"android.permission.REGISTER_STATS_PULL_ATOM";
+
+ // Time limit for waiting for permissions.
+ static constexpr int kPermissionsWaitTimeoutSeconds = 30;
+};
+
+} // namespace gpuwork
+} // namespace android
diff --git a/services/gpuservice/vts/Android.bp b/services/gpuservice/vts/Android.bp
new file mode 100644
index 0000000..83a40e7
--- /dev/null
+++ b/services/gpuservice/vts/Android.bp
@@ -0,0 +1,30 @@
+// Copyright 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+java_test_host {
+ name: "GpuServiceVendorTests",
+ srcs: ["src/**/*.java"],
+ libs: [
+ "tradefed",
+ "vts-core-tradefed-harness",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/services/gpuservice/vts/AndroidTest.xml b/services/gpuservice/vts/AndroidTest.xml
new file mode 100644
index 0000000..02ca07f
--- /dev/null
+++ b/services/gpuservice/vts/AndroidTest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs GpuServiceVendorTests">
+ <test class="com.android.tradefed.testtype.HostTest" >
+ <option name="jar" value="GpuServiceVendorTests.jar" />
+ </test>
+</configuration>
diff --git a/services/gpuservice/vts/OWNERS b/services/gpuservice/vts/OWNERS
new file mode 100644
index 0000000..e789052
--- /dev/null
+++ b/services/gpuservice/vts/OWNERS
@@ -0,0 +1,7 @@
+# Bug component: 653544
+paulthomson@google.com
+pbaiget@google.com
+lfy@google.com
+chrisforbes@google.com
+lpy@google.com
+alecmouri@google.com
diff --git a/services/gpuservice/vts/TEST_MAPPING b/services/gpuservice/vts/TEST_MAPPING
new file mode 100644
index 0000000..b33e962
--- /dev/null
+++ b/services/gpuservice/vts/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "GpuServiceVendorTests"
+ }
+ ]
+}
diff --git a/services/gpuservice/vts/src/com/android/tests/gpuservice/GpuWorkTracepointTest.java b/services/gpuservice/vts/src/com/android/tests/gpuservice/GpuWorkTracepointTest.java
new file mode 100644
index 0000000..4a77d9a
--- /dev/null
+++ b/services/gpuservice/vts/src/com/android/tests/gpuservice/GpuWorkTracepointTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.tests.gpuservice;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.tradefed.util.CommandResult;
+import com.android.tradefed.util.CommandStatus;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.stream.Collectors;
+
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class GpuWorkTracepointTest extends BaseHostJUnit4Test {
+
+ private static final String CPU_FREQUENCY_TRACEPOINT_FORMAT_PATH =
+ "/sys/kernel/tracing/events/power/cpu_frequency/format";
+ private static final String GPU_WORK_PERIOD_TRACEPOINT_FORMAT_PATH =
+ "/sys/kernel/tracing/events/power/gpu_work_period/format";
+
+ @Test
+ public void testReadTracingEvents() throws Exception {
+ // Test |testGpuWorkPeriodTracepointFormat| is dependent on whether certain tracepoint
+ // paths exist. This means the test will vacuously pass if the tracepoint file system is
+ // inaccessible. Thus, as a basic check, we make sure the CPU frequency tracepoint format
+ // is accessible. If not, something is probably fundamentally broken about the tracing
+ // file system.
+ CommandResult commandResult = getDevice().executeShellV2Command(
+ String.format("cat %s", CPU_FREQUENCY_TRACEPOINT_FORMAT_PATH));
+
+ assertEquals(String.format(
+ "Failed to read \"%s\". This probably means that the tracing file system "
+ + "is fundamentally broken in some way, possibly due to bad "
+ + "permissions.",
+ CPU_FREQUENCY_TRACEPOINT_FORMAT_PATH),
+ commandResult.getStatus(), CommandStatus.SUCCESS);
+ }
+
+ @Test
+ public void testGpuWorkPeriodTracepointFormat() throws Exception {
+ CommandResult commandResult = getDevice().executeShellV2Command(
+ String.format("cat %s", GPU_WORK_PERIOD_TRACEPOINT_FORMAT_PATH));
+
+ // If we failed to cat the tracepoint format then the test ends here.
+ assumeTrue(String.format("Failed to cat the gpu_work_period tracepoint format at %s",
+ GPU_WORK_PERIOD_TRACEPOINT_FORMAT_PATH),
+ commandResult.getStatus().equals(CommandStatus.SUCCESS));
+
+ // Otherwise, we check that the fields match the expected fields.
+ String actualFields = Arrays.stream(
+ commandResult.getStdout().trim().split("\n")).filter(
+ s -> s.startsWith("\tfield:")).collect(
+ Collectors.joining("\n"));
+
+ String expectedFields = String.join("\n",
+ "\tfield:unsigned short common_type;\toffset:0;\tsize:2;\tsigned:0;",
+ "\tfield:unsigned char common_flags;\toffset:2;\tsize:1;\tsigned:0;",
+ "\tfield:unsigned char common_preempt_count;\toffset:3;\tsize:1;\tsigned:0;",
+ "\tfield:int common_pid;\toffset:4;\tsize:4;\tsigned:1;",
+ "\tfield:u32 uid;\toffset:8;\tsize:4;\tsigned:0;",
+ "\tfield:u32 frequency;\toffset:12;\tsize:4;\tsigned:0;",
+ "\tfield:u64 start_time;\toffset:16;\tsize:8;\tsigned:0;",
+ "\tfield:u64 end_time;\toffset:24;\tsize:8;\tsigned:0;",
+ "\tfield:u64 flags;\toffset:32;\tsize:8;\tsigned:0;",
+ "\tfield:u32 thermally_throttled_max_frequency_khz;\toffset:40;\tsize:4;\tsigned:0;"
+ );
+
+ // We use |fail| rather than |assertEquals| because it allows us to give a clearer message.
+ if (!expectedFields.equals(actualFields)) {
+ String message = String.format(
+ "Tracepoint format given by \"%s\" does not match the expected format.\n"
+ + "Expected fields:\n%s\n\nActual fields:\n%s\n\n",
+ GPU_WORK_PERIOD_TRACEPOINT_FORMAT_PATH, expectedFields, actualFields);
+ fail(message);
+ }
+ }
+}
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 469c9e6..ec58325 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -72,7 +72,6 @@
"libstatssocket",
"libutils",
"libui",
- "lib-platform-compat-native-api",
"server_configurable_flags",
],
static_libs: [
diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp
index 19cad7b..6c4b11e 100644
--- a/services/inputflinger/InputClassifier.cpp
+++ b/services/inputflinger/InputClassifier.cpp
@@ -29,8 +29,6 @@
#endif
#include <unordered_set>
-#include <android/hardware/input/classifier/1.0/IInputClassifier.h>
-
#define INDENT1 " "
#define INDENT2 " "
#define INDENT3 " "
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index a6baf2f..e000283 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -33,7 +33,6 @@
#include <utils/Errors.h>
#include <utils/RefBase.h>
#include <utils/Timers.h>
-#include <utils/Vector.h>
using android::os::BnInputFlinger;
diff --git a/services/inputflinger/benchmarks/Android.bp b/services/inputflinger/benchmarks/Android.bp
index 902bd0d..75071d5 100644
--- a/services/inputflinger/benchmarks/Android.bp
+++ b/services/inputflinger/benchmarks/Android.bp
@@ -28,7 +28,6 @@
"libstatslog",
"libui",
"libutils",
- "lib-platform-compat-native-api",
],
static_libs: [
"libattestation",
diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp
index 4757d31..cdad9c9 100644
--- a/services/inputflinger/dispatcher/Android.bp
+++ b/services/inputflinger/dispatcher/Android.bp
@@ -66,7 +66,6 @@
"libui",
"libgui",
"libutils",
- "lib-platform-compat-native-api",
"server_configurable_flags",
],
static_libs: [
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index f190f67..3f3c0db 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -24,8 +24,6 @@
#include <android-base/stringprintf.h>
#include <android/os/IInputConstants.h>
#include <binder/Binder.h>
-#include <binder/IServiceManager.h>
-#include <com/android/internal/compat/IPlatformCompatNative.h>
#include <ftl/enum.h>
#include <gui/SurfaceComposerClient.h>
#include <input/InputDevice.h>
@@ -63,7 +61,6 @@
using android::os::IInputConstants;
using android::os::InputEventInjectionResult;
using android::os::InputEventInjectionSync;
-using com::android::internal::compat::IPlatformCompatNative;
namespace android::inputdispatcher {
@@ -411,15 +408,6 @@
return *lhs == *rhs;
}
-sp<IPlatformCompatNative> getCompatService() {
- sp<IBinder> service(defaultServiceManager()->getService(String16("platform_compat_native")));
- if (service == nullptr) {
- ALOGE("Failed to link to compat service");
- return nullptr;
- }
- return interface_cast<IPlatformCompatNative>(service);
-}
-
KeyEvent createKeyEvent(const KeyEntry& entry) {
KeyEvent event;
event.initialize(entry.id, entry.deviceId, entry.source, entry.displayId, INVALID_HMAC,
@@ -570,8 +558,7 @@
mFocusedDisplayId(ADISPLAY_ID_DEFAULT),
mWindowTokenWithPointerCapture(nullptr),
mLatencyAggregator(),
- mLatencyTracker(&mLatencyAggregator),
- mCompatService(getCompatService()) {
+ mLatencyTracker(&mLatencyAggregator) {
mLooper = new Looper(false);
mReporter = createInputReporter();
@@ -4812,18 +4799,6 @@
ALOGD("Window went away: %s", oldWindowHandle->getName().c_str());
}
oldWindowHandle->releaseChannel();
- // To avoid making too many calls into the compat framework, only
- // check for window flags when windows are going away.
- // TODO(b/157929241) : delete this. This is only needed temporarily
- // in order to gather some data about the flag usage
- if (oldWindowHandle->getInfo()->flags.test(WindowInfo::Flag::SLIPPERY)) {
- ALOGW("%s has FLAG_SLIPPERY. Please report this in b/157929241",
- oldWindowHandle->getName().c_str());
- if (mCompatService != nullptr) {
- mCompatService->reportChangeByUid(IInputConstants::BLOCK_FLAG_SLIPPERY,
- oldWindowHandle->getInfo()->ownerUid);
- }
- }
}
}
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index ee50ec5..cbb7bad 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -36,7 +36,6 @@
#include "TouchedWindow.h"
#include <attestation/HmacKeyManager.h>
-#include <com/android/internal/compat/IPlatformCompatNative.h>
#include <gui/InputApplication.h>
#include <gui/WindowInfo.h>
#include <input/Input.h>
@@ -679,7 +678,6 @@
void traceWaitQueueLength(const Connection& connection);
sp<InputReporterInterface> mReporter;
- sp<com::android::internal::compat::IPlatformCompatNative> mCompatService;
};
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 269bdab..09a62f3 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -1262,12 +1262,11 @@
bool EventHub::setKeyboardLayoutOverlay(int32_t deviceId, std::shared_ptr<KeyCharacterMap> map) {
std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device != nullptr && map != nullptr && device->keyMap.keyCharacterMap != nullptr) {
- device->keyMap.keyCharacterMap->combine(*map);
- device->keyMap.keyCharacterMapFile = device->keyMap.keyCharacterMap->getLoadFileName();
- return true;
+ if (device == nullptr || map == nullptr || device->keyMap.keyCharacterMap == nullptr) {
+ return false;
}
- return false;
+ device->keyMap.keyCharacterMap->combine(*map);
+ return true;
}
static std::string generateDescriptor(InputDeviceIdentifier& identifier) {
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 068e03c..2c5b321 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -2330,6 +2330,17 @@
mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
}
+ void assertReceivedMotion(int32_t action, const std::vector<Point>& points) {
+ NotifyMotionArgs args;
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
+ EXPECT_EQ(action, args.action);
+ ASSERT_EQ(points.size(), args.pointerCount);
+ for (size_t i = 0; i < args.pointerCount; i++) {
+ EXPECT_EQ(points[i].x, args.pointerCoords[i].getX());
+ EXPECT_EQ(points[i].y, args.pointerCoords[i].getY());
+ }
+ }
+
std::unique_ptr<UinputTouchScreen> mDevice;
};
@@ -2340,16 +2351,19 @@
// ACTION_DOWN
mDevice->sendTrackingId(FIRST_TRACKING_ID);
mDevice->sendDown(centerPoint);
+ mDevice->sendSync();
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action);
// ACTION_MOVE
mDevice->sendMove(centerPoint + Point(1, 1));
+ mDevice->sendSync();
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
// ACTION_UP
mDevice->sendUp();
+ mDevice->sendSync();
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action);
}
@@ -2362,6 +2376,7 @@
mDevice->sendSlot(FIRST_SLOT);
mDevice->sendTrackingId(FIRST_TRACKING_ID);
mDevice->sendDown(centerPoint);
+ mDevice->sendSync();
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action);
@@ -2369,27 +2384,129 @@
const Point secondPoint = centerPoint + Point(100, 100);
mDevice->sendSlot(SECOND_SLOT);
mDevice->sendTrackingId(SECOND_TRACKING_ID);
- mDevice->sendDown(secondPoint + Point(1, 1));
+ mDevice->sendDown(secondPoint);
+ mDevice->sendSync();
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
ASSERT_EQ(ACTION_POINTER_1_DOWN, args.action);
// ACTION_MOVE (Second slot)
- mDevice->sendMove(secondPoint);
+ mDevice->sendMove(secondPoint + Point(1, 1));
+ mDevice->sendSync();
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
// ACTION_POINTER_UP (Second slot)
mDevice->sendPointerUp();
+ mDevice->sendSync();
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
ASSERT_EQ(ACTION_POINTER_1_UP, args.action);
// ACTION_UP
mDevice->sendSlot(FIRST_SLOT);
mDevice->sendUp();
+ mDevice->sendSync();
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action);
}
+/**
+ * What happens when a pointer goes up while another pointer moves in the same frame? Are POINTER_UP
+ * events guaranteed to contain the same data as a preceding MOVE, or can they contain different
+ * data?
+ * In this test, we try to send a change in coordinates in Pointer 0 in the same frame as the
+ * liftoff of Pointer 1. We check that POINTER_UP event is generated first, and the MOVE event
+ * for Pointer 0 only is generated after.
+ * Suppose we are only interested in learning the movement of Pointer 0. If we only observe MOVE
+ * events, we will not miss any information.
+ * Even though the Pointer 1 up event contains updated Pointer 0 coordinates, there is another MOVE
+ * event generated afterwards that contains the newest movement of pointer 0.
+ * This is important for palm rejection. If there is a subsequent InputListener stage that detects
+ * palms, and wants to cancel Pointer 1, then it is safe to simply drop POINTER_1_UP event without
+ * losing information about non-palm pointers.
+ */
+TEST_F(TouchIntegrationTest, MultiTouch_PointerMoveAndSecondPointerUp) {
+ NotifyMotionArgs args;
+ const Point centerPoint = mDevice->getCenterPoint();
+
+ // ACTION_DOWN
+ mDevice->sendSlot(FIRST_SLOT);
+ mDevice->sendTrackingId(FIRST_TRACKING_ID);
+ mDevice->sendDown(centerPoint);
+ mDevice->sendSync();
+ assertReceivedMotion(AMOTION_EVENT_ACTION_DOWN, {centerPoint});
+
+ // ACTION_POINTER_DOWN (Second slot)
+ const Point secondPoint = centerPoint + Point(100, 100);
+ mDevice->sendSlot(SECOND_SLOT);
+ mDevice->sendTrackingId(SECOND_TRACKING_ID);
+ mDevice->sendDown(secondPoint);
+ mDevice->sendSync();
+ assertReceivedMotion(ACTION_POINTER_1_DOWN, {centerPoint, secondPoint});
+
+ // ACTION_MOVE (First slot)
+ mDevice->sendSlot(FIRST_SLOT);
+ mDevice->sendMove(centerPoint + Point(5, 5));
+ // ACTION_POINTER_UP (Second slot)
+ mDevice->sendSlot(SECOND_SLOT);
+ mDevice->sendPointerUp();
+ // Send a single sync for the above 2 pointer updates
+ mDevice->sendSync();
+
+ // First, we should get POINTER_UP for the second pointer
+ assertReceivedMotion(ACTION_POINTER_1_UP,
+ {/*first pointer */ centerPoint + Point(5, 5),
+ /*second pointer*/ secondPoint});
+
+ // Next, the MOVE event for the first pointer
+ assertReceivedMotion(AMOTION_EVENT_ACTION_MOVE, {centerPoint + Point(5, 5)});
+}
+
+/**
+ * Similar scenario as above. The difference is that when the second pointer goes up, it will first
+ * move, and then it will go up, all in the same frame.
+ * In this scenario, the movement of the second pointer just prior to liftoff is ignored, and never
+ * gets sent to the listener.
+ */
+TEST_F(TouchIntegrationTest, MultiTouch_PointerMoveAndSecondPointerMoveAndUp) {
+ NotifyMotionArgs args;
+ const Point centerPoint = mDevice->getCenterPoint();
+
+ // ACTION_DOWN
+ mDevice->sendSlot(FIRST_SLOT);
+ mDevice->sendTrackingId(FIRST_TRACKING_ID);
+ mDevice->sendDown(centerPoint);
+ mDevice->sendSync();
+ assertReceivedMotion(AMOTION_EVENT_ACTION_DOWN, {centerPoint});
+
+ // ACTION_POINTER_DOWN (Second slot)
+ const Point secondPoint = centerPoint + Point(100, 100);
+ mDevice->sendSlot(SECOND_SLOT);
+ mDevice->sendTrackingId(SECOND_TRACKING_ID);
+ mDevice->sendDown(secondPoint);
+ mDevice->sendSync();
+ assertReceivedMotion(ACTION_POINTER_1_DOWN, {centerPoint, secondPoint});
+
+ // ACTION_MOVE (First slot)
+ mDevice->sendSlot(FIRST_SLOT);
+ mDevice->sendMove(centerPoint + Point(5, 5));
+ // ACTION_POINTER_UP (Second slot)
+ mDevice->sendSlot(SECOND_SLOT);
+ mDevice->sendMove(secondPoint + Point(6, 6));
+ mDevice->sendPointerUp();
+ // Send a single sync for the above 2 pointer updates
+ mDevice->sendSync();
+
+ // First, we should get POINTER_UP for the second pointer
+ // The movement of the second pointer during the liftoff frame is ignored.
+ // The coordinates 'secondPoint + Point(6, 6)' are never sent to the listener.
+ assertReceivedMotion(ACTION_POINTER_1_UP,
+ {/*first pointer */ centerPoint + Point(5, 5),
+ /*second pointer*/ secondPoint});
+
+ // Next, the MOVE event for the first pointer
+ assertReceivedMotion(AMOTION_EVENT_ACTION_MOVE, {centerPoint + Point(5, 5)});
+}
+
TEST_F(TouchIntegrationTest, InputEvent_ProcessPalm) {
NotifyMotionArgs args;
const Point centerPoint = mDevice->getCenterPoint();
@@ -2398,6 +2515,7 @@
mDevice->sendSlot(FIRST_SLOT);
mDevice->sendTrackingId(FIRST_TRACKING_ID);
mDevice->sendDown(centerPoint);
+ mDevice->sendSync();
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action);
@@ -2406,11 +2524,13 @@
mDevice->sendSlot(SECOND_SLOT);
mDevice->sendTrackingId(SECOND_TRACKING_ID);
mDevice->sendDown(secondPoint);
+ mDevice->sendSync();
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
ASSERT_EQ(ACTION_POINTER_1_DOWN, args.action);
// ACTION_MOVE (second slot)
mDevice->sendMove(secondPoint + Point(1, 1));
+ mDevice->sendSync();
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
@@ -2418,18 +2538,21 @@
// a palm event.
// Expect to receive the ACTION_POINTER_UP with cancel flag.
mDevice->sendToolType(MT_TOOL_PALM);
+ mDevice->sendSync();
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
ASSERT_EQ(ACTION_POINTER_1_UP, args.action);
ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, args.flags);
// Send up to second slot, expect first slot send moving.
mDevice->sendPointerUp();
+ mDevice->sendSync();
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
// Send ACTION_UP (first slot)
mDevice->sendSlot(FIRST_SLOT);
mDevice->sendUp();
+ mDevice->sendSync();
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action);
diff --git a/services/inputflinger/tests/UinputDevice.cpp b/services/inputflinger/tests/UinputDevice.cpp
index 7fec2c8..132b877 100644
--- a/services/inputflinger/tests/UinputDevice.cpp
+++ b/services/inputflinger/tests/UinputDevice.cpp
@@ -170,28 +170,27 @@
injectEvent(EV_KEY, BTN_TOUCH, 1);
injectEvent(EV_ABS, ABS_MT_POSITION_X, point.x);
injectEvent(EV_ABS, ABS_MT_POSITION_Y, point.y);
- injectEvent(EV_SYN, SYN_REPORT, 0);
}
void UinputTouchScreen::sendMove(const Point& point) {
injectEvent(EV_ABS, ABS_MT_POSITION_X, point.x);
injectEvent(EV_ABS, ABS_MT_POSITION_Y, point.y);
- injectEvent(EV_SYN, SYN_REPORT, 0);
}
void UinputTouchScreen::sendPointerUp() {
sendTrackingId(0xffffffff);
- injectEvent(EV_SYN, SYN_REPORT, 0);
}
void UinputTouchScreen::sendUp() {
sendTrackingId(0xffffffff);
injectEvent(EV_KEY, BTN_TOUCH, 0);
- injectEvent(EV_SYN, SYN_REPORT, 0);
}
void UinputTouchScreen::sendToolType(int32_t toolType) {
injectEvent(EV_ABS, ABS_MT_TOOL_TYPE, toolType);
+}
+
+void UinputTouchScreen::sendSync() {
injectEvent(EV_SYN, SYN_REPORT, 0);
}
diff --git a/services/inputflinger/tests/UinputDevice.h b/services/inputflinger/tests/UinputDevice.h
index 01a557c..a37fc2b 100644
--- a/services/inputflinger/tests/UinputDevice.h
+++ b/services/inputflinger/tests/UinputDevice.h
@@ -142,6 +142,7 @@
void sendPointerUp();
void sendUp();
void sendToolType(int32_t toolType);
+ void sendSync();
const Point getCenterPoint();
diff --git a/services/sensorservice/AidlSensorHalWrapper.cpp b/services/sensorservice/AidlSensorHalWrapper.cpp
index 74c47ba..049d06a 100644
--- a/services/sensorservice/AidlSensorHalWrapper.cpp
+++ b/services/sensorservice/AidlSensorHalWrapper.cpp
@@ -214,13 +214,27 @@
dstInfo->type = (int32_t)srcInfo.type;
dstInfo->serial = srcInfo.serial;
- // TODO(b/195593357): Finish additional info conversion
- // CHECK_EQ(sizeof(srcInfo.payload.values), sizeof(dstInfo->data_int32));
-
- // memcpy(dstInfo->data_int32,
- // &srcInfo.u,
- // sizeof(dstInfo->data_int32));
-
+ switch (srcInfo.payload.getTag()) {
+ case AdditionalInfo::AdditionalInfoPayload::Tag::dataInt32: {
+ const auto &values =
+ srcInfo.payload.get<AdditionalInfo::AdditionalInfoPayload::dataInt32>()
+ .values;
+ CHECK_EQ(values.size() * sizeof(int32_t), sizeof(dstInfo->data_int32));
+ memcpy(dstInfo->data_int32, values.data(), sizeof(dstInfo->data_int32));
+ break;
+ }
+ case AdditionalInfo::AdditionalInfoPayload::Tag::dataFloat: {
+ const auto &values =
+ srcInfo.payload.get<AdditionalInfo::AdditionalInfoPayload::dataFloat>()
+ .values;
+ CHECK_EQ(values.size() * sizeof(float), sizeof(dstInfo->data_float));
+ memcpy(dstInfo->data_float, values.data(), sizeof(dstInfo->data_float));
+ break;
+ }
+ default: {
+ ALOGE("Invalid sensor additional info tag: %d", srcInfo.payload.getTag());
+ }
+ }
break;
}
@@ -238,6 +252,7 @@
*dst = {
.timestamp = src.timestamp,
.sensorHandle = src.sensor,
+ .sensorType = (SensorType) src.type,
};
switch (dst->sensorType) {
@@ -359,7 +374,10 @@
info.type = (AdditionalInfo::AdditionalInfoType)srcInfo.type;
info.serial = srcInfo.serial;
- // TODO(b/195593357): Finish additional info conversion
+ AdditionalInfo::AdditionalInfoPayload::Int32Values data;
+ CHECK_EQ(data.values.size() * sizeof(int32_t), sizeof(srcInfo.data_int32));
+ memcpy(data.values.data(), srcInfo.data_int32, sizeof(srcInfo.data_int32));
+ info.payload.set<AdditionalInfo::AdditionalInfoPayload::Tag::dataInt32>(data);
dst->payload.set<Event::EventPayload::Tag::additional>(info);
break;
@@ -445,7 +463,6 @@
ndk::SpAIBinder binder(AServiceManager_waitForService(aidlServiceName.c_str()));
if (binder.get() != nullptr) {
-
mSensors = ISensors::fromBinder(binder);
mEventQueue = std::make_unique<AidlMessageQueue<
Event, SynchronizedReadWrite>>(MAX_RECEIVE_BUFFER_EVENT_COUNT,
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 9bc7b8e..517d383 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -1254,6 +1254,11 @@
for (auto &sensor : sensorList) {
int32_t id = getIdFromUuid(sensor.getUuid());
sensor.setId(id);
+ // The sensor UUID must always be anonymized here for non privileged clients.
+ // There is no other checks after this point before returning to client process.
+ if (!isAudioServerOrSystemServerUid(IPCThreadState::self()->getCallingUid())) {
+ sensor.anonymizeUuid();
+ }
}
}
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 9b6d01a..b009829 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -26,6 +26,7 @@
#include <binder/IUidObserver.h>
#include <cutils/compiler.h>
#include <cutils/multiuser.h>
+#include <private/android_filesystem_config.h>
#include <sensor/ISensorServer.h>
#include <sensor/ISensorEventConnection.h>
#include <sensor/Sensor.h>
@@ -447,6 +448,10 @@
// Removes the capped rate on active direct connections (when the mic toggle is flipped to off)
void uncapRates(userid_t userId);
+ static inline bool isAudioServerOrSystemServerUid(uid_t uid) {
+ return multiuser_get_app_id(uid) == AID_SYSTEM || uid == AID_AUDIOSERVER;
+ }
+
static uint8_t sHmacGlobalKey[128];
static bool sHmacGlobalKeyIsValid;
diff --git a/services/sensorservice/SensorServiceUtils.cpp b/services/sensorservice/SensorServiceUtils.cpp
index fdd56b3..baa01c9 100644
--- a/services/sensorservice/SensorServiceUtils.cpp
+++ b/services/sensorservice/SensorServiceUtils.cpp
@@ -58,6 +58,9 @@
case SENSOR_TYPE_HINGE_ANGLE:
return 1;
+ case SENSOR_TYPE_HEAD_TRACKER:
+ return 7;
+
default:
return 3;
}
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 5560ed7..9f40849 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -125,10 +125,7 @@
thin: true,
},
whole_program_vtables: true, // Requires ThinLTO
- pgo: {
- sampling: true,
- profile_file: "surfaceflinger/surfaceflinger.profdata",
- },
+ afdo: true,
// TODO(b/131771163): Fix broken fuzzer support with LTO.
sanitize: {
fuzzer: false,
@@ -192,8 +189,6 @@
"Scheduler/MessageQueue.cpp",
"Scheduler/RefreshRateConfigs.cpp",
"Scheduler/Scheduler.cpp",
- "Scheduler/SchedulerUtils.cpp",
- "Scheduler/Timer.cpp",
"Scheduler/VSyncDispatchTimerQueue.cpp",
"Scheduler/VSyncPredictor.cpp",
"Scheduler/VSyncReactor.cpp",
@@ -231,7 +226,6 @@
"libcutils",
"libdisplayservicehidl",
"libhidlbase",
- "liblayers_proto",
"liblog",
"libprocessgroup",
"libsync",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index d61a4cb..e797b5d 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -164,7 +164,7 @@
const bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) ||
((isSecure() || isProtected()) && !targetSettings.isSecure);
const bool bufferCanBeUsedAsHwTexture =
- mBufferInfo.mBuffer->getBuffer()->getUsage() & GraphicBuffer::USAGE_HW_TEXTURE;
+ mBufferInfo.mBuffer->getUsage() & GraphicBuffer::USAGE_HW_TEXTURE;
compositionengine::LayerFE::LayerSettings& layer = *result;
if (blackOutLayer || !bufferCanBeUsedAsHwTexture) {
ALOGE_IF(!bufferCanBeUsedAsHwTexture, "%s is blacked out as buffer is not gpu readable",
@@ -201,7 +201,7 @@
}
layer.source.buffer.maxLuminanceNits = maxLuminance;
layer.frameNumber = mCurrentFrameNumber;
- layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer()->getId() : 0;
+ layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0;
const bool useFiltering =
targetSettings.needsFiltering || mNeedsFiltering || bufferNeedsFiltering();
@@ -436,7 +436,7 @@
void BufferLayer::gatherBufferInfo() {
mBufferInfo.mPixelFormat =
- !mBufferInfo.mBuffer ? PIXEL_FORMAT_NONE : mBufferInfo.mBuffer->getBuffer()->format;
+ !mBufferInfo.mBuffer ? PIXEL_FORMAT_NONE : mBufferInfo.mBuffer->getPixelFormat();
mBufferInfo.mFrameLatencyNeeded = true;
}
@@ -533,10 +533,10 @@
}
if (oldBufferInfo.mBuffer != nullptr) {
- uint32_t bufWidth = mBufferInfo.mBuffer->getBuffer()->getWidth();
- uint32_t bufHeight = mBufferInfo.mBuffer->getBuffer()->getHeight();
- if (bufWidth != uint32_t(oldBufferInfo.mBuffer->getBuffer()->width) ||
- bufHeight != uint32_t(oldBufferInfo.mBuffer->getBuffer()->height)) {
+ uint32_t bufWidth = mBufferInfo.mBuffer->getWidth();
+ uint32_t bufHeight = mBufferInfo.mBuffer->getHeight();
+ if (bufWidth != oldBufferInfo.mBuffer->getWidth() ||
+ bufHeight != oldBufferInfo.mBuffer->getHeight()) {
recomputeVisibleRegions = true;
}
}
@@ -558,7 +558,7 @@
bool BufferLayer::isProtected() const {
return (mBufferInfo.mBuffer != nullptr) &&
- (mBufferInfo.mBuffer->getBuffer()->getUsage() & GRALLOC_USAGE_PROTECTED);
+ (mBufferInfo.mBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
}
// As documented in libhardware header, formats in the range
@@ -638,8 +638,8 @@
return Rect::INVALID_RECT;
}
- uint32_t bufWidth = mBufferInfo.mBuffer->getBuffer()->getWidth();
- uint32_t bufHeight = mBufferInfo.mBuffer->getBuffer()->getHeight();
+ uint32_t bufWidth = mBufferInfo.mBuffer->getWidth();
+ uint32_t bufHeight = mBufferInfo.mBuffer->getHeight();
// Undo any transformations on the buffer and return the result.
if (mBufferInfo.mTransform & ui::Transform::ROT_90) {
@@ -670,8 +670,8 @@
return parentBounds;
}
- uint32_t bufWidth = mBufferInfo.mBuffer->getBuffer()->getWidth();
- uint32_t bufHeight = mBufferInfo.mBuffer->getBuffer()->getHeight();
+ uint32_t bufWidth = mBufferInfo.mBuffer->getWidth();
+ uint32_t bufHeight = mBufferInfo.mBuffer->getHeight();
// Undo any transformations on the buffer and return the result.
if (mBufferInfo.mTransform & ui::Transform::ROT_90) {
@@ -713,7 +713,7 @@
return mBufferInfo.mCrop;
} else if (mBufferInfo.mBuffer != nullptr) {
// otherwise we use the whole buffer
- return mBufferInfo.mBuffer->getBuffer()->getBounds();
+ return mBufferInfo.mBuffer->getBounds();
} else {
// if we don't have a buffer yet, we use an empty/invalid crop
return Rect();
@@ -820,6 +820,10 @@
return isFixedSize();
}
+const std::shared_ptr<renderengine::ExternalTexture>& BufferLayer::getExternalTexture() const {
+ return mBufferInfo.mBuffer;
+}
+
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 34d11ac..99267be 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -111,6 +111,7 @@
ui::Dataspace getDataSpace() const override;
sp<GraphicBuffer> getBuffer() const override;
+ const std::shared_ptr<renderengine::ExternalTexture>& getExternalTexture() const override;
ui::Transform::RotationFlags getTransformHint() const override { return mTransformHint; }
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index c79fa11..9ae45fc 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -41,6 +41,7 @@
#include <gui/SurfaceComposerClient.h>
#include <private/gui/ComposerService.h>
#include <renderengine/RenderEngine.h>
+#include <renderengine/impl/ExternalTexture.h>
#include <utils/Log.h>
#include <utils/String8.h>
#include <utils/Trace.h>
@@ -208,8 +209,9 @@
if (mImages[item->mSlot] == nullptr || mImages[item->mSlot]->getBuffer() == nullptr ||
mImages[item->mSlot]->getBuffer()->getId() != item->mGraphicBuffer->getId()) {
mImages[item->mSlot] = std::make_shared<
- renderengine::ExternalTexture>(item->mGraphicBuffer, mRE,
- renderengine::ExternalTexture::Usage::READABLE);
+ renderengine::impl::ExternalTexture>(item->mGraphicBuffer, mRE,
+ renderengine::impl::ExternalTexture::
+ Usage::READABLE);
}
}
@@ -462,8 +464,9 @@
if (oldImage == nullptr || oldImage->getBuffer() == nullptr ||
oldImage->getBuffer()->getId() != item.mGraphicBuffer->getId()) {
mImages[item.mSlot] = std::make_shared<
- renderengine::ExternalTexture>(item.mGraphicBuffer, mRE,
- renderengine::ExternalTexture::Usage::READABLE);
+ renderengine::impl::ExternalTexture>(item.mGraphicBuffer, mRE,
+ renderengine::impl::ExternalTexture::
+ Usage::READABLE);
}
}
}
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 2fac880..0c93872 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -295,8 +295,8 @@
return assignTransform(&mDrawingState.transform, t);
}
- uint32_t bufferWidth = mDrawingState.buffer->getBuffer()->getWidth();
- uint32_t bufferHeight = mDrawingState.buffer->getBuffer()->getHeight();
+ uint32_t bufferWidth = mDrawingState.buffer->getWidth();
+ uint32_t bufferHeight = mDrawingState.buffer->getHeight();
// Undo any transformations on the buffer.
if (mDrawingState.bufferTransform & ui::Transform::ROT_90) {
std::swap(bufferWidth, bufferHeight);
@@ -368,46 +368,13 @@
return true;
}
-std::shared_ptr<renderengine::ExternalTexture> BufferStateLayer::getBufferFromBufferData(
- const BufferData& bufferData) {
- bool cacheIdChanged = bufferData.flags.test(BufferData::BufferDataChange::cachedBufferChanged);
- bool bufferSizeExceedsLimit = false;
- std::shared_ptr<renderengine::ExternalTexture> buffer = nullptr;
- if (cacheIdChanged && bufferData.buffer != nullptr) {
- bufferSizeExceedsLimit =
- mFlinger->exceedsMaxRenderTargetSize(bufferData.buffer->getWidth(),
- bufferData.buffer->getHeight());
- if (!bufferSizeExceedsLimit) {
- ClientCache::getInstance().add(bufferData.cachedBuffer, bufferData.buffer);
- buffer = ClientCache::getInstance().get(bufferData.cachedBuffer);
- }
- } else if (cacheIdChanged) {
- buffer = ClientCache::getInstance().get(bufferData.cachedBuffer);
- } else if (bufferData.buffer != nullptr) {
- bufferSizeExceedsLimit =
- mFlinger->exceedsMaxRenderTargetSize(bufferData.buffer->getWidth(),
- bufferData.buffer->getHeight());
- if (!bufferSizeExceedsLimit) {
- buffer = std::make_shared<
- renderengine::ExternalTexture>(bufferData.buffer, mFlinger->getRenderEngine(),
- renderengine::ExternalTexture::Usage::READABLE);
- }
- }
- ALOGE_IF(bufferSizeExceedsLimit,
- "Attempted to create an ExternalTexture for layer %s that exceeds render target size "
- "limit.",
- getDebugName());
- return buffer;
-}
-
-bool BufferStateLayer::setBuffer(const BufferData& bufferData, nsecs_t postTime,
+bool BufferStateLayer::setBuffer(std::shared_ptr<renderengine::ExternalTexture>& buffer,
+ const BufferData& bufferData, nsecs_t postTime,
nsecs_t desiredPresentTime, bool isAutoTimestamp,
std::optional<nsecs_t> dequeueTime,
const FrameTimelineInfo& info) {
ATRACE_CALL();
- const std::shared_ptr<renderengine::ExternalTexture>& buffer =
- getBufferFromBufferData(bufferData);
if (!buffer) {
return false;
}
@@ -419,8 +386,9 @@
if (mDrawingState.buffer) {
mReleasePreviousBuffer = true;
- if (mDrawingState.buffer != mBufferInfo.mBuffer ||
- mDrawingState.frameNumber != mBufferInfo.mFrameNumber) {
+ if (!mBufferInfo.mBuffer ||
+ (!mDrawingState.buffer->hasSameBuffer(*mBufferInfo.mBuffer) ||
+ mDrawingState.frameNumber != mBufferInfo.mFrameNumber)) {
// If mDrawingState has a buffer, and we are about to update again
// before swapping to drawing state, then the first buffer will be
// dropped and we should decrement the pending buffer count and
@@ -448,7 +416,7 @@
mDrawingState.frameNumber = frameNumber;
mDrawingState.releaseBufferListener = bufferData.releaseBufferListener;
- mDrawingState.buffer = buffer;
+ mDrawingState.buffer = std::move(buffer);
mDrawingState.clientCacheId = bufferData.cachedBuffer;
mDrawingState.acquireFence = bufferData.flags.test(BufferData::BufferDataChange::fenceChanged)
@@ -484,8 +452,8 @@
setFrameTimelineVsyncForBufferTransaction(info, postTime);
- if (buffer && dequeueTime && *dequeueTime != 0) {
- const uint64_t bufferId = buffer->getBuffer()->getId();
+ if (dequeueTime && *dequeueTime != 0) {
+ const uint64_t bufferId = mDrawingState.buffer->getId();
mFlinger->mFrameTracer->traceNewLayer(layerId, getName().c_str());
mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, *dequeueTime,
FrameTracer::FrameEvent::DEQUEUE);
@@ -493,8 +461,8 @@
FrameTracer::FrameEvent::QUEUE);
}
- mDrawingState.width = mDrawingState.buffer->getBuffer()->getWidth();
- mDrawingState.height = mDrawingState.buffer->getBuffer()->getHeight();
+ mDrawingState.width = mDrawingState.buffer->getWidth();
+ mDrawingState.height = mDrawingState.buffer->getHeight();
mDrawingState.releaseBufferEndpoint = bufferData.releaseBufferEndpoint;
return true;
}
@@ -599,8 +567,8 @@
return Rect::INVALID_RECT;
}
- uint32_t bufWidth = mBufferInfo.mBuffer->getBuffer()->getWidth();
- uint32_t bufHeight = mBufferInfo.mBuffer->getBuffer()->getHeight();
+ uint32_t bufWidth = mBufferInfo.mBuffer->getWidth();
+ uint32_t bufHeight = mBufferInfo.mBuffer->getHeight();
// Undo any transformations on the buffer and return the result.
if (mBufferInfo.mTransform & ui::Transform::ROT_90) {
@@ -709,7 +677,7 @@
}
const int32_t layerId = getSequence();
- const uint64_t bufferId = mDrawingState.buffer->getBuffer()->getId();
+ const uint64_t bufferId = mDrawingState.buffer->getId();
const uint64_t frameNumber = mDrawingState.frameNumber;
const auto acquireFence = std::make_shared<FenceTime>(mDrawingState.acquireFence);
mFlinger->mTimeStats->setAcquireFence(layerId, frameNumber, acquireFence);
@@ -749,7 +717,7 @@
return BAD_VALUE;
}
- if (!mBufferInfo.mBuffer || s.buffer->getBuffer() != mBufferInfo.mBuffer->getBuffer()) {
+ if (!mBufferInfo.mBuffer || !s.buffer->hasSameBuffer(*mBufferInfo.mBuffer)) {
decrementPendingBufferCount();
}
@@ -874,10 +842,10 @@
Rect BufferStateLayer::computeBufferCrop(const State& s) {
if (s.buffer && !s.bufferCrop.isEmpty()) {
Rect bufferCrop;
- s.buffer->getBuffer()->getBounds().intersect(s.bufferCrop, &bufferCrop);
+ s.buffer->getBounds().intersect(s.bufferCrop, &bufferCrop);
return bufferCrop;
} else if (s.buffer) {
- return s.buffer->getBuffer()->getBounds();
+ return s.buffer->getBounds();
} else {
return s.bufferCrop;
}
@@ -898,8 +866,8 @@
return false;
}
- int32_t bufferWidth = s.buffer->getBuffer()->width;
- int32_t bufferHeight = s.buffer->getBuffer()->height;
+ int32_t bufferWidth = static_cast<int32_t>(s.buffer->getWidth());
+ int32_t bufferHeight = static_cast<int32_t>(s.buffer->getHeight());
// Undo any transformations on the buffer and return the result.
if (s.bufferTransform & ui::Transform::ROT_90) {
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index eea700c..2f613d7 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -57,7 +57,8 @@
bool setTransform(uint32_t transform) override;
bool setTransformToDisplayInverse(bool transformToDisplayInverse) override;
bool setCrop(const Rect& crop) override;
- bool setBuffer(const BufferData& bufferData, nsecs_t postTime, nsecs_t desiredPresentTime,
+ bool setBuffer(std::shared_ptr<renderengine::ExternalTexture>& /* buffer */,
+ const BufferData& bufferData, nsecs_t postTime, nsecs_t desiredPresentTime,
bool isAutoTimestamp, std::optional<nsecs_t> dequeueTime,
const FrameTimelineInfo& info) override;
bool setDataspace(ui::Dataspace dataspace) override;
@@ -136,9 +137,6 @@
bool bufferNeedsFiltering() const override;
- std::shared_ptr<renderengine::ExternalTexture> getBufferFromBufferData(
- const BufferData& bufferData);
-
ReleaseCallbackId mPreviousReleaseCallbackId = ReleaseCallbackId::INVALID_ID;
uint64_t mPreviousReleasedFrameNumber = 0;
diff --git a/services/surfaceflinger/ClientCache.cpp b/services/surfaceflinger/ClientCache.cpp
index e7b8995..3c7b9d9 100644
--- a/services/surfaceflinger/ClientCache.cpp
+++ b/services/surfaceflinger/ClientCache.cpp
@@ -22,6 +22,7 @@
#include <cinttypes>
#include <android-base/stringprintf.h>
+#include <renderengine/impl/ExternalTexture.h>
#include "ClientCache.h"
@@ -109,8 +110,9 @@
"Attempted to build the ClientCache before a RenderEngine instance was "
"ready!");
processBuffers[id].buffer = std::make_shared<
- renderengine::ExternalTexture>(buffer, *mRenderEngine,
- renderengine::ExternalTexture::Usage::READABLE);
+ renderengine::impl::ExternalTexture>(buffer, *mRenderEngine,
+ renderengine::impl::ExternalTexture::Usage::
+ READABLE);
return true;
}
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 73770b7..6cb12dd 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -173,6 +173,8 @@
// Sets the projection state to use
virtual void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
const Rect& orientedDisplaySpaceRect) = 0;
+ // Sets the brightness that will take effect next frame.
+ virtual void setNextBrightness(float brightness) = 0;
// Sets the bounds to use
virtual void setDisplaySize(const ui::Size&) = 0;
// Gets the transform hint used in layers that belong to this output. Used to guide
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 844876a..a7a8e97 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -45,6 +45,7 @@
void setLayerCachingTexturePoolEnabled(bool) override;
void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
const Rect& orientedDisplaySpaceRect) override;
+ void setNextBrightness(float brightness) override;
void setDisplaySize(const ui::Size&) override;
void setLayerFilter(ui::LayerFilter) override;
ui::Transform::RotationFlags getTransformHint() const override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index c8f177b..cc7c257 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -133,6 +133,10 @@
// White point of the client target
float clientTargetWhitePointNits{-1.f};
+ // Display brightness that will take effect this frame.
+ // This is slightly distinct from nits, in that nits cannot be passed to hw composer.
+ std::optional<float> displayBrightness = std::nullopt;
+
// Debugging
void dump(std::string& result) const;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 7b0d028..b68b95d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -39,6 +39,7 @@
MOCK_METHOD1(setLayerCachingEnabled, void(bool));
MOCK_METHOD1(setLayerCachingTexturePoolEnabled, void(bool));
MOCK_METHOD3(setProjection, void(ui::Rotation, const Rect&, const Rect&));
+ MOCK_METHOD1(setNextBrightness, void(float));
MOCK_METHOD1(setDisplaySize, void(const ui::Size&));
MOCK_CONST_METHOD0(getTransformHint, ui::Transform::RotationFlags());
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 08dd22d..186e191 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -226,6 +226,17 @@
// Get any composition changes requested by the HWC device, and apply them.
std::optional<android::HWComposer::DeviceRequestedChanges> changes;
auto& hwc = getCompositionEngine().getHwComposer();
+ if (const auto physicalDisplayId = PhysicalDisplayId::tryCast(*halDisplayId);
+ physicalDisplayId && getState().displayBrightness) {
+ const status_t result =
+ hwc.setDisplayBrightness(*physicalDisplayId, *getState().displayBrightness,
+ Hwc2::Composer::DisplayBrightnessOptions{
+ .applyImmediately = false})
+ .get();
+ ALOGE_IF(result != NO_ERROR, "setDisplayBrightness failed for %s: %d, (%s)",
+ getName().c_str(), result, strerror(-result));
+ }
+
if (status_t result =
hwc.getDeviceCompositionChanges(*halDisplayId, anyLayersRequireClientComposition(),
getState().earliestPresentTime,
@@ -248,6 +259,8 @@
auto& state = editState();
state.usesClientComposition = anyLayersRequireClientComposition();
state.usesDeviceComposition = !allLayersRequireClientComposition();
+ // Clear out the display brightness now that it's been communicated to composer.
+ state.displayBrightness.reset();
}
bool Display::getSkipColorTransform() const {
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 6833584..192ee04 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -197,6 +197,10 @@
dirtyEntireOutput();
}
+void Output::setNextBrightness(float brightness) {
+ editState().displayBrightness = brightness;
+}
+
void Output::setDisplaySize(const ui::Size& size) {
mRenderSurface->setDisplaySize(size);
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 545e2a2..95cc5a8 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -481,7 +481,7 @@
if (auto error = hwcLayer->setVisibleRegion(visibleRegion); error != hal::Error::NONE) {
ALOGE("[%s] Failed to set visible region: %s (%d)", getLayerFE().getDebugName(),
to_string(error).c_str(), static_cast<int32_t>(error));
- outputDependentState.outputSpaceVisibleRegion.dump(LOG_TAG);
+ visibleRegion.dump(LOG_TAG);
}
const auto dataspace = outputDependentState.overrideInfo.buffer
@@ -551,10 +551,10 @@
void OutputLayer::writeSolidColorStateToHWC(HWC2::Layer* hwcLayer,
const LayerFECompositionState& outputIndependentState) {
- 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)),
- 255};
+ aidl::android::hardware::graphics::composer3::Color color = {outputIndependentState.color.r,
+ outputIndependentState.color.g,
+ outputIndependentState.color.b,
+ 1.0f};
if (auto error = hwcLayer->setColor(color); error != hal::Error::NONE) {
ALOGE("[%s] Failed to set color: %s (%d)", getLayerFE().getDebugName(),
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index a19d23f..12c2c8e 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -28,6 +28,7 @@
#include <log/log.h>
#include <renderengine/ExternalTexture.h>
#include <renderengine/RenderEngine.h>
+#include <renderengine/impl/ExternalTexture.h>
#include <system/window.h>
#include <ui/GraphicBuffer.h>
#include <ui/Rect.h>
@@ -182,9 +183,10 @@
mTexture = texture;
} else {
mTexture = std::make_shared<
- renderengine::ExternalTexture>(GraphicBuffer::from(buffer),
- mCompositionEngine.getRenderEngine(),
- renderengine::ExternalTexture::Usage::WRITEABLE);
+ renderengine::impl::ExternalTexture>(GraphicBuffer::from(buffer),
+ mCompositionEngine.getRenderEngine(),
+ renderengine::impl::ExternalTexture::Usage::
+ WRITEABLE);
}
mTextureCache.push_back(mTexture);
if (mTextureCache.size() > mMaxTextureCacheSize) {
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp b/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp
index 497c433..54ecb56 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp
@@ -20,6 +20,7 @@
#define LOG_TAG "Planner"
#include <compositionengine/impl/planner/TexturePool.h>
+#include <renderengine/impl/ExternalTexture.h>
#include <utils/Log.h>
namespace android::compositionengine::impl::planner {
@@ -82,16 +83,19 @@
std::shared_ptr<renderengine::ExternalTexture> TexturePool::genTexture() {
LOG_ALWAYS_FATAL_IF(!mSize.isValid(), "Attempted to generate texture with invalid size");
return std::make_shared<
- renderengine::ExternalTexture>(sp<GraphicBuffer>::
- make(mSize.getWidth(), mSize.getHeight(),
- HAL_PIXEL_FORMAT_RGBA_8888, 1,
- GraphicBuffer::USAGE_HW_RENDER |
- GraphicBuffer::USAGE_HW_COMPOSER |
- GraphicBuffer::USAGE_HW_TEXTURE,
- "Planner"),
- mRenderEngine,
- renderengine::ExternalTexture::Usage::READABLE |
- renderengine::ExternalTexture::Usage::WRITEABLE);
+ renderengine::impl::
+ ExternalTexture>(sp<GraphicBuffer>::
+ make(static_cast<uint32_t>(mSize.getWidth()),
+ static_cast<uint32_t>(mSize.getHeight()),
+ HAL_PIXEL_FORMAT_RGBA_8888, 1U,
+ static_cast<uint64_t>(
+ GraphicBuffer::USAGE_HW_RENDER |
+ GraphicBuffer::USAGE_HW_COMPOSER |
+ GraphicBuffer::USAGE_HW_TEXTURE),
+ "Planner"),
+ mRenderEngine,
+ renderengine::impl::ExternalTexture::Usage::READABLE |
+ renderengine::impl::ExternalTexture::Usage::WRITEABLE);
}
void TexturePool::setEnabled(bool enabled) {
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 8558a80..7dd4c21 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -37,6 +37,7 @@
#include "MockHWC2.h"
#include "MockHWComposer.h"
#include "MockPowerAdvisor.h"
+#include "ftl/future.h"
#include <aidl/android/hardware/graphics/composer3/Composition.h>
@@ -48,6 +49,7 @@
namespace hal = android::hardware::graphics::composer::hal;
using testing::_;
+using testing::ByMove;
using testing::DoAll;
using testing::Eq;
using testing::InSequence;
@@ -594,6 +596,38 @@
EXPECT_TRUE(state.usesDeviceComposition);
}
+TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithDisplayBrightness) {
+ // Since two calls are made to anyLayersRequireClientComposition with different return
+ // values, use a Sequence to control the matching so the values are returned in a known
+ // order.
+ constexpr float kDisplayBrightness = 0.5f;
+ Sequence s;
+ EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition())
+ .InSequence(s)
+ .WillOnce(Return(true));
+ EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition())
+ .InSequence(s)
+ .WillOnce(Return(false));
+ EXPECT_CALL(mHwComposer,
+ setDisplayBrightness(DEFAULT_DISPLAY_ID, kDisplayBrightness,
+ Hwc2::Composer::DisplayBrightnessOptions{.applyImmediately =
+ false}))
+ .WillOnce(Return(ByMove(ftl::yield<status_t>(NO_ERROR))));
+
+ EXPECT_CALL(mHwComposer,
+ getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _))
+ .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false));
+
+ mDisplay->setNextBrightness(kDisplayBrightness);
+ mDisplay->chooseCompositionStrategy();
+
+ auto& state = mDisplay->getState();
+ EXPECT_FALSE(state.usesClientComposition);
+ EXPECT_TRUE(state.usesDeviceComposition);
+ EXPECT_FALSE(state.displayBrightness.has_value());
+}
+
TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) {
android::HWComposer::DeviceRequestedChanges changes{
{{nullptr, Composition::CLIENT}},
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
index ff68053..5185ea9 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
@@ -58,7 +58,7 @@
const android::sp<android::Fence>&));
MOCK_METHOD1(setSurfaceDamage, Error(const android::Region&));
MOCK_METHOD1(setBlendMode, Error(hal::BlendMode));
- MOCK_METHOD1(setColor, Error(hal::Color));
+ MOCK_METHOD1(setColor, Error(aidl::android::hardware::graphics::composer3::Color));
MOCK_METHOD1(setCompositionType,
Error(aidl::android::hardware::graphics::composer3::Composition));
MOCK_METHOD1(setDataspace, Error(android::ui::Dataspace));
@@ -75,6 +75,7 @@
MOCK_METHOD3(setLayerGenericMetadata,
Error(const std::string&, bool, const std::vector<uint8_t>&));
MOCK_METHOD1(setWhitePointNits, Error(float));
+ MOCK_METHOD1(setBlockingRegion, Error(const android::Region&));
};
} // namespace mock
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index a590e2a..bd3022b 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -83,7 +83,9 @@
MOCK_METHOD4(setDisplayContentSamplingEnabled, status_t(HalDisplayId, bool, uint8_t, uint64_t));
MOCK_METHOD4(getDisplayedContentSample,
status_t(HalDisplayId, uint64_t, uint64_t, DisplayedFrameStats*));
- MOCK_METHOD2(setDisplayBrightness, std::future<status_t>(PhysicalDisplayId, float));
+ MOCK_METHOD3(setDisplayBrightness,
+ std::future<status_t>(PhysicalDisplayId, float,
+ const Hwc2::Composer::DisplayBrightnessOptions&));
MOCK_METHOD2(getDisplayBrightnessSupport, status_t(PhysicalDisplayId, bool*));
MOCK_METHOD2(onHotplug,
@@ -104,6 +106,9 @@
status_t(PhysicalDisplayId, hal::HWConfigId,
const hal::VsyncPeriodChangeConstraints&,
hal::VsyncPeriodChangeTimeline*));
+ MOCK_METHOD2(setBootDisplayMode, status_t(PhysicalDisplayId, hal::HWConfigId));
+ MOCK_METHOD1(clearBootDisplayMode, status_t(PhysicalDisplayId));
+ MOCK_METHOD1(getPreferredBootDisplayMode, hal::HWConfigId(PhysicalDisplayId));
MOCK_METHOD2(setAutoLowLatencyMode, status_t(PhysicalDisplayId, bool));
MOCK_METHOD2(getSupportedContentTypes,
status_t(PhysicalDisplayId, std::vector<hal::ContentType>*));
@@ -122,6 +127,7 @@
(const, override));
MOCK_METHOD(std::optional<hal::HWDisplayId>, fromPhysicalDisplayId, (PhysicalDisplayId),
(const, override));
+ MOCK_METHOD(bool, getBootDisplayModeSupport, (), (override));
};
} // namespace mock
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
index db4151b..50adcfb 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
@@ -39,11 +39,10 @@
MOCK_METHOD(bool, supportsPowerHintSession, (), (override));
MOCK_METHOD(bool, isPowerHintSessionRunning, (), (override));
MOCK_METHOD(void, setTargetWorkDuration, (int64_t targetDurationNanos), (override));
- MOCK_METHOD(void, setPowerHintSessionThreadIds, (const std::vector<int32_t>& threadIds),
- (override));
MOCK_METHOD(void, sendActualWorkDuration, (int64_t actualDurationNanos, nsecs_t timestamp),
(override));
MOCK_METHOD(void, enablePowerHint, (bool enabled), (override));
+ MOCK_METHOD(bool, startPowerHintSession, (const std::vector<int32_t>& threadIds), (override));
};
} // namespace mock
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index ad7976f..132ac02 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -24,6 +24,7 @@
#include <gtest/gtest.h>
#include <log/log.h>
+#include <renderengine/impl/ExternalTexture.h>
#include <renderengine/mock/RenderEngine.h>
#include <ui/PixelFormat.h>
#include "MockHWC2.h"
@@ -815,10 +816,11 @@
auto& overrideInfo = mOutputLayer.editState().overrideInfo;
overrideInfo.buffer = std::make_shared<
- renderengine::ExternalTexture>(kOverrideBuffer, mRenderEngine,
- renderengine::ExternalTexture::Usage::READABLE |
- renderengine::ExternalTexture::Usage::
- WRITEABLE);
+ renderengine::impl::ExternalTexture>(kOverrideBuffer, mRenderEngine,
+ renderengine::impl::ExternalTexture::Usage::
+ READABLE |
+ renderengine::impl::ExternalTexture::
+ Usage::WRITEABLE);
overrideInfo.acquireFence = kOverrideFence;
overrideInfo.displayFrame = kOverrideDisplayFrame;
overrideInfo.dataspace = kOverrideDataspace;
@@ -864,9 +866,8 @@
}
void expectSetColorCall() {
- const hal::Color color = {static_cast<uint8_t>(std::round(kColor.r * 255)),
- static_cast<uint8_t>(std::round(kColor.g * 255)),
- static_cast<uint8_t>(std::round(kColor.b * 255)), 255};
+ const aidl::android::hardware::graphics::composer3::Color color = {kColor.r, kColor.g,
+ kColor.b, 1.0f};
EXPECT_CALL(*mHwcLayer, setColor(ColorEq(color))).WillOnce(Return(kError));
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 6d96260..b13e13c 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -26,6 +26,8 @@
#include <compositionengine/mock/RenderSurface.h>
#include <ftl/future.h>
#include <gtest/gtest.h>
+#include <renderengine/ExternalTexture.h>
+#include <renderengine/impl/ExternalTexture.h>
#include <renderengine/mock/RenderEngine.h>
#include <ui/Rect.h>
#include <ui/Region.h>
@@ -37,7 +39,6 @@
#include "MockHWC2.h"
#include "RegionMatcher.h"
#include "TestUtils.h"
-#include "renderengine/ExternalTexture.h"
namespace android::compositionengine {
namespace {
@@ -273,9 +274,10 @@
// Inject some layers
InjectedLayer layer;
layer.outputLayerState.overrideInfo.buffer = std::make_shared<
- renderengine::ExternalTexture>(new GraphicBuffer(), renderEngine,
- renderengine::ExternalTexture::Usage::READABLE |
- renderengine::ExternalTexture::Usage::WRITEABLE);
+ renderengine::impl::
+ ExternalTexture>(new GraphicBuffer(), renderEngine,
+ renderengine::impl::ExternalTexture::Usage::READABLE |
+ renderengine::impl::ExternalTexture::Usage::WRITEABLE);
injectOutputLayer(layer);
// inject a null layer to check for null exceptions
injectNullOutputLayer();
@@ -574,6 +576,17 @@
EXPECT_EQ(Rect(newDisplaySize), mOutput->getState().framebufferSpace.getBoundsAsRect());
}
+/**
+ * Output::setDisplayBrightness()
+ */
+
+TEST_F(OutputTest, setNextBrightness) {
+ constexpr float kDisplayBrightness = 0.5f;
+ mOutput->setNextBrightness(kDisplayBrightness);
+ ASSERT_TRUE(mOutput->getState().displayBrightness.has_value());
+ EXPECT_EQ(kDisplayBrightness, mOutput->getState().displayBrightness);
+}
+
/*
* Output::getDirtyRegion()
*/
@@ -956,9 +969,10 @@
mOutput->planComposition();
std::shared_ptr<renderengine::ExternalTexture> buffer = std::make_shared<
- renderengine::ExternalTexture>(new GraphicBuffer(), renderEngine,
- renderengine::ExternalTexture::Usage::READABLE |
- renderengine::ExternalTexture::Usage::WRITEABLE);
+ renderengine::impl::
+ ExternalTexture>(new GraphicBuffer(), renderEngine,
+ renderengine::impl::ExternalTexture::Usage::READABLE |
+ renderengine::impl::ExternalTexture::Usage::WRITEABLE);
layer1.outputLayerState.overrideInfo.buffer = buffer;
layer2.outputLayerState.overrideInfo.buffer = buffer;
layer1.outputLayerState.overrideInfo.peekThroughLayer = layer3.outputLayer;
@@ -3077,9 +3091,10 @@
mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>();
StrictMock<OutputPartialMock> mOutput;
std::shared_ptr<renderengine::ExternalTexture> mOutputBuffer = std::make_shared<
- renderengine::ExternalTexture>(new GraphicBuffer(), mRenderEngine,
- renderengine::ExternalTexture::Usage::READABLE |
- renderengine::ExternalTexture::Usage::WRITEABLE);
+ renderengine::impl::
+ ExternalTexture>(new GraphicBuffer(), mRenderEngine,
+ renderengine::impl::ExternalTexture::Usage::READABLE |
+ renderengine::impl::ExternalTexture::Usage::WRITEABLE);
std::optional<base::unique_fd> mReadyFence;
};
@@ -3313,9 +3328,10 @@
.WillRepeatedly(Return());
const auto otherOutputBuffer = std::make_shared<
- renderengine::ExternalTexture>(new GraphicBuffer(), mRenderEngine,
- renderengine::ExternalTexture::Usage::READABLE |
- renderengine::ExternalTexture::Usage::WRITEABLE);
+ renderengine::impl::
+ ExternalTexture>(new GraphicBuffer(), mRenderEngine,
+ renderengine::impl::ExternalTexture::Usage::READABLE |
+ renderengine::impl::ExternalTexture::Usage::WRITEABLE);
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_))
.WillOnce(Return(mOutputBuffer))
.WillOnce(Return(otherOutputBuffer));
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
index 7c8e41b..e5f9ebf 100644
--- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -27,6 +27,7 @@
#include <compositionengine/mock/OutputLayer.h>
#include <gtest/gtest.h>
#include <renderengine/ExternalTexture.h>
+#include <renderengine/impl/ExternalTexture.h>
#include <renderengine/mock/RenderEngine.h>
#include <ui/GraphicBuffer.h>
@@ -251,9 +252,10 @@
TEST_F(RenderSurfaceTest, queueBufferHandlesNoClientComposition) {
const auto buffer = std::make_shared<
- renderengine::ExternalTexture>(new GraphicBuffer(), mRenderEngine,
- renderengine::ExternalTexture::Usage::READABLE |
- renderengine::ExternalTexture::Usage::WRITEABLE);
+ renderengine::impl::
+ ExternalTexture>(new GraphicBuffer(), mRenderEngine,
+ renderengine::impl::ExternalTexture::Usage::READABLE |
+ renderengine::impl::ExternalTexture::Usage::WRITEABLE);
mSurface.mutableTextureForTest() = buffer;
impl::OutputCompositionState state;
@@ -269,8 +271,8 @@
}
TEST_F(RenderSurfaceTest, queueBufferHandlesClientComposition) {
- const auto buffer = std::make_shared<renderengine::ExternalTexture>(new GraphicBuffer(),
- mRenderEngine, false);
+ const auto buffer = std::make_shared<renderengine::impl::ExternalTexture>(new GraphicBuffer(),
+ mRenderEngine, false);
mSurface.mutableTextureForTest() = buffer;
impl::OutputCompositionState state;
@@ -288,8 +290,8 @@
}
TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequest) {
- const auto buffer = std::make_shared<renderengine::ExternalTexture>(new GraphicBuffer(),
- mRenderEngine, false);
+ const auto buffer = std::make_shared<renderengine::impl::ExternalTexture>(new GraphicBuffer(),
+ mRenderEngine, false);
mSurface.mutableTextureForTest() = buffer;
impl::OutputCompositionState state;
@@ -327,8 +329,8 @@
}
TEST_F(RenderSurfaceTest, queueBufferHandlesNativeWindowQueueBufferFailureOnVirtualDisplay) {
- const auto buffer = std::make_shared<renderengine::ExternalTexture>(new GraphicBuffer(),
- mRenderEngine, false);
+ const auto buffer = std::make_shared<renderengine::impl::ExternalTexture>(new GraphicBuffer(),
+ mRenderEngine, false);
mSurface.mutableTextureForTest() = buffer;
impl::OutputCompositionState state;
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
index d5a117a..4ae921d 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
@@ -22,6 +22,7 @@
#include <gmock/gmock-actions.h>
#include <gtest/gtest.h>
#include <renderengine/ExternalTexture.h>
+#include <renderengine/mock/FakeExternalTexture.h>
#include <renderengine/mock/RenderEngine.h>
#include <ui/GraphicTypes.h>
#include <utils/Errors.h>
@@ -702,9 +703,11 @@
std::vector<compositionengine::LayerFE::LayerSettings> clientCompList3;
clientCompList3.push_back({});
- clientCompList3[0].source.buffer.buffer = std::make_shared<
- renderengine::ExternalTexture>(sp<GraphicBuffer>::make(), mRenderEngine,
- renderengine::ExternalTexture::READABLE);
+ clientCompList3[0].source.buffer.buffer =
+ std::make_shared<renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/,
+ 1ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0ULL /*usage*/);
EXPECT_CALL(*layerFE1, prepareClientCompositionList(_)).WillOnce(Return(clientCompList1));
EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2));
@@ -901,9 +904,11 @@
std::vector<compositionengine::LayerFE::LayerSettings> clientCompList3;
clientCompList3.push_back({});
- clientCompList3[0].source.buffer.buffer = std::make_shared<
- renderengine::ExternalTexture>(sp<GraphicBuffer>::make(), mRenderEngine,
- renderengine::ExternalTexture::READABLE);
+ clientCompList3[0].source.buffer.buffer =
+ std::make_shared<renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/,
+ 1ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0ULL /*usage*/);
EXPECT_CALL(*layerFE1,
prepareClientCompositionList(ClientCompositionTargetSettingsBlurSettingsEq(
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
index 35d051e..58dc244 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
@@ -23,6 +23,7 @@
#include <gtest/gtest.h>
#include <renderengine/ExternalTexture.h>
#include <renderengine/LayerSettings.h>
+#include <renderengine/impl/ExternalTexture.h>
#include <renderengine/mock/RenderEngine.h>
#include <chrono>
@@ -639,9 +640,10 @@
LayerFE::LayerSettings{},
};
clientCompositionList[0].source.buffer.buffer = std::make_shared<
- renderengine::ExternalTexture>(mTestLayers[2]->layerFECompositionState.buffer,
- mRenderEngine,
- renderengine::ExternalTexture::Usage::READABLE);
+ renderengine::impl::ExternalTexture>(mTestLayers[2]->layerFECompositionState.buffer,
+ mRenderEngine,
+ renderengine::impl::ExternalTexture::Usage::
+ READABLE);
EXPECT_CALL(*mTestLayers[2]->layerFE, prepareClientCompositionList(_))
.WillOnce(Return(clientCompositionList));
@@ -711,9 +713,10 @@
LayerFE::LayerSettings{},
};
clientCompositionList[0].source.buffer.buffer = std::make_shared<
- renderengine::ExternalTexture>(mTestLayers[1]->layerFECompositionState.buffer,
- mRenderEngine,
- renderengine::ExternalTexture::Usage::READABLE);
+ renderengine::impl::ExternalTexture>(mTestLayers[1]->layerFECompositionState.buffer,
+ mRenderEngine,
+ renderengine::impl::ExternalTexture::Usage::
+ READABLE);
EXPECT_CALL(*mTestLayers[1]->layerFE, prepareClientCompositionList(_))
.WillOnce(Return(clientCompositionList));
@@ -781,9 +784,10 @@
LayerFE::LayerSettings{},
};
clientCompositionList[0].source.buffer.buffer = std::make_shared<
- renderengine::ExternalTexture>(mTestLayers[1]->layerFECompositionState.buffer,
- mRenderEngine,
- renderengine::ExternalTexture::Usage::READABLE);
+ renderengine::impl::ExternalTexture>(mTestLayers[1]->layerFECompositionState.buffer,
+ mRenderEngine,
+ renderengine::impl::ExternalTexture::Usage::
+ READABLE);
EXPECT_CALL(*mTestLayers[1]->layerFE, prepareClientCompositionList(_))
.WillOnce(Return(clientCompositionList));
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 76bbe2c..a36ea72 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -311,6 +311,22 @@
orientedDisplaySpaceRect);
}
+void DisplayDevice::stageBrightness(float brightness) {
+ mStagedBrightness = brightness;
+}
+
+void DisplayDevice::persistBrightness(bool needsComposite) {
+ if (needsComposite && mStagedBrightness && mBrightness != *mStagedBrightness) {
+ getCompositionDisplay()->setNextBrightness(*mStagedBrightness);
+ mBrightness = *mStagedBrightness;
+ }
+ mStagedBrightness = std::nullopt;
+}
+
+std::optional<float> DisplayDevice::getStagedBrightness() const {
+ return mStagedBrightness;
+}
+
ui::Transform::RotationFlags DisplayDevice::getPrimaryDisplayRotationFlags() {
return sPrimaryDisplayRotationFlags;
}
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 324145e..d2accaa 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -99,6 +99,9 @@
void setLayerStack(ui::LayerStack);
void setDisplaySize(int width, int height);
void setProjection(ui::Rotation orientation, Rect viewport, Rect frame);
+ void stageBrightness(float brightness) REQUIRES(SF_MAIN_THREAD);
+ void persistBrightness(bool needsComposite) REQUIRES(SF_MAIN_THREAD);
+ bool isBrightnessStale() const REQUIRES(SF_MAIN_THREAD);
void setFlags(uint32_t flags);
ui::Rotation getPhysicalOrientation() const { return mPhysicalOrientation; }
@@ -106,6 +109,7 @@
static ui::Transform::RotationFlags getPrimaryDisplayRotationFlags();
+ std::optional<float> getStagedBrightness() const REQUIRES(SF_MAIN_THREAD);
ui::Transform::RotationFlags getTransformHint() const;
const ui::Transform& getTransform() const;
const Rect& getLayerStackSpaceRect() const;
@@ -271,6 +275,8 @@
hardware::graphics::composer::hal::PowerMode mPowerMode =
hardware::graphics::composer::hal::PowerMode::OFF;
DisplayModePtr mActiveMode;
+ std::optional<float> mStagedBrightness = std::nullopt;
+ float mBrightness = -1.f;
const DisplayModes mSupportedModes;
std::atomic<nsecs_t> mLastHwVsync = 0;
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index 1091a75..1448e56 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -110,16 +110,6 @@
}
template <>
-Color translate(IComposerClient::Color x) {
- return Color{
- .r = static_cast<int8_t>(x.r),
- .g = static_cast<int8_t>(x.g),
- .b = static_cast<int8_t>(x.b),
- .a = static_cast<int8_t>(x.a),
- };
-}
-
-template <>
AidlPerFrameMetadataBlob translate(IComposerClient::PerFrameMetadataBlob x) {
AidlPerFrameMetadataBlob blob;
blob.key = translate<AidlPerFrameMetadataKey>(x.key),
@@ -246,6 +236,8 @@
switch (feature) {
case OptionalFeature::RefreshRateSwitching:
case OptionalFeature::ExpectedPresentTime:
+ case OptionalFeature::DisplayBrightnessCommand:
+ case OptionalFeature::BootDisplayConfig:
return true;
}
}
@@ -669,10 +661,8 @@
return Error::NONE;
}
-Error AidlComposer::setLayerColor(Display display, Layer layer,
- const IComposerClient::Color& color) {
- mWriter.setLayerColor(translate<int64_t>(display), translate<int64_t>(layer),
- translate<Color>(color));
+Error AidlComposer::setLayerColor(Display display, Layer layer, const Color& color) {
+ mWriter.setLayerColor(translate<int64_t>(display), translate<int64_t>(layer), color);
return Error::NONE;
}
@@ -906,13 +896,14 @@
return Error::NONE;
}
-Error AidlComposer::setDisplayBrightness(Display display, float brightness) {
- const auto status =
- mAidlComposerClient->setDisplayBrightness(translate<int64_t>(display), brightness);
- if (!status.isOk()) {
- ALOGE("setDisplayBrightness failed %s", status.getDescription().c_str());
- return static_cast<Error>(status.getServiceSpecificError());
+Error AidlComposer::setDisplayBrightness(Display display, float brightness,
+ const DisplayBrightnessOptions& options) {
+ mWriter.setDisplayBrightness(translate<int64_t>(display), brightness);
+
+ if (options.applyImmediately) {
+ return execute();
}
+
return Error::NONE;
}
@@ -1019,6 +1010,38 @@
return V2_4::Error::UNSUPPORTED;
}
+Error AidlComposer::setBootDisplayConfig(Display display, Config config) {
+ const auto status = mAidlComposerClient->setBootDisplayConfig(translate<int64_t>(display),
+ translate<int32_t>(config));
+ if (!status.isOk()) {
+ ALOGE("setBootDisplayConfig failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ return Error::NONE;
+}
+
+Error AidlComposer::clearBootDisplayConfig(Display display) {
+ const auto status = mAidlComposerClient->clearBootDisplayConfig(translate<int64_t>(display));
+ if (!status.isOk()) {
+ ALOGE("clearBootDisplayConfig failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ return Error::NONE;
+}
+
+Error AidlComposer::getPreferredBootDisplayConfig(Display display, Config* config) {
+ int32_t displayConfig;
+ const auto status =
+ mAidlComposerClient->getPreferredBootDisplayConfig(translate<int64_t>(display),
+ &displayConfig);
+ if (!status.isOk()) {
+ ALOGE("getPreferredBootDisplayConfig failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ *config = translate<uint32_t>(displayConfig);
+ return Error::NONE;
+}
+
Error AidlComposer::getClientTargetProperty(
Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty,
float* whitePointNits) {
@@ -1035,5 +1058,11 @@
return Error::NONE;
}
+Error AidlComposer::setLayerBlockingRegion(Display display, Layer layer,
+ const std::vector<IComposerClient::Rect>& blocking) {
+ mWriter.setLayerBlockingRegion(translate<int64_t>(display), translate<int64_t>(layer),
+ translate<AidlRect>(blocking));
+ return Error::NONE;
+}
} // namespace Hwc2
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
index 5c41982..6770017 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
@@ -139,7 +139,7 @@
Error setLayerSurfaceDamage(Display display, Layer layer,
const std::vector<IComposerClient::Rect>& damage) override;
Error setLayerBlendMode(Display display, Layer layer, IComposerClient::BlendMode mode) override;
- Error setLayerColor(Display display, Layer layer, const IComposerClient::Color& color) override;
+ Error setLayerColor(Display display, Layer layer, const Color& color) override;
Error setLayerCompositionType(
Display display, Layer layer,
aidl::android::hardware::graphics::composer3::Composition type) override;
@@ -180,7 +180,8 @@
Error setLayerPerFrameMetadataBlobs(
Display display, Layer layer,
const std::vector<IComposerClient::PerFrameMetadataBlob>& metadata) override;
- Error setDisplayBrightness(Display display, float brightness) override;
+ Error setDisplayBrightness(Display display, float brightness,
+ const DisplayBrightnessOptions& options) override;
// Composer HAL 2.4
Error getDisplayCapabilities(
@@ -207,7 +208,14 @@
Error getClientTargetProperty(Display display,
IComposerClient::ClientTargetProperty* outClientTargetProperty,
float* outClientTargetWhitePointNits) override;
+
+ // AIDL Composer HAL
Error setLayerWhitePointNits(Display display, Layer layer, float whitePointNits) override;
+ Error setLayerBlockingRegion(Display display, Layer layer,
+ const std::vector<IComposerClient::Rect>& blocking) override;
+ Error setBootDisplayConfig(Display displayId, Config) override;
+ Error clearBootDisplayConfig(Display displayId) override;
+ Error getPreferredBootDisplayConfig(Display displayId, Config*) override;
private:
// Many public functions above simply write a command into the command
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index f491a00..22f424f 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -31,6 +31,7 @@
#include <ui/GraphicBuffer.h>
#include <utils/StrongPointer.h>
+#include <aidl/android/hardware/graphics/composer3/Color.h>
#include <aidl/android/hardware/graphics/composer3/Composition.h>
#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
@@ -78,6 +79,9 @@
enum class OptionalFeature {
RefreshRateSwitching,
ExpectedPresentTime,
+ // Whether setDisplayBrightness is able to be applied as part of a display command.
+ DisplayBrightnessCommand,
+ BootDisplayConfig,
};
virtual bool isSupported(OptionalFeature) const = 0;
@@ -162,8 +166,9 @@
const std::vector<IComposerClient::Rect>& damage) = 0;
virtual Error setLayerBlendMode(Display display, Layer layer,
IComposerClient::BlendMode mode) = 0;
- virtual Error setLayerColor(Display display, Layer layer,
- const IComposerClient::Color& color) = 0;
+ virtual Error setLayerColor(
+ Display display, Layer layer,
+ const aidl::android::hardware::graphics::composer3::Color& color) = 0;
virtual Error setLayerCompositionType(
Display display, Layer layer,
aidl::android::hardware::graphics::composer3::Composition type) = 0;
@@ -204,7 +209,20 @@
DisplayedFrameStats* outStats) = 0;
virtual Error setLayerPerFrameMetadataBlobs(
Display display, Layer layer, const std::vector<PerFrameMetadataBlob>& metadata) = 0;
- virtual Error setDisplayBrightness(Display display, float brightness) = 0;
+ // Options for setting the display brightness
+ struct DisplayBrightnessOptions {
+ // If true, then immediately submits a brightness change request to composer. Otherwise,
+ // submission of the brightness change may be deferred until presenting the next frame.
+ // applyImmediately should only be false if OptionalFeature::DisplayBrightnessCommand is
+ // supported.
+ bool applyImmediately = true;
+
+ bool operator==(const DisplayBrightnessOptions& other) const {
+ return applyImmediately == other.applyImmediately;
+ }
+ };
+ virtual Error setDisplayBrightness(Display display, float brightness,
+ const DisplayBrightnessOptions& options) = 0;
// Composer HAL 2.4
virtual Error getDisplayCapabilities(
@@ -231,12 +249,18 @@
const std::vector<uint8_t>& value) = 0;
virtual V2_4::Error getLayerGenericMetadataKeys(
std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) = 0;
+
virtual Error getClientTargetProperty(
Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty,
float* outWhitePointNits) = 0;
// AIDL Composer
virtual Error setLayerWhitePointNits(Display display, Layer layer, float whitePointNits) = 0;
+ virtual Error setLayerBlockingRegion(Display display, Layer layer,
+ const std::vector<IComposerClient::Rect>& blocking) = 0;
+ virtual Error setBootDisplayConfig(Display displayId, Config) = 0;
+ virtual Error clearBootDisplayConfig(Display displayId) = 0;
+ virtual Error getPreferredBootDisplayConfig(Display displayId, Config*) = 0;
};
} // namespace android::Hwc2
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 548d839..05e3aef 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -37,8 +37,7 @@
#include <iterator>
#include <set>
-#include "ComposerHal.h"
-
+using aidl::android::hardware::graphics::composer3::Color;
using aidl::android::hardware::graphics::composer3::Composition;
using aidl::android::hardware::graphics::composer3::DisplayCapability;
@@ -532,13 +531,29 @@
return error;
}
-std::future<Error> Display::setDisplayBrightness(float brightness) {
- return ftl::defer([composer = &mComposer, id = mId, brightness] {
- const auto intError = composer->setDisplayBrightness(id, brightness);
+std::future<Error> Display::setDisplayBrightness(
+ float brightness, const Hwc2::Composer::DisplayBrightnessOptions& options) {
+ return ftl::defer([composer = &mComposer, id = mId, brightness, options] {
+ const auto intError = composer->setDisplayBrightness(id, brightness, options);
return static_cast<Error>(intError);
});
}
+Error Display::setBootDisplayConfig(hal::HWConfigId configId) {
+ auto intError = mComposer.setBootDisplayConfig(mId, configId);
+ return static_cast<Error>(intError);
+}
+
+Error Display::clearBootDisplayConfig() {
+ auto intError = mComposer.clearBootDisplayConfig(mId);
+ return static_cast<Error>(intError);
+}
+
+Error Display::getPreferredBootDisplayConfig(hal::HWConfigId* configId) const {
+ auto intError = mComposer.getPreferredBootDisplayConfig(mId, configId);
+ return static_cast<Error>(intError);
+}
+
Error Display::setAutoLowLatencyMode(bool on) {
auto intError = mComposer.setAutoLowLatencyMode(mId, on);
return static_cast<Error>(intError);
@@ -584,6 +599,21 @@
// Layer methods
+namespace {
+std::vector<Hwc2::IComposerClient::Rect> convertRegionToHwcRects(const Region& region) {
+ size_t rectCount = 0;
+ Rect const* rectArray = region.getArray(&rectCount);
+
+ std::vector<Hwc2::IComposerClient::Rect> hwcRects;
+ hwcRects.reserve(rectCount);
+ for (size_t rect = 0; rect < rectCount; ++rect) {
+ hwcRects.push_back({rectArray[rect].left, rectArray[rect].top, rectArray[rect].right,
+ rectArray[rect].bottom});
+ }
+ return hwcRects;
+}
+} // namespace
+
Layer::~Layer() = default;
namespace impl {
@@ -674,15 +704,7 @@
intError = mComposer.setLayerSurfaceDamage(mDisplay->getId(), mId,
std::vector<Hwc2::IComposerClient::Rect>());
} else {
- size_t rectCount = 0;
- auto rectArray = damage.getArray(&rectCount);
-
- std::vector<Hwc2::IComposerClient::Rect> hwcRects;
- for (size_t rect = 0; rect < rectCount; ++rect) {
- hwcRects.push_back({rectArray[rect].left, rectArray[rect].top,
- rectArray[rect].right, rectArray[rect].bottom});
- }
-
+ const auto hwcRects = convertRegionToHwcRects(damage);
intError = mComposer.setLayerSurfaceDamage(mDisplay->getId(), mId, hwcRects);
}
@@ -870,16 +892,7 @@
return Error::NONE;
}
mVisibleRegion = region;
-
- size_t rectCount = 0;
- auto rectArray = region.getArray(&rectCount);
-
- std::vector<Hwc2::IComposerClient::Rect> hwcRects;
- for (size_t rect = 0; rect < rectCount; ++rect) {
- hwcRects.push_back({rectArray[rect].left, rectArray[rect].top,
- rectArray[rect].right, rectArray[rect].bottom});
- }
-
+ const auto hwcRects = convertRegionToHwcRects(region);
auto intError = mComposer.setLayerVisibleRegion(mDisplay->getId(), mId, hwcRects);
return static_cast<Error>(intError);
}
@@ -934,6 +947,21 @@
return static_cast<Error>(intError);
}
+Error Layer::setBlockingRegion(const Region& region) {
+ if (CC_UNLIKELY(!mDisplay)) {
+ return Error::BAD_DISPLAY;
+ }
+
+ if (region.isRect() && mBlockingRegion.isRect() &&
+ (region.getBounds() == mBlockingRegion.getBounds())) {
+ return Error::NONE;
+ }
+ mBlockingRegion = region;
+ const auto hwcRects = convertRegionToHwcRects(region);
+ const auto intError = mComposer.setLayerBlockingRegion(mDisplay->getId(), mId, hwcRects);
+ 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 731d7f6..57eb128 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -34,8 +34,10 @@
#include <unordered_set>
#include <vector>
+#include "ComposerHal.h"
#include "Hal.h"
+#include <aidl/android/hardware/graphics/composer3/Color.h>
#include <aidl/android/hardware/graphics/composer3/Composition.h>
#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
@@ -143,10 +145,15 @@
nsecs_t expectedPresentTime, uint32_t* outNumTypes, uint32_t* outNumRequests,
android::sp<android::Fence>* outPresentFence, uint32_t* state) = 0;
[[clang::warn_unused_result]] virtual std::future<hal::Error> setDisplayBrightness(
- float brightness) = 0;
+ float brightness, const Hwc2::Composer::DisplayBrightnessOptions& options) = 0;
[[clang::warn_unused_result]] virtual hal::Error setActiveConfigWithConstraints(
hal::HWConfigId configId, const hal::VsyncPeriodChangeConstraints& constraints,
hal::VsyncPeriodChangeTimeline* outTimeline) = 0;
+ [[clang::warn_unused_result]] virtual hal::Error setBootDisplayConfig(
+ hal::HWConfigId configId) = 0;
+ [[clang::warn_unused_result]] virtual hal::Error clearBootDisplayConfig() = 0;
+ [[clang::warn_unused_result]] virtual hal::Error getPreferredBootDisplayConfig(
+ hal::HWConfigId* configId) const = 0;
[[clang::warn_unused_result]] virtual hal::Error setAutoLowLatencyMode(bool on) = 0;
[[clang::warn_unused_result]] virtual hal::Error getSupportedContentTypes(
std::vector<hal::ContentType>*) const = 0;
@@ -211,10 +218,14 @@
uint32_t* outNumRequests,
android::sp<android::Fence>* outPresentFence,
uint32_t* state) override;
- std::future<hal::Error> setDisplayBrightness(float brightness) override;
+ std::future<hal::Error> setDisplayBrightness(
+ float brightness, const Hwc2::Composer::DisplayBrightnessOptions& options) override;
hal::Error setActiveConfigWithConstraints(hal::HWConfigId configId,
const hal::VsyncPeriodChangeConstraints& constraints,
hal::VsyncPeriodChangeTimeline* outTimeline) override;
+ hal::Error setBootDisplayConfig(hal::HWConfigId configId) override;
+ hal::Error clearBootDisplayConfig() override;
+ hal::Error getPreferredBootDisplayConfig(hal::HWConfigId* configId) const override;
hal::Error setAutoLowLatencyMode(bool on) override;
hal::Error getSupportedContentTypes(
std::vector<hal::ContentType>* outSupportedContentTypes) const override;
@@ -277,7 +288,8 @@
const android::Region& damage) = 0;
[[clang::warn_unused_result]] virtual hal::Error setBlendMode(hal::BlendMode mode) = 0;
- [[clang::warn_unused_result]] virtual hal::Error setColor(hal::Color color) = 0;
+ [[clang::warn_unused_result]] virtual hal::Error setColor(
+ aidl::android::hardware::graphics::composer3::Color color) = 0;
[[clang::warn_unused_result]] virtual hal::Error setCompositionType(
aidl::android::hardware::graphics::composer3::Composition type) = 0;
[[clang::warn_unused_result]] virtual hal::Error setDataspace(hal::Dataspace dataspace) = 0;
@@ -305,6 +317,8 @@
// AIDL HAL
[[clang::warn_unused_result]] virtual hal::Error setWhitePointNits(float whitePointNits) = 0;
+ [[clang::warn_unused_result]] virtual hal::Error setBlockingRegion(
+ const android::Region& region) = 0;
};
namespace impl {
@@ -328,7 +342,7 @@
hal::Error setSurfaceDamage(const android::Region& damage) override;
hal::Error setBlendMode(hal::BlendMode mode) override;
- hal::Error setColor(hal::Color color) override;
+ hal::Error setColor(aidl::android::hardware::graphics::composer3::Color color) override;
hal::Error setCompositionType(
aidl::android::hardware::graphics::composer3::Composition type) override;
hal::Error setDataspace(hal::Dataspace dataspace) override;
@@ -351,6 +365,7 @@
// AIDL HAL
hal::Error setWhitePointNits(float whitePointNits) override;
+ hal::Error setBlockingRegion(const android::Region& region) override;
private:
// These are references to data owned by HWC2::Device, which will outlive
@@ -366,6 +381,7 @@
// multiple times.
android::Region mVisibleRegion = android::Region::INVALID_REGION;
android::Region mDamageRegion = android::Region::INVALID_REGION;
+ android::Region mBlockingRegion = android::Region::INVALID_REGION;
hal::Dataspace mDataSpace = hal::Dataspace::UNKNOWN;
android::HdrMetadata mHdrMetadata;
android::mat4 mColorMatrix;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 546e677..44e4597 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -782,12 +782,13 @@
return NO_ERROR;
}
-std::future<status_t> HWComposer::setDisplayBrightness(PhysicalDisplayId displayId,
- float brightness) {
+std::future<status_t> HWComposer::setDisplayBrightness(
+ PhysicalDisplayId displayId, float brightness,
+ const Hwc2::Composer::DisplayBrightnessOptions& options) {
RETURN_IF_INVALID_DISPLAY(displayId, ftl::yield<status_t>(BAD_INDEX));
auto& display = mDisplayData[displayId].hwcDisplay;
- return ftl::chain(display->setDisplayBrightness(brightness))
+ return ftl::chain(display->setDisplayBrightness(brightness, options))
.then([displayId](hal::Error error) -> status_t {
if (error == hal::Error::UNSUPPORTED) {
RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION);
@@ -800,6 +801,52 @@
});
}
+bool HWComposer::getBootDisplayModeSupport() {
+ return mComposer->isSupported(Hwc2::Composer::OptionalFeature::BootDisplayConfig);
+}
+
+status_t HWComposer::setBootDisplayMode(PhysicalDisplayId displayId,
+ hal::HWConfigId displayModeId) {
+ RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
+ const auto error = mDisplayData[displayId].hwcDisplay->setBootDisplayConfig(displayModeId);
+ if (error == hal::Error::UNSUPPORTED) {
+ RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION);
+ }
+ if (error == hal::Error::BAD_PARAMETER) {
+ RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE);
+ }
+ RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
+ return NO_ERROR;
+}
+
+status_t HWComposer::clearBootDisplayMode(PhysicalDisplayId displayId) {
+ RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
+ const auto error = mDisplayData[displayId].hwcDisplay->clearBootDisplayConfig();
+ if (error == hal::Error::UNSUPPORTED) {
+ RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION);
+ }
+ if (error == hal::Error::BAD_PARAMETER) {
+ RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE);
+ }
+ RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
+ return NO_ERROR;
+}
+
+hal::HWConfigId HWComposer::getPreferredBootDisplayMode(PhysicalDisplayId displayId) {
+ RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
+ hal::HWConfigId displayModeId = -1;
+ const auto error =
+ mDisplayData[displayId].hwcDisplay->getPreferredBootDisplayConfig(&displayModeId);
+ if (error == hal::Error::UNSUPPORTED) {
+ RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION);
+ }
+ if (error == hal::Error::BAD_PARAMETER) {
+ RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE);
+ }
+ RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
+ return displayModeId;
+}
+
status_t HWComposer::setAutoLowLatencyMode(PhysicalDisplayId displayId, bool on) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
const auto error = mDisplayData[displayId].hwcDisplay->setAutoLowLatencyMode(on);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 69adfcd..9e57602 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -192,7 +192,9 @@
DisplayedFrameStats* outStats) = 0;
// Sets the brightness of a display.
- virtual std::future<status_t> setDisplayBrightness(PhysicalDisplayId, float brightness) = 0;
+ virtual std::future<status_t> setDisplayBrightness(
+ PhysicalDisplayId, float brightness,
+ const Hwc2::Composer::DisplayBrightnessOptions&) = 0;
// Events handling ---------------------------------------------------------
@@ -253,6 +255,12 @@
virtual std::optional<PhysicalDisplayId> toPhysicalDisplayId(hal::HWDisplayId) const = 0;
virtual std::optional<hal::HWDisplayId> fromPhysicalDisplayId(PhysicalDisplayId) const = 0;
+
+ // Composer 3.0
+ virtual bool getBootDisplayModeSupport() = 0;
+ virtual status_t setBootDisplayMode(PhysicalDisplayId, hal::HWConfigId) = 0;
+ virtual status_t clearBootDisplayMode(PhysicalDisplayId) = 0;
+ virtual hal::HWConfigId getPreferredBootDisplayMode(PhysicalDisplayId) = 0;
};
namespace impl {
@@ -340,7 +348,9 @@
uint64_t maxFrames) override;
status_t getDisplayedContentSample(HalDisplayId, uint64_t maxFrames, uint64_t timestamp,
DisplayedFrameStats* outStats) override;
- std::future<status_t> setDisplayBrightness(PhysicalDisplayId, float brightness) override;
+ std::future<status_t> setDisplayBrightness(
+ PhysicalDisplayId, float brightness,
+ const Hwc2::Composer::DisplayBrightnessOptions&) override;
// Events handling ---------------------------------------------------------
@@ -377,6 +387,12 @@
const std::unordered_map<std::string, bool>& getSupportedLayerGenericMetadata() const override;
+ // Composer 3.0
+ bool getBootDisplayModeSupport() override;
+ status_t setBootDisplayMode(PhysicalDisplayId, hal::HWConfigId) override;
+ status_t clearBootDisplayMode(PhysicalDisplayId) override;
+ hal::HWConfigId getPreferredBootDisplayMode(PhysicalDisplayId) override;
+
// for debugging ----------------------------------------------------------
void dump(std::string& out) const override;
diff --git a/services/surfaceflinger/DisplayHardware/Hal.h b/services/surfaceflinger/DisplayHardware/Hal.h
index e33dc0f..40c9761 100644
--- a/services/surfaceflinger/DisplayHardware/Hal.h
+++ b/services/surfaceflinger/DisplayHardware/Hal.h
@@ -51,7 +51,6 @@
using Attribute = IComposerClient::Attribute;
using BlendMode = IComposerClient::BlendMode;
-using Color = IComposerClient::Color;
using Connection = IComposerCallback::Connection;
using ContentType = IComposerClient::ContentType;
using Capability = IComposer::Capability;
@@ -136,6 +135,8 @@
return "AutoLowLatencyMode";
case aidl::android::hardware::graphics::composer3::DisplayCapability::SUSPEND:
return "Suspend";
+ case aidl::android::hardware::graphics::composer3::DisplayCapability::DISPLAY_DECORATION:
+ return "DisplayDecoration";
default:
return "Unknown";
}
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index 7946002..d3acecb 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -161,6 +161,8 @@
case OptionalFeature::RefreshRateSwitching:
return mClient_2_4 != nullptr;
case OptionalFeature::ExpectedPresentTime:
+ case OptionalFeature::DisplayBrightnessCommand:
+ case OptionalFeature::BootDisplayConfig:
return false;
}
}
@@ -625,11 +627,29 @@
return Error::NONE;
}
-Error HidlComposer::setLayerColor(Display display, Layer layer,
- const IComposerClient::Color& color) {
+static IComposerClient::Color to_hidl_type(
+ aidl::android::hardware::graphics::composer3::Color color) {
+ const auto floatColorToUint8Clamped = [](float val) -> uint8_t {
+ const auto intVal = static_cast<uint64_t>(std::round(255.0f * val));
+ const auto minVal = static_cast<uint64_t>(0);
+ const auto maxVal = static_cast<uint64_t>(255);
+ return std::clamp(intVal, minVal, maxVal);
+ };
+
+ return IComposerClient::Color{
+ floatColorToUint8Clamped(color.r),
+ floatColorToUint8Clamped(color.g),
+ floatColorToUint8Clamped(color.b),
+ floatColorToUint8Clamped(color.a),
+ };
+}
+
+Error HidlComposer::setLayerColor(
+ Display display, Layer layer,
+ const aidl::android::hardware::graphics::composer3::Color& color) {
mWriter.selectDisplay(display);
mWriter.selectLayer(layer);
- mWriter.setLayerColor(color);
+ mWriter.setLayerColor(to_hidl_type(color));
return Error::NONE;
}
@@ -1013,7 +1033,8 @@
return Error::NONE;
}
-Error HidlComposer::setDisplayBrightness(Display display, float brightness) {
+Error HidlComposer::setDisplayBrightness(Display display, float brightness,
+ const DisplayBrightnessOptions&) {
if (!mClient_2_3) {
return Error::UNSUPPORTED;
}
@@ -1196,6 +1217,18 @@
return error;
}
+Error HidlComposer::setBootDisplayConfig(Display /*displayId*/, Config) {
+ return Error::UNSUPPORTED;
+}
+
+Error HidlComposer::clearBootDisplayConfig(Display /*displayId*/) {
+ return Error::UNSUPPORTED;
+}
+
+Error HidlComposer::getPreferredBootDisplayConfig(Display /*displayId*/, Config*) {
+ return Error::UNSUPPORTED;
+}
+
Error HidlComposer::getClientTargetProperty(
Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty,
float* outWhitePointNits) {
@@ -1208,6 +1241,11 @@
return Error::NONE;
}
+Error HidlComposer::setLayerBlockingRegion(Display, Layer,
+ const std::vector<IComposerClient::Rect>&) {
+ return Error::NONE;
+}
+
CommandReader::~CommandReader() {
resetData();
}
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
index 3b62fe0..c8c7800 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
@@ -248,7 +248,8 @@
Error setLayerSurfaceDamage(Display display, Layer layer,
const std::vector<IComposerClient::Rect>& damage) override;
Error setLayerBlendMode(Display display, Layer layer, IComposerClient::BlendMode mode) override;
- Error setLayerColor(Display display, Layer layer, const IComposerClient::Color& color) override;
+ Error setLayerColor(Display display, Layer layer,
+ const aidl::android::hardware::graphics::composer3::Color& color) override;
Error setLayerCompositionType(
Display display, Layer layer,
aidl::android::hardware::graphics::composer3::Composition type) override;
@@ -289,7 +290,8 @@
Error setLayerPerFrameMetadataBlobs(
Display display, Layer layer,
const std::vector<IComposerClient::PerFrameMetadataBlob>& metadata) override;
- Error setDisplayBrightness(Display display, float brightness) override;
+ Error setDisplayBrightness(Display display, float brightness,
+ const DisplayBrightnessOptions& options) override;
// Composer HAL 2.4
Error getDisplayCapabilities(
@@ -316,7 +318,14 @@
Error getClientTargetProperty(Display display,
IComposerClient::ClientTargetProperty* outClientTargetProperty,
float* outWhitePointNits) override;
+
+ // AIDL Composer HAL
Error setLayerWhitePointNits(Display display, Layer layer, float whitePointNits) override;
+ Error setLayerBlockingRegion(Display display, Layer layer,
+ const std::vector<IComposerClient::Rect>& blocking) override;
+ Error setBootDisplayConfig(Display displayId, Config) override;
+ Error clearBootDisplayConfig(Display displayId) override;
+ Error getPreferredBootDisplayConfig(Display displayId, Config*) override;
private:
class CommandWriter : public CommandWriterBase {
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 5c2390e..6f02843 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -93,13 +93,6 @@
void PowerAdvisor::onBootFinished() {
mBootFinished.store(true);
- {
- std::lock_guard lock(mPowerHalMutex);
- HalWrapper* halWrapper = getPowerHal();
- if (halWrapper != nullptr && usePowerHintSession()) {
- mPowerHintSessionRunning = halWrapper->startPowerHintSession();
- }
- }
}
void PowerAdvisor::setExpensiveRenderingExpected(DisplayId displayId, bool expected) {
@@ -156,7 +149,6 @@
// checks both if it supports and if it's enabled
bool PowerAdvisor::usePowerHintSession() {
// uses cached value since the underlying support and flag are unlikely to change at runtime
- ALOGE_IF(!mPowerHintEnabled.has_value(), "Power hint session cannot be used before boot!");
return mPowerHintEnabled.value_or(false) && supportsPowerHintSession();
}
@@ -175,10 +167,7 @@
}
void PowerAdvisor::setTargetWorkDuration(int64_t targetDurationNanos) {
- // we check "supports" here not "usePowerHintSession" because this needs to work
- // before the session is actually running, and "use" will always fail before boot
- // we store the values passed in before boot to start the session with during onBootFinished
- if (!supportsPowerHintSession()) {
+ if (!usePowerHintSession()) {
ALOGV("Power hint session target duration cannot be set, skipping");
return;
}
@@ -186,24 +175,7 @@
std::lock_guard lock(mPowerHalMutex);
HalWrapper* const halWrapper = getPowerHal();
if (halWrapper != nullptr) {
- halWrapper->setTargetWorkDuration(targetDurationNanos);
- }
- }
-}
-
-void PowerAdvisor::setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) {
- // we check "supports" here not "usePowerHintSession" because this needs to wsork
- // before the session is actually running, and "use" will always fail before boot.
- // we store the values passed in before boot to start the session with during onBootFinished
- if (!supportsPowerHintSession()) {
- ALOGV("Power hint session thread ids cannot be set, skipping");
- return;
- }
- {
- std::lock_guard lock(mPowerHalMutex);
- HalWrapper* const halWrapper = getPowerHal();
- if (halWrapper != nullptr) {
- halWrapper->setPowerHintSessionThreadIds(const_cast<std::vector<int32_t>&>(threadIds));
+ halWrapper->setTargetWorkDuration(targetDurationNanos - kTargetSafetyMargin.count());
}
}
}
@@ -227,6 +199,21 @@
mPowerHintEnabled = enabled;
}
+bool PowerAdvisor::startPowerHintSession(const std::vector<int32_t>& threadIds) {
+ if (!usePowerHintSession()) {
+ ALOGI("Power hint session cannot be started, skipping");
+ }
+ {
+ std::lock_guard lock(mPowerHalMutex);
+ HalWrapper* halWrapper = getPowerHal();
+ if (halWrapper != nullptr && usePowerHintSession()) {
+ halWrapper->setPowerHintSessionThreadIds(threadIds);
+ mPowerHintSessionRunning = halWrapper->startPowerHintSession();
+ }
+ }
+ return mPowerHintSessionRunning;
+}
+
class HidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
public:
HidlPowerHalWrapper(sp<V1_3::IPower> powerHal) : mPowerHal(std::move(powerHal)) {}
@@ -307,12 +294,7 @@
mHasDisplayUpdateImminent = false;
}
- // This just gives a number not a binder status, so no .isOk()
- mSupportsPowerHints = mPowerHal->getInterfaceVersion() >= 2;
-
- if (mSupportsPowerHints) {
- mPowerHintQueue.reserve(MAX_QUEUE_SIZE);
- }
+ mSupportsPowerHint = checkPowerHintSessionSupported();
}
~AidlPowerHalWrapper() override {
@@ -356,7 +338,14 @@
}
// only version 2+ of the aidl supports power hint sessions, hidl has no support
- bool supportsPowerHintSession() override { return mSupportsPowerHints; }
+ bool supportsPowerHintSession() override { return mSupportsPowerHint; }
+
+ bool checkPowerHintSessionSupported() {
+ int64_t unused;
+ // Try to get preferred rate to determine if hint sessions are supported
+ // We check for isOk not EX_UNSUPPORTED_OPERATION to lump other errors
+ return mPowerHal->getHintSessionPreferredRate(&unused).isOk();
+ }
bool isPowerHintSessionRunning() override { return mPowerHintSession != nullptr; }
@@ -382,38 +371,43 @@
}
bool startPowerHintSession() override {
- if (mPowerHintSession != nullptr || !mPowerHintTargetDuration.has_value() ||
- mPowerHintThreadIds.empty()) {
+ if (mPowerHintSession != nullptr || mPowerHintThreadIds.empty()) {
ALOGV("Cannot start power hint session, skipping");
return false;
}
auto ret = mPowerHal->createHintSession(getpid(), static_cast<int32_t>(getuid()),
- mPowerHintThreadIds, *mPowerHintTargetDuration,
+ mPowerHintThreadIds, mTargetDuration,
&mPowerHintSession);
if (!ret.isOk()) {
ALOGW("Failed to start power hint session with error: %s",
ret.exceptionToString(ret.exceptionCode()).c_str());
- // Indicate to the poweradvisor that this wrapper likely needs to be remade
- mShouldReconnectHal = true;
+ } else {
+ mLastTargetDurationSent = mTargetDuration;
}
return isPowerHintSessionRunning();
}
bool shouldSetTargetDuration(int64_t targetDurationNanos) {
- if (!mLastTargetDurationSent.has_value()) {
- return true;
- }
-
// report if the change in target from our last submission to now exceeds the threshold
return abs(1.0 -
- static_cast<double>(*mLastTargetDurationSent) /
+ static_cast<double>(mLastTargetDurationSent) /
static_cast<double>(targetDurationNanos)) >=
- ALLOWED_TARGET_DEVIATION_PERCENT;
+ kAllowedTargetDeviationPercent;
}
void setTargetWorkDuration(int64_t targetDurationNanos) override {
- mPowerHintTargetDuration = targetDurationNanos;
- if (shouldSetTargetDuration(targetDurationNanos) && isPowerHintSessionRunning()) {
+ ATRACE_CALL();
+ mTargetDuration = targetDurationNanos;
+ if (sTraceHintSessionData) ATRACE_INT64("Time target", targetDurationNanos);
+ if (!sNormalizeTarget && shouldSetTargetDuration(targetDurationNanos) &&
+ isPowerHintSessionRunning()) {
+ if (mLastActualDurationSent.has_value()) {
+ // update the error term here since we are actually sending an update to powerhal
+ if (sTraceHintSessionData)
+ ATRACE_INT64("Target error term",
+ targetDurationNanos - *mLastActualDurationSent);
+ }
+ ALOGV("Sending target time: %lld ns", static_cast<long long>(targetDurationNanos));
mLastTargetDurationSent = targetDurationNanos;
auto ret = mPowerHintSession->updateTargetWorkDuration(targetDurationNanos);
if (!ret.isOk()) {
@@ -425,24 +419,29 @@
}
bool shouldReportActualDurationsNow() {
- // report if we have never reported before or have exceeded the max queue size
- if (!mLastMessageReported.has_value() || mPowerHintQueue.size() >= MAX_QUEUE_SIZE) {
+ // report if we have never reported before or are approaching a stale session
+ if (!mLastActualDurationSent.has_value() ||
+ (systemTime() - mLastActualReportTimestamp) > kStaleTimeout.count()) {
return true;
}
+ if (!mActualDuration.has_value()) {
+ return false;
+ }
+
// duration of most recent timing
- const double mostRecentActualDuration =
- static_cast<double>(mPowerHintQueue.back().durationNanos);
+ const double mostRecentActualDuration = static_cast<double>(*mActualDuration);
// duration of the last timing actually reported to the powerhal
- const double lastReportedActualDuration =
- static_cast<double>(mLastMessageReported->durationNanos);
+ const double lastReportedActualDuration = static_cast<double>(*mLastActualDurationSent);
// report if the change in duration from then to now exceeds the threshold
return abs(1.0 - mostRecentActualDuration / lastReportedActualDuration) >=
- ALLOWED_ACTUAL_DEVIATION_PERCENT;
+ kAllowedActualDeviationPercent;
}
void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timeStampNanos) override {
+ ATRACE_CALL();
+
if (actualDurationNanos < 0 || !isPowerHintSessionRunning()) {
ALOGV("Failed to send actual work duration, skipping");
return;
@@ -450,13 +449,32 @@
WorkDuration duration;
duration.durationNanos = actualDurationNanos;
+ mActualDuration = actualDurationNanos;
+
+ // normalize the sent values to a pre-set target
+ if (sNormalizeTarget) {
+ duration.durationNanos += mLastTargetDurationSent - mTargetDuration;
+ }
duration.timeStampNanos = timeStampNanos;
mPowerHintQueue.push_back(duration);
+ long long targetNsec = mTargetDuration;
+ long long durationNsec = actualDurationNanos;
+
+ if (sTraceHintSessionData) {
+ ATRACE_INT64("Measured duration", durationNsec);
+ ATRACE_INT64("Target error term", targetNsec - durationNsec);
+ }
+
+ ALOGV("Sending actual work duration of: %lld on target: %lld with error: %lld",
+ durationNsec, targetNsec, targetNsec - durationNsec);
+
// This rate limiter queues similar duration reports to the powerhal into
// batches to avoid excessive binder calls. The criteria to send a given batch
// are outlined in shouldReportActualDurationsNow()
if (shouldReportActualDurationsNow()) {
+ ALOGV("Sending hint update batch");
+ mLastActualReportTimestamp = systemTime();
auto ret = mPowerHintSession->reportActualWorkDuration(mPowerHintQueue);
if (!ret.isOk()) {
ALOGW("Failed to report actual work durations with error: %s",
@@ -464,7 +482,8 @@
mShouldReconnectHal = true;
}
mPowerHintQueue.clear();
- mLastMessageReported = duration;
+ // we save the non-normalized value here to detect % changes
+ mLastActualDurationSent = actualDurationNanos;
}
}
@@ -472,32 +491,51 @@
std::vector<int32_t> getPowerHintSessionThreadIds() override { return mPowerHintThreadIds; }
- std::optional<int64_t> getTargetWorkDuration() override { return mPowerHintTargetDuration; }
+ std::optional<int64_t> getTargetWorkDuration() override { return mTargetDuration; }
private:
- // max number of messages allowed in mPowerHintQueue before reporting is forced
- static constexpr int32_t MAX_QUEUE_SIZE = 15;
- // max percent the actual duration can vary without causing a report (eg: 0.1 = 10%)
- static constexpr double ALLOWED_ACTUAL_DEVIATION_PERCENT = 0.1;
- // max percent the target duration can vary without causing a report (eg: 0.05 = 5%)
- static constexpr double ALLOWED_TARGET_DEVIATION_PERCENT = 0.05;
-
const sp<IPower> mPowerHal = nullptr;
bool mHasExpensiveRendering = false;
bool mHasDisplayUpdateImminent = false;
- bool mShouldReconnectHal = false; // used to indicate an error state and need for reconstruction
+ // Used to indicate an error state and need for reconstruction
+ bool mShouldReconnectHal = false;
// This is not thread safe, but is currently protected by mPowerHalMutex so it needs no lock
sp<IPowerHintSession> mPowerHintSession = nullptr;
+ // Queue of actual durations saved to report
std::vector<WorkDuration> mPowerHintQueue;
- // halwrapper owns these values so we can init when we want and reconnect if broken
- std::optional<int64_t> mPowerHintTargetDuration;
+ // The latest un-normalized values we have received for target and actual
+ int64_t mTargetDuration = kDefaultTarget.count();
+ std::optional<int64_t> mActualDuration;
+ // The list of thread ids, stored so we can restart the session from this class if needed
std::vector<int32_t> mPowerHintThreadIds;
- // keep track of the last messages sent for rate limiter change detection
- std::optional<WorkDuration> mLastMessageReported;
- std::optional<int64_t> mLastTargetDurationSent;
- bool mSupportsPowerHints;
+ bool mSupportsPowerHint;
+ // Keep track of the last messages sent for rate limiter change detection
+ std::optional<int64_t> mLastActualDurationSent;
+ // timestamp of the last report we sent, used to avoid stale sessions
+ int64_t mLastActualReportTimestamp = 0;
+ int64_t mLastTargetDurationSent = kDefaultTarget.count();
+ // Whether to normalize all the actual values as error terms relative to a constant target
+ // This saves a binder call by not setting the target, and should not affect the pid values
+ static const bool sNormalizeTarget;
+ // Whether we should emit ATRACE_INT data for hint sessions
+ static const bool sTraceHintSessionData;
+ // Max percent the actual duration can vary without causing a report (eg: 0.1 = 10%)
+ static constexpr double kAllowedActualDeviationPercent = 0.1;
+ // Max percent the target duration can vary without causing a report (eg: 0.05 = 5%)
+ static constexpr double kAllowedTargetDeviationPercent = 0.05;
+ // Target used for init and normalization, the actual value does not really matter
+ static constexpr const std::chrono::nanoseconds kDefaultTarget = 50ms;
+ // amount of time after the last message was sent before the session goes stale
+ // actually 100ms but we use 80 here to ideally avoid going stale
+ static constexpr const std::chrono::nanoseconds kStaleTimeout = 80ms;
};
+const bool AidlPowerHalWrapper::sTraceHintSessionData =
+ base::GetBoolProperty(std::string("debug.sf.trace_hint_sessions"), false);
+
+const bool AidlPowerHalWrapper::sNormalizeTarget =
+ base::GetBoolProperty(std::string("debug.sf.normalize_hint_session_durations"), true);
+
PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() {
static std::unique_ptr<HalWrapper> sHalWrapper = nullptr;
static bool sHasHal = true;
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index b8fd17d..28d28f4 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -17,6 +17,7 @@
#pragma once
#include <atomic>
+#include <chrono>
#include <unordered_set>
#include <utils/Mutex.h>
@@ -24,6 +25,8 @@
#include "../Scheduler/OneShotTimer.h"
#include "DisplayIdentification.h"
+using namespace std::chrono_literals;
+
namespace android {
class SurfaceFlinger;
@@ -44,9 +47,9 @@
virtual bool supportsPowerHintSession() = 0;
virtual bool isPowerHintSessionRunning() = 0;
virtual void setTargetWorkDuration(int64_t targetDurationNanos) = 0;
- virtual void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) = 0;
virtual void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timestamp) = 0;
virtual void enablePowerHint(bool enabled) = 0;
+ virtual bool startPowerHintSession(const std::vector<int32_t>& threadIds) = 0;
};
namespace impl {
@@ -86,9 +89,9 @@
bool supportsPowerHintSession() override;
bool isPowerHintSessionRunning() override;
void setTargetWorkDuration(int64_t targetDurationNanos) override;
- void setPowerHintSessionThreadIds(const std::vector<int32_t>& threadIds) override;
void sendActualWorkDuration(int64_t actualDurationNanos, nsecs_t timestamp) override;
void enablePowerHint(bool enabled) override;
+ bool startPowerHintSession(const std::vector<int32_t>& threadIds) override;
private:
HalWrapper* getPowerHal() REQUIRES(mPowerHalMutex);
@@ -100,6 +103,12 @@
std::optional<bool> mSupportsPowerHint;
bool mPowerHintSessionRunning = false;
+ // An adjustable safety margin which moves the "target" earlier to allow flinger to
+ // go a bit over without dropping a frame, especially since we can't measure
+ // the exact time HWC finishes composition so "actual" durations are measured
+ // from the end of present() instead, which is a bit later.
+ static constexpr const std::chrono::nanoseconds kTargetSafetyMargin = 2ms;
+
std::unordered_set<DisplayId> mExpensiveDisplays;
bool mNotifiedExpensiveRendering = false;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 5948a78..fa2c92d 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -101,7 +101,9 @@
if (args.flags & ISurfaceComposerClient::eSecure) layerFlags |= layer_state_t::eLayerSecure;
if (args.flags & ISurfaceComposerClient::eSkipScreenshot)
layerFlags |= layer_state_t::eLayerSkipScreenshot;
-
+ if (args.sequence) {
+ sSequence = *args.sequence + 1;
+ }
mDrawingState.flags = layerFlags;
mDrawingState.active_legacy.transform.set(0, 0);
mDrawingState.crop.makeInvalid();
@@ -2022,9 +2024,9 @@
void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags,
const DisplayDevice* display) {
const ui::Transform transform = getTransform();
- auto buffer = getBuffer();
+ auto buffer = getExternalTexture();
if (buffer != nullptr) {
- LayerProtoHelper::writeToProto(buffer,
+ LayerProtoHelper::writeToProto(*buffer,
[&]() { return layerInfo->mutable_active_buffer(); });
LayerProtoHelper::writeToProtoDeprecated(ui::Transform(getBufferTransform()),
layerInfo->mutable_buffer_transform());
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 31cdf0b..4cdd8fa 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -416,8 +416,10 @@
// Used only to set BufferStateLayer state
virtual bool setTransform(uint32_t /*transform*/) { return false; };
virtual bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/) { return false; };
- virtual bool setBuffer(const BufferData&, nsecs_t /*postTime*/, nsecs_t /*desiredPresentTime*/,
- bool /*isAutoTimestamp*/, std::optional<nsecs_t> /* dequeueTime */,
+ virtual bool setBuffer(std::shared_ptr<renderengine::ExternalTexture>& /* buffer */,
+ const BufferData& /* bufferData */, nsecs_t /* postTime */,
+ nsecs_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/,
+ std::optional<nsecs_t> /* dequeueTime */,
const FrameTimelineInfo& /*info*/) {
return false;
};
@@ -563,6 +565,9 @@
virtual uint32_t getBufferTransform() const { return 0; }
virtual sp<GraphicBuffer> getBuffer() const { return nullptr; }
+ virtual const std::shared_ptr<renderengine::ExternalTexture>& getExternalTexture() const {
+ return mDrawingState.buffer;
+ };
virtual ui::Transform::RotationFlags getTransformHint() const { return ui::Transform::ROT_0; }
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index ee23561..015caa6 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -154,16 +154,16 @@
}
}
-void LayerProtoHelper::writeToProto(const sp<GraphicBuffer>& buffer,
+void LayerProtoHelper::writeToProto(const renderengine::ExternalTexture& buffer,
std::function<ActiveBufferProto*()> getActiveBufferProto) {
- if (buffer->getWidth() != 0 || buffer->getHeight() != 0 || buffer->getStride() != 0 ||
- buffer->format != 0) {
+ if (buffer.getBuffer()->getWidth() != 0 || buffer.getBuffer()->getHeight() != 0 ||
+ buffer.getBuffer()->getUsage() != 0 || buffer.getBuffer()->getPixelFormat() != 0) {
// Use a lambda do avoid writing the object header when the object is empty
ActiveBufferProto* activeBufferProto = getActiveBufferProto();
- activeBufferProto->set_width(buffer->getWidth());
- activeBufferProto->set_height(buffer->getHeight());
- activeBufferProto->set_stride(buffer->getStride());
- activeBufferProto->set_format(buffer->format);
+ activeBufferProto->set_width(buffer.getBuffer()->getWidth());
+ activeBufferProto->set_height(buffer.getBuffer()->getHeight());
+ activeBufferProto->set_format(buffer.getBuffer()->getPixelFormat());
+ activeBufferProto->set_usage(buffer.getBuffer()->getUsage());
}
}
diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h
index 249ec42..6ade143 100644
--- a/services/surfaceflinger/LayerProtoHelper.h
+++ b/services/surfaceflinger/LayerProtoHelper.h
@@ -15,6 +15,7 @@
*/
#include <layerproto/LayerProtoHeader.h>
+#include <renderengine/ExternalTexture.h>
#include <Layer.h>
#include <gui/WindowInfo.h>
@@ -48,7 +49,7 @@
TransformProto* transformProto);
static void writeTransformToProto(const ui::Transform& transform,
TransformProto* transformProto);
- static void writeToProto(const sp<GraphicBuffer>& buffer,
+ static void writeToProto(const renderengine::ExternalTexture& buffer,
std::function<ActiveBufferProto*()> getActiveBufferProto);
static void writeToProto(const gui::WindowInfo& inputInfo,
const wp<Layer>& touchableRegionBounds,
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index da8c3e0..ff30348 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -31,6 +31,7 @@
#include <cutils/properties.h>
#include <ftl/future.h>
#include <gui/SyncScreenCaptureListener.h>
+#include <renderengine/impl/ExternalTexture.h>
#include <ui/DisplayStatInfo.h>
#include <utils/Trace.h>
@@ -351,8 +352,9 @@
LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureSample: Buffer failed to allocate: %d",
bufferStatus);
buffer = std::make_shared<
- renderengine::ExternalTexture>(graphicBuffer, mFlinger.getRenderEngine(),
- renderengine::ExternalTexture::Usage::WRITEABLE);
+ renderengine::impl::ExternalTexture>(graphicBuffer, mFlinger.getRenderEngine(),
+ renderengine::impl::ExternalTexture::Usage::
+ WRITEABLE);
}
auto captureScreenResultFuture =
diff --git a/services/surfaceflinger/Scheduler/Android.bp b/services/surfaceflinger/Scheduler/Android.bp
index 409d098..5de796d 100644
--- a/services/surfaceflinger/Scheduler/Android.bp
+++ b/services/surfaceflinger/Scheduler/Android.bp
@@ -16,6 +16,8 @@
],
shared_libs: [
"libbase",
+ "libcutils",
+ "liblog",
"libutils",
],
}
@@ -26,10 +28,36 @@
export_include_dirs: ["include"],
}
+// TODO(b/185535769): Remove libsurfaceflinger_unittest's dependency on AsyncCallRecorder.
+cc_library_headers {
+ name: "libscheduler_test_headers",
+ defaults: ["libscheduler_defaults"],
+ export_include_dirs: ["tests"],
+}
+
cc_library_static {
name: "libscheduler",
defaults: ["libscheduler_defaults"],
- srcs: [],
+ srcs: [
+ "src/Timer.cpp",
+ ],
local_include_dirs: ["include"],
export_include_dirs: ["include"],
}
+
+cc_test {
+ name: "libscheduler_test",
+ test_suites: ["device-tests"],
+ defaults: ["libscheduler_defaults"],
+ srcs: [
+ "tests/TimerTest.cpp",
+ ],
+ static_libs: [
+ "libgmock",
+ "libgtest",
+ "libscheduler",
+ ],
+ sanitize: {
+ address: true,
+ },
+}
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 74a2ca7..0efc28b 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -33,7 +33,6 @@
#include "../Layer.h"
#include "LayerInfo.h"
-#include "SchedulerUtils.h"
namespace android::scheduler {
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h
index 2d88a4f..8a3b0b9 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.h
+++ b/services/surfaceflinger/Scheduler/LayerInfo.h
@@ -29,7 +29,6 @@
#include "LayerHistory.h"
#include "RefreshRateConfigs.h"
-#include "SchedulerUtils.h"
namespace android {
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 71d5631..42dc539 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -618,7 +618,7 @@
const auto [refreshRate, score] = *i;
ALOGV("%s scores %.2f", refreshRate->getName().c_str(), score);
- ATRACE_INT(refreshRate->getName().c_str(), round<int>(score * 100));
+ ATRACE_INT(refreshRate->getName().c_str(), static_cast<int>(std::round(score * 100)));
if (score > max * (1 + kEpsilon)) {
max = score;
@@ -714,20 +714,19 @@
void RefreshRateConfigs::initializeIdleTimer() {
if (mConfig.idleTimerTimeoutMs > 0) {
- const auto getCallback = [this]() -> std::optional<IdleTimerCallbacks::Callbacks> {
- std::scoped_lock lock(mIdleTimerCallbacksMutex);
- if (!mIdleTimerCallbacks.has_value()) return {};
- return mConfig.supportKernelIdleTimer ? mIdleTimerCallbacks->kernel
- : mIdleTimerCallbacks->platform;
- };
-
mIdleTimer.emplace(
"IdleTimer", std::chrono::milliseconds(mConfig.idleTimerTimeoutMs),
- [getCallback] {
- if (const auto callback = getCallback()) callback->onReset();
+ [this] {
+ std::scoped_lock lock(mIdleTimerCallbacksMutex);
+ if (const auto callbacks = getIdleTimerCallbacks()) {
+ callbacks->onReset();
+ }
},
- [getCallback] {
- if (const auto callback = getCallback()) callback->onExpired();
+ [this] {
+ std::scoped_lock lock(mIdleTimerCallbacksMutex);
+ if (const auto callbacks = getIdleTimerCallbacks()) {
+ callbacks->onExpired();
+ }
});
}
}
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 4bbdab6..de5afb7 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -30,7 +30,6 @@
#include "DisplayHardware/DisplayMode.h"
#include "DisplayHardware/HWComposer.h"
#include "Scheduler/OneShotTimer.h"
-#include "Scheduler/SchedulerUtils.h"
#include "Scheduler/StrongTyping.h"
namespace android::scheduler {
@@ -348,16 +347,24 @@
bool supportsKernelIdleTimer() const { return mConfig.supportKernelIdleTimer; }
- void setIdleTimerCallbacks(std::function<void()> platformTimerReset,
- std::function<void()> platformTimerExpired,
- std::function<void()> kernelTimerReset,
- std::function<void()> kernelTimerExpired) {
+ struct IdleTimerCallbacks {
+ struct Callbacks {
+ std::function<void()> onReset;
+ std::function<void()> onExpired;
+ };
+
+ Callbacks platform;
+ Callbacks kernel;
+ };
+
+ void setIdleTimerCallbacks(IdleTimerCallbacks callbacks) EXCLUDES(mIdleTimerCallbacksMutex) {
std::scoped_lock lock(mIdleTimerCallbacksMutex);
- mIdleTimerCallbacks.emplace();
- mIdleTimerCallbacks->platform.onReset = std::move(platformTimerReset);
- mIdleTimerCallbacks->platform.onExpired = std::move(platformTimerExpired);
- mIdleTimerCallbacks->kernel.onReset = std::move(kernelTimerReset);
- mIdleTimerCallbacks->kernel.onExpired = std::move(kernelTimerExpired);
+ mIdleTimerCallbacks = std::move(callbacks);
+ }
+
+ void clearIdleTimerCallbacks() EXCLUDES(mIdleTimerCallbacksMutex) {
+ std::scoped_lock lock(mIdleTimerCallbacksMutex);
+ mIdleTimerCallbacks.reset();
}
void startIdleTimer() {
@@ -380,7 +387,7 @@
return;
}
mIdleTimer->reset();
- };
+ }
void dump(std::string& result) const EXCLUDES(mLock);
@@ -448,6 +455,13 @@
void initializeIdleTimer();
+ std::optional<IdleTimerCallbacks::Callbacks> getIdleTimerCallbacks() const
+ REQUIRES(mIdleTimerCallbacksMutex) {
+ if (!mIdleTimerCallbacks) return {};
+ return mConfig.supportKernelIdleTimer ? mIdleTimerCallbacks->kernel
+ : mIdleTimerCallbacks->platform;
+ }
+
// The list of refresh rates, indexed by display modes ID. This may change after this
// object is initialized.
AllRefreshRatesMapType mRefreshRates GUARDED_BY(mLock);
@@ -492,21 +506,11 @@
mutable std::optional<GetBestRefreshRateInvocation> lastBestRefreshRateInvocation
GUARDED_BY(mLock);
- // Timer that records time between requests for next vsync.
- std::optional<scheduler::OneShotTimer> mIdleTimer;
-
- struct IdleTimerCallbacks {
- struct Callbacks {
- std::function<void()> onReset;
- std::function<void()> onExpired;
- };
-
- Callbacks platform;
- Callbacks kernel;
- };
-
+ // Declare mIdleTimer last to ensure its thread joins before the mutex/callbacks are destroyed.
std::mutex mIdleTimerCallbacksMutex;
std::optional<IdleTimerCallbacks> mIdleTimerCallbacks GUARDED_BY(mIdleTimerCallbacksMutex);
+ // Used to detect (lack of) frame activity.
+ std::optional<scheduler::OneShotTimer> mIdleTimer;
};
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h
index 23ebb06..f1ad755 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateStats.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h
@@ -25,7 +25,6 @@
#include <scheduler/Fps.h>
-#include "Scheduler/SchedulerUtils.h"
#include "TimeStats/TimeStats.h"
namespace android::scheduler {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index cbe4552..d4b3917 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -44,7 +44,6 @@
#include "EventThread.h"
#include "InjectVSyncSource.h"
#include "OneShotTimer.h"
-#include "SchedulerUtils.h"
#include "SurfaceFlingerProperties.h"
#include "VSyncPredictor.h"
#include "VSyncReactor.h"
@@ -62,6 +61,15 @@
Scheduler::Scheduler(ICompositor& compositor, ISchedulerCallback& callback, FeatureFlags features)
: impl::MessageQueue(compositor), mFeatures(features), mSchedulerCallback(callback) {}
+Scheduler::~Scheduler() {
+ // Stop timers and wait for their threads to exit.
+ mDisplayPowerTimer.reset();
+ mTouchTimer.reset();
+
+ // Stop idle timer and clear callbacks, as the RefreshRateConfigs may outlive the Scheduler.
+ setRefreshRateConfigs(nullptr);
+}
+
void Scheduler::startTimers() {
using namespace sysprop;
using namespace std::string_literals;
@@ -84,11 +92,32 @@
}
}
-Scheduler::~Scheduler() {
- // Ensure the OneShotTimer threads are joined before we start destroying state.
- mDisplayPowerTimer.reset();
- mTouchTimer.reset();
- mRefreshRateConfigs.reset();
+void Scheduler::setRefreshRateConfigs(std::shared_ptr<RefreshRateConfigs> configs) {
+ {
+ // The current RefreshRateConfigs instance may outlive this call, so unbind its idle timer.
+ std::scoped_lock lock(mRefreshRateConfigsLock);
+ if (mRefreshRateConfigs) {
+ mRefreshRateConfigs->stopIdleTimer();
+ mRefreshRateConfigs->clearIdleTimerCallbacks();
+ }
+ }
+ {
+ // Clear state that depends on the current instance.
+ std::scoped_lock lock(mPolicyLock);
+ mPolicy = {};
+ }
+
+ std::scoped_lock lock(mRefreshRateConfigsLock);
+ mRefreshRateConfigs = std::move(configs);
+ if (!mRefreshRateConfigs) return;
+
+ mRefreshRateConfigs->setIdleTimerCallbacks(
+ {.platform = {.onReset = [this] { idleTimerCallback(TimerState::Reset); },
+ .onExpired = [this] { idleTimerCallback(TimerState::Expired); }},
+ .kernel = {.onReset = [this] { kernelIdleTimerCallback(TimerState::Reset); },
+ .onExpired = [this] { kernelIdleTimerCallback(TimerState::Expired); }}});
+
+ mRefreshRateConfigs->startIdleTimer();
}
void Scheduler::run() {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 818f1ed..2f3d952 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -17,6 +17,7 @@
#pragma once
#include <atomic>
+#include <cstdint>
#include <functional>
#include <future>
#include <memory>
@@ -38,9 +39,37 @@
#include "MessageQueue.h"
#include "OneShotTimer.h"
#include "RefreshRateConfigs.h"
-#include "SchedulerUtils.h"
#include "VsyncSchedule.h"
+namespace android::scheduler {
+
+// Opaque handle to scheduler connection.
+struct ConnectionHandle {
+ using Id = std::uintptr_t;
+ static constexpr Id INVALID_ID = static_cast<Id>(-1);
+
+ Id id = INVALID_ID;
+
+ explicit operator bool() const { return id != INVALID_ID; }
+};
+
+inline bool operator==(ConnectionHandle lhs, ConnectionHandle rhs) {
+ return lhs.id == rhs.id;
+}
+
+} // namespace android::scheduler
+
+namespace std {
+
+template <>
+struct hash<android::scheduler::ConnectionHandle> {
+ size_t operator()(android::scheduler::ConnectionHandle handle) const {
+ return hash<android::scheduler::ConnectionHandle::Id>()(handle.id);
+ }
+};
+
+} // namespace std
+
namespace android {
class FenceTime;
@@ -74,11 +103,15 @@
public:
Scheduler(ICompositor&, ISchedulerCallback&, FeatureFlags);
- ~Scheduler();
+ virtual ~Scheduler();
+
+ void startTimers();
+ void setRefreshRateConfigs(std::shared_ptr<RefreshRateConfigs>)
+ EXCLUDES(mRefreshRateConfigsLock);
+
+ void run();
void createVsyncSchedule(FeatureFlags);
- void startTimers();
- void run();
using Impl::initVsync;
using Impl::setInjector;
@@ -198,36 +231,6 @@
std::optional<Fps> getFrameRateOverride(uid_t uid) const
EXCLUDES(mRefreshRateConfigsLock, mFrameRateOverridesLock);
- void setRefreshRateConfigs(std::shared_ptr<RefreshRateConfigs> refreshRateConfigs)
- EXCLUDES(mRefreshRateConfigsLock) {
- // We need to stop the idle timer on the previous RefreshRateConfigs instance
- // and cleanup the scheduler's state before we switch to the other RefreshRateConfigs.
- {
- std::scoped_lock lock(mRefreshRateConfigsLock);
- if (mRefreshRateConfigs) mRefreshRateConfigs->stopIdleTimer();
- }
- {
- std::scoped_lock lock(mPolicyLock);
- mPolicy = {};
- }
- {
- std::scoped_lock lock(mRefreshRateConfigsLock);
- mRefreshRateConfigs = std::move(refreshRateConfigs);
- mRefreshRateConfigs->setIdleTimerCallbacks(
- [this] { std::invoke(&Scheduler::idleTimerCallback, this, TimerState::Reset); },
- [this] {
- std::invoke(&Scheduler::idleTimerCallback, this, TimerState::Expired);
- },
- [this] {
- std::invoke(&Scheduler::kernelIdleTimerCallback, this, TimerState::Reset);
- },
- [this] {
- std::invoke(&Scheduler::kernelIdleTimerCallback, this, TimerState::Expired);
- });
- mRefreshRateConfigs->startIdleTimer();
- }
- }
-
nsecs_t getVsyncPeriodFromRefreshRateConfigs() const EXCLUDES(mRefreshRateConfigsLock) {
std::scoped_lock lock(mRefreshRateConfigsLock);
return mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.cpp b/services/surfaceflinger/Scheduler/SchedulerUtils.cpp
deleted file mode 100644
index e8e0444..0000000
--- a/services/surfaceflinger/Scheduler/SchedulerUtils.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "SchedulerUtils.h"
-
-#include <cinttypes>
-#include <numeric>
-#include <unordered_map>
-#include <vector>
-
-namespace android {
-namespace scheduler {
-
-int64_t calculate_median(std::vector<int64_t>* v) {
- if (!v || v->empty()) {
- return 0;
- }
-
- size_t n = v->size() / 2;
- nth_element(v->begin(), v->begin() + static_cast<long>(n), v->end());
- return v->at(n);
-}
-
-} // namespace scheduler
-} // namespace android
-
diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.h b/services/surfaceflinger/Scheduler/SchedulerUtils.h
deleted file mode 100644
index 04a4cd1..0000000
--- a/services/surfaceflinger/Scheduler/SchedulerUtils.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <utils/Timers.h>
-#include <cinttypes>
-#include <numeric>
-#include <unordered_map>
-#include <vector>
-
-namespace android::scheduler {
-
-// Opaque handle to scheduler connection.
-struct ConnectionHandle {
- using Id = std::uintptr_t;
- static constexpr Id INVALID_ID = static_cast<Id>(-1);
-
- Id id = INVALID_ID;
-
- explicit operator bool() const { return id != INVALID_ID; }
-};
-
-inline bool operator==(ConnectionHandle lhs, ConnectionHandle rhs) {
- return lhs.id == rhs.id;
-}
-
-// Calculates the statistical mean (average) in the data structure (array, vector). The
-// function does not modify the contents of the array.
-template <typename T>
-auto calculate_mean(const T& v) {
- using V = typename T::value_type;
- V sum = std::accumulate(v.begin(), v.end(), static_cast<V>(0));
- return sum / static_cast<V>(v.size());
-}
-
-// Calculates the statistical median in the vector. Return 0 if the vector is empty. The
-// function modifies the vector contents.
-int64_t calculate_median(std::vector<int64_t>* v);
-
-// Calculates the statistical mode in the vector. Return 0 if the vector is empty.
-template <typename T>
-auto calculate_mode(const T& v) {
- if (v.empty()) {
- return 0;
- }
-
- // Create a map with all the counts for the indivicual values in the vector.
- std::unordered_map<int64_t, int> counts;
- for (int64_t value : v) {
- counts[value]++;
- }
-
- // Sort the map, and return the number with the highest count. If two numbers have
- // the same count, first one is returned.
- using ValueType = const decltype(counts)::value_type&;
- const auto compareCounts = [](ValueType l, ValueType r) { return l.second <= r.second; };
- return static_cast<int>(std::max_element(counts.begin(), counts.end(), compareCounts)->first);
-}
-
-template <class T, size_t N>
-constexpr size_t arrayLen(T (&)[N]) {
- return N;
-}
-
-static constexpr size_t max64print = std::numeric_limits<nsecs_t>::digits10 + 1;
-
-template <typename T>
-static inline T round(float f) {
- return static_cast<T>(std::round(f));
-}
-
-} // namespace android::scheduler
-
-namespace std {
-
-template <>
-struct hash<android::scheduler::ConnectionHandle> {
- size_t operator()(android::scheduler::ConnectionHandle handle) const {
- return hash<android::scheduler::ConnectionHandle::Id>()(handle.id);
- }
-};
-
-} // namespace std
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatch.h b/services/surfaceflinger/Scheduler/VSyncDispatch.h
index b52706f..2bfe204 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatch.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatch.h
@@ -16,17 +16,15 @@
#pragma once
-#include <utils/Log.h>
-#include <utils/Timers.h>
#include <functional>
#include <optional>
#include <string>
+#include <utils/Timers.h>
+
#include "StrongTyping.h"
namespace android::scheduler {
-class TimeKeeper;
-class VSyncTracker;
using ScheduleResult = std::optional<nsecs_t>;
@@ -64,8 +62,7 @@
* invocation of callbackFn.
*
*/
- virtual CallbackToken registerCallback(Callback const& callbackFn,
- std::string callbackName) = 0;
+ virtual CallbackToken registerCallback(Callback, std::string callbackName) = 0;
/*
* Unregisters a callback.
@@ -142,8 +139,9 @@
protected:
VSyncDispatch() = default;
- VSyncDispatch(VSyncDispatch const&) = delete;
- VSyncDispatch& operator=(VSyncDispatch const&) = delete;
+
+ VSyncDispatch(const VSyncDispatch&) = delete;
+ VSyncDispatch& operator=(const VSyncDispatch&) = delete;
};
/*
@@ -152,11 +150,11 @@
*/
class VSyncCallbackRegistration {
public:
- VSyncCallbackRegistration(VSyncDispatch&, VSyncDispatch::Callback const& callbackFn,
- std::string const& callbackName);
+ VSyncCallbackRegistration(VSyncDispatch&, VSyncDispatch::Callback, std::string callbackName);
+ ~VSyncCallbackRegistration();
+
VSyncCallbackRegistration(VSyncCallbackRegistration&&);
VSyncCallbackRegistration& operator=(VSyncCallbackRegistration&&);
- ~VSyncCallbackRegistration();
// See documentation for VSyncDispatch::schedule.
ScheduleResult schedule(VSyncDispatch::ScheduleTiming scheduleTiming);
@@ -165,9 +163,6 @@
CancelResult cancel();
private:
- VSyncCallbackRegistration(VSyncCallbackRegistration const&) = delete;
- VSyncCallbackRegistration& operator=(VSyncCallbackRegistration const&) = delete;
-
std::reference_wrapper<VSyncDispatch> mDispatch;
VSyncDispatch::CallbackToken mToken;
bool mValidToken;
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
index b805bf6..27f4311 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
@@ -15,18 +15,24 @@
*/
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <android-base/stringprintf.h>
-#include <utils/Trace.h>
+
#include <vector>
-#include "TimeKeeper.h"
+#include <android-base/stringprintf.h>
+#include <ftl/concat.h>
+#include <utils/Trace.h>
+
+#include <scheduler/TimeKeeper.h>
+
#include "VSyncDispatchTimerQueue.h"
#include "VSyncTracker.h"
namespace android::scheduler {
+
using base::StringAppendF;
namespace {
+
nsecs_t getExpectedCallbackTime(nsecs_t nextVsyncTime,
const VSyncDispatch::ScheduleTiming& timing) {
return nextVsyncTime - timing.readyDuration - timing.workDuration;
@@ -38,17 +44,17 @@
std::max(timing.earliestVsync, now + timing.workDuration + timing.readyDuration));
return getExpectedCallbackTime(nextVsyncTime, timing);
}
+
} // namespace
VSyncDispatch::~VSyncDispatch() = default;
VSyncTracker::~VSyncTracker() = default;
-TimeKeeper::~TimeKeeper() = default;
-VSyncDispatchTimerQueueEntry::VSyncDispatchTimerQueueEntry(std::string const& name,
- VSyncDispatch::Callback const& cb,
+VSyncDispatchTimerQueueEntry::VSyncDispatchTimerQueueEntry(std::string name,
+ VSyncDispatch::Callback callback,
nsecs_t minVsyncDistance)
- : mName(name),
- mCallback(cb),
+ : mName(std::move(name)),
+ mCallback(std::move(callback)),
mMinVsyncDistance(minVsyncDistance) {}
std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::lastExecutedVsyncTarget() const {
@@ -222,16 +228,6 @@
rearmTimerSkippingUpdateFor(now, mCallbacks.end());
}
-void VSyncDispatchTimerQueue::TraceBuffer::note(std::string_view name, nsecs_t alarmIn,
- nsecs_t vsFor) {
- if (ATRACE_ENABLED()) {
- snprintf(str_buffer.data(), str_buffer.size(), "%.4s%s%" PRId64 "%s%" PRId64,
- name.substr(0, kMaxNamePrint).data(), kTraceNamePrefix, alarmIn,
- kTraceNameSeparator, vsFor);
- }
- ATRACE_NAME(str_buffer.data());
-}
-
void VSyncDispatchTimerQueue::rearmTimerSkippingUpdateFor(
nsecs_t now, CallbackMap::iterator const& skipUpdateIt) {
std::optional<nsecs_t> min;
@@ -247,16 +243,18 @@
callback->update(mTracker, now);
}
auto const wakeupTime = *callback->wakeupTime();
- if (!min || (min && *min > wakeupTime)) {
+ if (!min || *min > wakeupTime) {
nextWakeupName = callback->name();
min = wakeupTime;
targetVsync = callback->targetVsync();
}
}
- if (min && (min < mIntendedWakeupTime)) {
- if (targetVsync && nextWakeupName) {
- mTraceBuffer.note(*nextWakeupName, *min - now, *targetVsync - now);
+ if (min && min < mIntendedWakeupTime) {
+ if (ATRACE_ENABLED() && nextWakeupName && targetVsync) {
+ ftl::Concat trace(ftl::truncated<5>(*nextWakeupName), " alarm in ", ns2us(*min - now),
+ "us; VSYNC in ", ns2us(*targetVsync - now), "us");
+ ATRACE_NAME(trace.c_str());
}
setTimer(*min, now);
} else {
@@ -305,13 +303,13 @@
}
VSyncDispatchTimerQueue::CallbackToken VSyncDispatchTimerQueue::registerCallback(
- Callback const& callbackFn, std::string callbackName) {
+ Callback callback, std::string callbackName) {
std::lock_guard lock(mMutex);
return CallbackToken{
mCallbacks
.emplace(++mCallbackToken,
- std::make_shared<VSyncDispatchTimerQueueEntry>(callbackName,
- callbackFn,
+ std::make_shared<VSyncDispatchTimerQueueEntry>(std::move(callbackName),
+ std::move(callback),
mMinVsyncDistance))
.first->first};
}
@@ -406,10 +404,10 @@
}
VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncDispatch& dispatch,
- VSyncDispatch::Callback const& callbackFn,
- std::string const& callbackName)
+ VSyncDispatch::Callback callback,
+ std::string callbackName)
: mDispatch(dispatch),
- mToken(dispatch.registerCallback(callbackFn, callbackName)),
+ mToken(dispatch.registerCallback(std::move(callback), std::move(callbackName))),
mValidToken(true) {}
VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncCallbackRegistration&& other)
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
index 26237b6..3186d6d 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
@@ -16,8 +16,6 @@
#pragma once
-#include <android-base/thread_annotations.h>
-#include <array>
#include <functional>
#include <memory>
#include <mutex>
@@ -25,11 +23,14 @@
#include <string_view>
#include <unordered_map>
-#include "SchedulerUtils.h"
+#include <android-base/thread_annotations.h>
+
#include "VSyncDispatch.h"
namespace android::scheduler {
+class VSyncTracker;
+
// VSyncDispatchTimerQueueEntry is a helper class representing internal state for each entry in
// VSyncDispatchTimerQueue hoisted to public for unit testing.
class VSyncDispatchTimerQueueEntry {
@@ -38,7 +39,7 @@
// Valid transition: disarmed -> armed ( when scheduled )
// Valid transition: armed -> running -> disarmed ( when timer is called)
// Valid transition: armed -> disarmed ( when cancelled )
- VSyncDispatchTimerQueueEntry(std::string const& name, VSyncDispatch::Callback const& fn,
+ VSyncDispatchTimerQueueEntry(std::string name, VSyncDispatch::Callback,
nsecs_t minVsyncDistance);
std::string_view name() const;
@@ -47,10 +48,9 @@
std::optional<nsecs_t> lastExecutedVsyncTarget() const;
// This moves the state from disarmed->armed and will calculate the wakeupTime.
- ScheduleResult schedule(VSyncDispatch::ScheduleTiming timing, VSyncTracker& tracker,
- nsecs_t now);
+ ScheduleResult schedule(VSyncDispatch::ScheduleTiming, VSyncTracker&, nsecs_t now);
// This will update armed entries with the latest vsync information. Entry remains armed.
- void update(VSyncTracker& tracker, nsecs_t now);
+ void update(VSyncTracker&, nsecs_t now);
// This will return empty if not armed, or the next calculated wakeup time if armed.
// It will not update the wakeupTime.
@@ -83,11 +83,11 @@
void dump(std::string& result) const;
private:
- std::string const mName;
- VSyncDispatch::Callback const mCallback;
+ const std::string mName;
+ const VSyncDispatch::Callback mCallback;
VSyncDispatch::ScheduleTiming mScheduleTiming;
- nsecs_t const mMinVsyncDistance;
+ const nsecs_t mMinVsyncDistance;
struct ArmingInfo {
nsecs_t mActualWakeupTime;
@@ -117,19 +117,19 @@
// should be grouped into one wakeup.
// \param[in] minVsyncDistance The minimum distance between two vsync estimates before the
// vsyncs are considered the same vsync event.
- explicit VSyncDispatchTimerQueue(std::unique_ptr<TimeKeeper> tk, VSyncTracker& tracker,
- nsecs_t timerSlack, nsecs_t minVsyncDistance);
+ VSyncDispatchTimerQueue(std::unique_ptr<TimeKeeper>, VSyncTracker&, nsecs_t timerSlack,
+ nsecs_t minVsyncDistance);
~VSyncDispatchTimerQueue();
- CallbackToken registerCallback(Callback const& callbackFn, std::string callbackName) final;
- void unregisterCallback(CallbackToken token) final;
- ScheduleResult schedule(CallbackToken token, ScheduleTiming scheduleTiming) final;
- CancelResult cancel(CallbackToken token) final;
- void dump(std::string& result) const final;
+ CallbackToken registerCallback(Callback, std::string callbackName) final;
+ void unregisterCallback(CallbackToken) final;
+ ScheduleResult schedule(CallbackToken, ScheduleTiming) final;
+ CancelResult cancel(CallbackToken) final;
+ void dump(std::string&) const final;
private:
- VSyncDispatchTimerQueue(VSyncDispatchTimerQueue const&) = delete;
- VSyncDispatchTimerQueue& operator=(VSyncDispatchTimerQueue const&) = delete;
+ VSyncDispatchTimerQueue(const VSyncDispatchTimerQueue&) = delete;
+ VSyncDispatchTimerQueue& operator=(const VSyncDispatchTimerQueue&) = delete;
using CallbackMap =
std::unordered_map<CallbackToken, std::shared_ptr<VSyncDispatchTimerQueueEntry>>;
@@ -153,17 +153,6 @@
CallbackMap mCallbacks GUARDED_BY(mMutex);
nsecs_t mIntendedWakeupTime GUARDED_BY(mMutex) = kInvalidTime;
- struct TraceBuffer {
- static constexpr char const kTraceNamePrefix[] = "-alarm in:";
- static constexpr char const kTraceNameSeparator[] = " for vs:";
- static constexpr size_t kMaxNamePrint = 4;
- static constexpr size_t kNumTsPrinted = 2;
- static constexpr size_t maxlen = kMaxNamePrint + arrayLen(kTraceNamePrefix) +
- arrayLen(kTraceNameSeparator) - 1 + (kNumTsPrinted * max64print);
- std::array<char, maxlen> str_buffer;
- void note(std::string_view name, nsecs_t in, nsecs_t vs);
- } mTraceBuffer GUARDED_BY(mMutex);
-
// For debugging purposes
nsecs_t mLastTimerCallback GUARDED_BY(mMutex) = kInvalidTime;
nsecs_t mLastTimerSchedule GUARDED_BY(mMutex) = kInvalidTime;
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index e9bd92a..61d2fb7 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -18,24 +18,27 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wextra"
+#undef LOG_TAG
+#define LOG_TAG "VSyncPredictor"
+
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-//#define LOG_NDEBUG 0
-#include "VSyncPredictor.h"
+
+#include <algorithm>
+#include <chrono>
+#include <sstream>
+
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <cutils/compiler.h>
#include <cutils/properties.h>
#include <utils/Log.h>
#include <utils/Trace.h>
-#include <algorithm>
-#include <chrono>
-#include <sstream>
-#include "RefreshRateConfigs.h"
-#undef LOG_TAG
-#define LOG_TAG "VSyncPredictor"
+#include "RefreshRateConfigs.h"
+#include "VSyncPredictor.h"
namespace android::scheduler {
+
using base::StringAppendF;
static auto constexpr kMaxPercent = 100u;
@@ -121,7 +124,8 @@
mTimestamps[mLastTimestampIndex] = timestamp;
}
- if (mTimestamps.size() < kMinimumSamplesForPrediction) {
+ const size_t numSamples = mTimestamps.size();
+ if (numSamples < kMinimumSamplesForPrediction) {
mRateMap[mIdealPeriod] = {mIdealPeriod, 0};
return true;
}
@@ -141,36 +145,44 @@
//
// intercept = mean(Y) - slope * mean(X)
//
- std::vector<nsecs_t> vsyncTS(mTimestamps.size());
- std::vector<nsecs_t> ordinals(mTimestamps.size());
+ std::vector<nsecs_t> vsyncTS(numSamples);
+ std::vector<nsecs_t> ordinals(numSamples);
- // normalizing to the oldest timestamp cuts down on error in calculating the intercept.
- auto const oldest_ts = *std::min_element(mTimestamps.begin(), mTimestamps.end());
+ // Normalizing to the oldest timestamp cuts down on error in calculating the intercept.
+ const auto oldestTS = *std::min_element(mTimestamps.begin(), mTimestamps.end());
auto it = mRateMap.find(mIdealPeriod);
auto const currentPeriod = it->second.slope;
- // TODO (b/144707443): its important that there's some precision in the mean of the ordinals
- // for the intercept calculation, so scale the ordinals by 1000 to continue
- // fixed point calculation. Explore expanding
- // scheduler::utils::calculate_mean to have a fixed point fractional part.
- static constexpr int64_t kScalingFactor = 1000;
- for (auto i = 0u; i < mTimestamps.size(); i++) {
+ // The mean of the ordinals must be precise for the intercept calculation, so scale them up for
+ // fixed-point arithmetic.
+ constexpr int64_t kScalingFactor = 1000;
+
+ nsecs_t meanTS = 0;
+ nsecs_t meanOrdinal = 0;
+
+ for (size_t i = 0; i < numSamples; i++) {
traceInt64If("VSP-ts", mTimestamps[i]);
- vsyncTS[i] = mTimestamps[i] - oldest_ts;
- ordinals[i] = ((vsyncTS[i] + (currentPeriod / 2)) / currentPeriod) * kScalingFactor;
+ const auto timestamp = mTimestamps[i] - oldestTS;
+ vsyncTS[i] = timestamp;
+ meanTS += timestamp;
+
+ const auto ordinal = (vsyncTS[i] + currentPeriod / 2) / currentPeriod * kScalingFactor;
+ ordinals[i] = ordinal;
+ meanOrdinal += ordinal;
}
- auto meanTS = scheduler::calculate_mean(vsyncTS);
- auto meanOrdinal = scheduler::calculate_mean(ordinals);
- for (size_t i = 0; i < vsyncTS.size(); i++) {
+ meanTS /= numSamples;
+ meanOrdinal /= numSamples;
+
+ for (size_t i = 0; i < numSamples; i++) {
vsyncTS[i] -= meanTS;
ordinals[i] -= meanOrdinal;
}
- auto top = 0ll;
- auto bottom = 0ll;
- for (size_t i = 0; i < vsyncTS.size(); i++) {
+ nsecs_t top = 0;
+ nsecs_t bottom = 0;
+ for (size_t i = 0; i < numSamples; i++) {
top += vsyncTS[i] * ordinals[i];
bottom += ordinals[i] * ordinals[i];
}
@@ -365,4 +377,4 @@
} // namespace android::scheduler
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wextra"
\ No newline at end of file
+#pragma clang diagnostic pop // ignored "-Wextra"
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h
index 40e6944..cfaf7d6 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.h
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h
@@ -16,11 +16,12 @@
#pragma once
-#include <android-base/thread_annotations.h>
#include <mutex>
#include <unordered_map>
#include <vector>
-#include "SchedulerUtils.h"
+
+#include <android-base/thread_annotations.h>
+
#include "VSyncTracker.h"
namespace android::scheduler {
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index 1c9de1c..bdcab51 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -18,21 +18,22 @@
#undef LOG_TAG
#define LOG_TAG "VSyncReactor"
//#define LOG_NDEBUG 0
-#include "VSyncReactor.h"
+
#include <cutils/properties.h>
#include <log/log.h>
#include <utils/Trace.h>
+
#include "../TracedOrdinal.h"
-#include "TimeKeeper.h"
#include "VSyncDispatch.h"
+#include "VSyncReactor.h"
#include "VSyncTracker.h"
namespace android::scheduler {
+
using base::StringAppendF;
VsyncController::~VsyncController() = default;
-Clock::~Clock() = default;
nsecs_t SystemClock::now() const {
return systemTime(SYSTEM_TIME_MONOTONIC);
}
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h
index a9d536b..6a1950a 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.h
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.h
@@ -16,14 +16,18 @@
#pragma once
-#include <android-base/thread_annotations.h>
-#include <ui/FenceTime.h>
#include <memory>
#include <mutex>
#include <unordered_map>
#include <vector>
-#include "TimeKeeper.h"
+
+#include <android-base/thread_annotations.h>
+#include <ui/FenceTime.h>
+
+#include <scheduler/TimeKeeper.h>
+
#include "VsyncController.h"
+
namespace android::scheduler {
class Clock;
diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.cpp b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp
index 77d1223..e611658 100644
--- a/services/surfaceflinger/Scheduler/VsyncSchedule.cpp
+++ b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp
@@ -15,10 +15,10 @@
*/
#include <scheduler/Fps.h>
+#include <scheduler/Timer.h>
#include "VsyncSchedule.h"
-#include "Timer.h"
#include "VSyncDispatchTimerQueue.h"
#include "VSyncPredictor.h"
#include "VSyncReactor.h"
diff --git a/services/surfaceflinger/Scheduler/TimeKeeper.h b/services/surfaceflinger/Scheduler/include/scheduler/TimeKeeper.h
similarity index 81%
rename from services/surfaceflinger/Scheduler/TimeKeeper.h
rename to services/surfaceflinger/Scheduler/include/scheduler/TimeKeeper.h
index 40dd841..319390b 100644
--- a/services/surfaceflinger/Scheduler/TimeKeeper.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/TimeKeeper.h
@@ -16,14 +16,17 @@
#pragma once
-#include <utils/Timers.h>
#include <functional>
+#include <string>
+
+#include <utils/Timers.h>
namespace android::scheduler {
class Clock {
public:
virtual ~Clock();
+
/*
* Returns the SYSTEM_TIME_MONOTONIC, used by testing infra to stub time.
*/
@@ -31,8 +34,9 @@
protected:
Clock() = default;
- Clock(Clock const&) = delete;
- Clock& operator=(Clock const&) = delete;
+
+ Clock(const Clock&) = delete;
+ Clock& operator=(const Clock&) = delete;
};
/*
@@ -46,19 +50,20 @@
* Arms callback to fired when time is current based on CLOCK_MONOTONIC
* There is only one timer, and subsequent calls will reset the callback function and the time.
*/
- virtual void alarmAt(std::function<void()> const& callback, nsecs_t time) = 0;
+ virtual void alarmAt(std::function<void()>, nsecs_t time) = 0;
/*
* Cancels an existing pending callback
*/
virtual void alarmCancel() = 0;
- virtual void dump(std::string& result) const = 0;
+ virtual void dump(std::string&) const = 0;
protected:
- TimeKeeper(TimeKeeper const&) = delete;
- TimeKeeper& operator=(TimeKeeper const&) = delete;
TimeKeeper() = default;
+
+ TimeKeeper(const TimeKeeper&) = delete;
+ TimeKeeper& operator=(const TimeKeeper&) = delete;
};
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/Timer.h b/services/surfaceflinger/Scheduler/include/scheduler/Timer.h
similarity index 80%
rename from services/surfaceflinger/Scheduler/Timer.h
rename to services/surfaceflinger/Scheduler/include/scheduler/Timer.h
index 628d800..58ad6cb 100644
--- a/services/surfaceflinger/Scheduler/Timer.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/Timer.h
@@ -16,11 +16,14 @@
#pragma once
-#include "TimeKeeper.h"
+#include <array>
+#include <functional>
+#include <mutex>
+#include <thread>
#include <android-base/thread_annotations.h>
-#include <array>
-#include <thread>
+
+#include <scheduler/TimeKeeper.h>
namespace android::scheduler {
@@ -28,13 +31,19 @@
public:
Timer();
~Timer();
+
nsecs_t now() const final;
// NB: alarmAt and alarmCancel are threadsafe; with the last-returning function being effectual
// Most users will want to serialize thes calls so as to be aware of the timer state.
- void alarmAt(std::function<void()> const& cb, nsecs_t time) final;
+ void alarmAt(std::function<void()>, nsecs_t time) final;
void alarmCancel() final;
- void dump(std::string& result) const final;
+
+ void dump(std::string&) const final;
+
+protected:
+ // For unit testing
+ int mEpollFd = -1;
private:
enum class DebugState {
@@ -48,12 +57,12 @@
ftl_last = Terminated
};
- void reset();
- void cleanup();
- void setDebugState(DebugState state) EXCLUDES(mMutex);
+ void reset() EXCLUDES(mMutex);
+ void cleanup() REQUIRES(mMutex);
+ void setDebugState(DebugState) EXCLUDES(mMutex);
int mTimerFd = -1;
- int mEpollFd = -1;
+
std::array<int, 2> mPipes = {-1, -1};
std::thread mDispatchThread;
@@ -63,6 +72,7 @@
mutable std::mutex mMutex;
std::function<void()> mCallback GUARDED_BY(mMutex);
+ bool mExpectingCallback GUARDED_BY(mMutex) = false;
DebugState mDebugState GUARDED_BY(mMutex);
};
diff --git a/services/surfaceflinger/Scheduler/Timer.cpp b/services/surfaceflinger/Scheduler/src/Timer.cpp
similarity index 81%
rename from services/surfaceflinger/Scheduler/Timer.cpp
rename to services/surfaceflinger/Scheduler/src/Timer.cpp
index 22c3a70..a4cf57f 100644
--- a/services/surfaceflinger/Scheduler/Timer.cpp
+++ b/services/surfaceflinger/Scheduler/src/Timer.cpp
@@ -16,7 +16,6 @@
#undef LOG_TAG
#define LOG_TAG "SchedulerTimer"
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <chrono>
#include <cstdint>
@@ -25,19 +24,20 @@
#include <sys/timerfd.h>
#include <sys/unistd.h>
-#include <android-base/stringprintf.h>
+#include <ftl/concat.h>
#include <ftl/enum.h>
#include <log/log.h>
#include <utils/Trace.h>
-#include "SchedulerUtils.h"
-#include "Timer.h"
+#include <scheduler/Timer.h>
namespace android::scheduler {
-using base::StringAppendF;
-static constexpr size_t kReadPipe = 0;
-static constexpr size_t kWritePipe = 1;
+constexpr size_t kReadPipe = 0;
+constexpr size_t kWritePipe = 1;
+
+Clock::~Clock() = default;
+TimeKeeper::~TimeKeeper() = default;
Timer::Timer() {
reset();
@@ -51,13 +51,25 @@
}
void Timer::reset() {
- cleanup();
- mTimerFd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
- mEpollFd = epoll_create1(EPOLL_CLOEXEC);
- if (pipe2(mPipes.data(), O_CLOEXEC | O_NONBLOCK)) {
- ALOGE("could not create TimerDispatch mPipes");
- return;
- };
+ std::function<void()> cb;
+ {
+ std::lock_guard lock(mMutex);
+ if (mExpectingCallback && mCallback) {
+ cb = mCallback;
+ }
+
+ cleanup();
+ mTimerFd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
+ mEpollFd = epoll_create1(EPOLL_CLOEXEC);
+ if (pipe2(mPipes.data(), O_CLOEXEC | O_NONBLOCK)) {
+ ALOGE("could not create TimerDispatch mPipes");
+ }
+ }
+ if (cb) {
+ setDebugState(DebugState::InCallback);
+ cb();
+ setDebugState(DebugState::Running);
+ }
setDebugState(DebugState::Reset);
}
@@ -81,6 +93,8 @@
close(mPipes[kWritePipe]);
mPipes[kWritePipe] = -1;
}
+ mExpectingCallback = false;
+ mCallback = {};
}
void Timer::endDispatch() {
@@ -92,13 +106,14 @@
return systemTime(SYSTEM_TIME_MONOTONIC);
}
-void Timer::alarmAt(std::function<void()> const& cb, nsecs_t time) {
+void Timer::alarmAt(std::function<void()> callback, nsecs_t time) {
std::lock_guard lock(mMutex);
using namespace std::literals;
static constexpr int ns_per_s =
std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count();
- mCallback = cb;
+ mCallback = std::move(callback);
+ mExpectingCallback = true;
struct itimerspec old_timer;
struct itimerspec new_timer {
@@ -165,9 +180,6 @@
}
uint64_t iteration = 0;
- char const traceNamePrefix[] = "TimerIteration #";
- static constexpr size_t maxlen = arrayLen(traceNamePrefix) + max64print;
- std::array<char, maxlen> str_buffer;
while (true) {
setDebugState(DebugState::Waiting);
@@ -176,9 +188,8 @@
setDebugState(DebugState::Running);
if (ATRACE_ENABLED()) {
- snprintf(str_buffer.data(), str_buffer.size(), "%s%" PRIu64, traceNamePrefix,
- iteration++);
- ATRACE_NAME(str_buffer.data());
+ ftl::Concat trace("TimerIteration #", iteration++);
+ ATRACE_NAME(trace.c_str());
}
if (nfds == -1) {
@@ -198,6 +209,7 @@
{
std::lock_guard lock(mMutex);
cb = mCallback;
+ mExpectingCallback = false;
}
if (cb) {
setDebugState(DebugState::InCallback);
@@ -221,7 +233,9 @@
void Timer::dump(std::string& result) const {
std::lock_guard lock(mMutex);
- StringAppendF(&result, "\t\tDebugState: %s\n", ftl::enum_string(mDebugState).c_str());
+ result.append("\t\tDebugState: ");
+ result.append(ftl::enum_string(mDebugState));
+ result.push_back('\n');
}
} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/AsyncCallRecorder.h b/services/surfaceflinger/Scheduler/tests/AsyncCallRecorder.h
similarity index 98%
rename from services/surfaceflinger/tests/unittests/AsyncCallRecorder.h
rename to services/surfaceflinger/Scheduler/tests/AsyncCallRecorder.h
index 8bed766..57f0dab 100644
--- a/services/surfaceflinger/tests/unittests/AsyncCallRecorder.h
+++ b/services/surfaceflinger/Scheduler/tests/AsyncCallRecorder.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/services/surfaceflinger/tests/unittests/TimerTest.cpp b/services/surfaceflinger/Scheduler/tests/TimerTest.cpp
similarity index 61%
rename from services/surfaceflinger/tests/unittests/TimerTest.cpp
rename to services/surfaceflinger/Scheduler/tests/TimerTest.cpp
index cda6bbf..47d968c 100644
--- a/services/surfaceflinger/tests/unittests/TimerTest.cpp
+++ b/services/surfaceflinger/Scheduler/tests/TimerTest.cpp
@@ -14,32 +14,48 @@
* limitations under the License.
*/
-#include "AsyncCallRecorder.h"
-#include "Scheduler/TimeKeeper.h"
-#include "Scheduler/Timer.h"
-
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-using namespace testing;
-using namespace std::literals;
+#include <scheduler/TimeKeeper.h>
+#include <scheduler/Timer.h>
+
+#include "AsyncCallRecorder.h"
namespace android::scheduler {
+struct TestableTimer : public Timer {
+public:
+ void makeEpollError() {
+ // close the epoll file descriptor to cause an epoll error
+ close(mEpollFd);
+ }
+};
+
struct TimerTest : testing::Test {
- static constexpr int mIterations = 20;
+ static constexpr int kIterations = 20;
AsyncCallRecorder<void (*)()> mCallbackRecorder;
- Timer mTimer;
+ TestableTimer mTimer;
void timerCallback() { mCallbackRecorder.recordCall(); }
};
TEST_F(TimerTest, callsCallbackIfScheduledInPast) {
- for (int i = 0; i < mIterations; i++) {
- mTimer.alarmAt(std::bind(&TimerTest::timerCallback, this), systemTime() - 10'000'00);
+ for (int i = 0; i < kIterations; i++) {
+ mTimer.alarmAt(std::bind(&TimerTest::timerCallback, this), systemTime() - 1'000'000);
EXPECT_TRUE(mCallbackRecorder.waitForCall().has_value());
EXPECT_FALSE(mCallbackRecorder.waitForUnexpectedCall().has_value());
}
}
+
+TEST_F(TimerTest, recoversAfterEpollError) {
+ for (int i = 0; i < kIterations; i++) {
+ mTimer.makeEpollError();
+ mTimer.alarmAt(std::bind(&TimerTest::timerCallback, this), systemTime() - 1'000'000);
+ EXPECT_TRUE(mCallbackRecorder.waitForCall().has_value());
+ EXPECT_FALSE(mCallbackRecorder.waitForUnexpectedCall().has_value());
+ }
+}
+
} // namespace android::scheduler
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a6eeda2..38d9f10 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -65,6 +65,7 @@
#include <private/gui/SyncFeatures.h>
#include <processgroup/processgroup.h>
#include <renderengine/RenderEngine.h>
+#include <renderengine/impl/ExternalTexture.h>
#include <sys/types.h>
#include <ui/ColorSpace.h>
#include <ui/DataspaceUtils.h>
@@ -339,7 +340,6 @@
ui::PixelFormat SurfaceFlinger::defaultCompositionPixelFormat = ui::PixelFormat::RGBA_8888;
Dataspace SurfaceFlinger::wideColorGamutCompositionDataspace = Dataspace::V0_SRGB;
ui::PixelFormat SurfaceFlinger::wideColorGamutCompositionPixelFormat = ui::PixelFormat::RGBA_8888;
-bool SurfaceFlinger::enableSdrDimming;
LatchUnsignaledConfig SurfaceFlinger::enableLatchUnsignaledConfig;
std::string decodeDisplayColorSetting(DisplayColorSetting displayColorSetting) {
@@ -385,7 +385,7 @@
mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)),
mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)),
mPowerAdvisor(*this),
- mWindowInfosListenerInvoker(new WindowInfosListenerInvoker(this)) {
+ mWindowInfosListenerInvoker(sp<WindowInfosListenerInvoker>::make(*this)) {
ALOGI("Using HWComposer service: %s", mHwcServiceName.c_str());
}
@@ -503,15 +503,10 @@
mRefreshRateOverlaySpinner = property_get_bool("sf.debug.show_refresh_rate_overlay_spinner", 0);
- // Debug property overrides ro. property
- enableSdrDimming = property_get_bool("debug.sf.enable_sdr_dimming", enable_sdr_dimming(false));
-
enableLatchUnsignaledConfig = getLatchUnsignaledConfig();
- mTransactionTracingEnabled =
- !mIsUserBuild && property_get_bool("debug.sf.enable_transaction_tracing", true);
- if (mTransactionTracingEnabled) {
- mTransactionTracing.enable();
+ if (!mIsUserBuild && base::GetBoolProperty("debug.sf.enable_transaction_tracing"s, true)) {
+ mTransactionTracing.emplace();
}
}
@@ -721,7 +716,6 @@
ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
mFlagManager = std::make_unique<android::FlagManager>();
- mPowerAdvisor.enablePowerHint(mFlagManager->use_adpf_cpu_hint());
mFrameTracer->initialize();
mFrameTimeline->onBootFinished();
@@ -751,7 +745,18 @@
}
readPersistentProperties();
+ std::optional<pid_t> renderEngineTid = getRenderEngine().getRenderEngineTid();
+ std::vector<int32_t> tidList;
+ tidList.emplace_back(gettid());
+ if (renderEngineTid.has_value()) {
+ tidList.emplace_back(*renderEngineTid);
+ }
mPowerAdvisor.onBootFinished();
+ mPowerAdvisor.enablePowerHint(mFlagManager->use_adpf_cpu_hint());
+ if (mPowerAdvisor.usePowerHintSession()) {
+ mPowerAdvisor.startPowerHintSession(tidList);
+ }
+
mBootStage = BootStage::FINISHED;
if (property_get_bool("sf.debug.show_refresh_rate_overlay", false)) {
@@ -1420,6 +1425,52 @@
return NO_ERROR;
}
+status_t SurfaceFlinger::getBootDisplayModeSupport(bool* outSupport) const {
+ auto future = mScheduler->schedule([=]() MAIN_THREAD mutable -> status_t {
+ *outSupport = getHwComposer().getBootDisplayModeSupport();
+ return NO_ERROR;
+ });
+ return future.get();
+}
+
+status_t SurfaceFlinger::setBootDisplayMode(const sp<IBinder>& displayToken, ui::DisplayModeId id) {
+ auto future = mScheduler->schedule([=]() MAIN_THREAD -> status_t {
+ if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
+ return getHwComposer().setBootDisplayMode(*displayId, id);
+ } else {
+ ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get());
+ return BAD_VALUE;
+ }
+ });
+ return future.get();
+}
+
+status_t SurfaceFlinger::clearBootDisplayMode(const sp<IBinder>& displayToken) {
+ auto future = mScheduler->schedule([=]() MAIN_THREAD -> status_t {
+ if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
+ return getHwComposer().clearBootDisplayMode(*displayId);
+ } else {
+ ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get());
+ return BAD_VALUE;
+ }
+ });
+ return future.get();
+}
+
+status_t SurfaceFlinger::getPreferredBootDisplayMode(const sp<IBinder>& displayToken,
+ ui::DisplayModeId* id) {
+ auto future = mScheduler->schedule([=]() MAIN_THREAD mutable -> status_t {
+ if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
+ *id = getHwComposer().getPreferredBootDisplayMode(*displayId);
+ return NO_ERROR;
+ } else {
+ ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get());
+ return BAD_VALUE;
+ }
+ });
+ return future.get();
+}
+
void SurfaceFlinger::setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on) {
const char* const whence = __func__;
static_cast<void>(mScheduler->schedule([=]() MAIN_THREAD {
@@ -1599,7 +1650,7 @@
status_t SurfaceFlinger::addRegionSamplingListener(const Rect& samplingArea,
const sp<IBinder>& stopLayerHandle,
const sp<IRegionSamplingListener>& listener) {
- if (!listener || samplingArea == Rect::INVALID_RECT) {
+ if (!listener || samplingArea == Rect::INVALID_RECT || samplingArea.isEmpty()) {
return BAD_VALUE;
}
@@ -1669,6 +1720,17 @@
return NO_ERROR;
}
+bool SurfaceFlinger::hasVisibleHdrLayer(const sp<DisplayDevice>& display) {
+ bool hasHdrLayers = false;
+ mDrawingState.traverse([&,
+ compositionDisplay = display->getCompositionDisplay()](Layer* layer) {
+ hasHdrLayers |= (layer->isVisible() &&
+ compositionDisplay->includesLayer(layer->getCompositionEngineLayerFE()) &&
+ isHdrDataspace(layer->getDataSpace()));
+ });
+ return hasHdrLayers;
+}
+
status_t SurfaceFlinger::setDisplayBrightness(const sp<IBinder>& displayToken,
const gui::DisplayBrightness& brightness) {
if (!displayToken) {
@@ -1678,13 +1740,30 @@
const char* const whence = __func__;
return ftl::chain(mScheduler->schedule([=]() MAIN_THREAD {
if (const auto display = getDisplayDeviceLocked(displayToken)) {
- if (enableSdrDimming) {
+ const bool supportsDisplayBrightnessCommand =
+ getHwComposer().getComposer()->isSupported(
+ Hwc2::Composer::OptionalFeature::DisplayBrightnessCommand);
+ // If we support applying display brightness as a command, then we also support
+ // dimming SDR layers.
+ if (supportsDisplayBrightnessCommand) {
display->getCompositionDisplay()
->setDisplayBrightness(brightness.sdrWhitePointNits,
brightness.displayBrightnessNits);
+ MAIN_THREAD_GUARD(display->stageBrightness(brightness.displayBrightness));
+ if (hasVisibleHdrLayer(display)) {
+ scheduleComposite(FrameHint::kNone);
+ } else {
+ scheduleCommit(FrameHint::kNone);
+ }
+ return ftl::yield<status_t>(OK);
+ } else {
+ return getHwComposer()
+ .setDisplayBrightness(display->getPhysicalId(),
+ brightness.displayBrightness,
+ Hwc2::Composer::DisplayBrightnessOptions{
+ .applyImmediately = true});
}
- return getHwComposer().setDisplayBrightness(display->getPhysicalId(),
- brightness.displayBrightness);
+
} else {
ALOGE("%s: Invalid display token %p", whence, displayToken.get());
return ftl::yield<status_t>(NAME_NOT_FOUND);
@@ -1748,6 +1827,23 @@
return NO_ERROR;
}
+status_t SurfaceFlinger::getDisplayDecorationSupport(const sp<IBinder>& displayToken,
+ bool* outSupport) const {
+ if (!displayToken || !outSupport) {
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock lock(mStateLock);
+
+ const auto displayId = getPhysicalDisplayIdLocked(displayToken);
+ if (!displayId) {
+ return NAME_NOT_FOUND;
+ }
+ *outSupport =
+ getHwComposer().hasDisplayCapability(*displayId, DisplayCapability::DISPLAY_DECORATION);
+ return NO_ERROR;
+}
+
// ----------------------------------------------------------------------------
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
@@ -1922,6 +2018,13 @@
}
bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime) {
+ MainThreadScopedGuard mainThreadGuard(SF_MAIN_THREAD);
+ // we set this once at the beginning of commit to ensure consistency throughout the whole frame
+ mPowerHintSessionData.sessionEnabled = mPowerAdvisor.usePowerHintSession();
+ if (mPowerHintSessionData.sessionEnabled) {
+ mPowerHintSessionData.commitStart = systemTime();
+ }
+
// calculate the expected present time once and use the cached
// value throughout this frame to make sure all layers are
// seeing this same value.
@@ -1935,6 +2038,10 @@
const nsecs_t lastScheduledPresentTime = mScheduledPresentTime;
mScheduledPresentTime = expectedVsyncTime;
+ if (mPowerHintSessionData.sessionEnabled) {
+ mPowerAdvisor.setTargetWorkDuration(mExpectedPresentTime -
+ mPowerHintSessionData.commitStart);
+ }
const auto vsyncIn = [&] {
if (!ATRACE_ENABLED()) return 0.f;
return (mExpectedPresentTime - systemTime()) / 1e6f;
@@ -1997,7 +2104,10 @@
// We received the present fence from the HWC, so we assume it successfully updated
// the mode, hence we update SF.
mSetActiveModePending = false;
- ON_MAIN_THREAD(updateInternalStateWithChangedMode());
+ {
+ Mutex::Autolock lock(mStateLock);
+ updateInternalStateWithChangedMode();
+ }
}
if (framePending) {
@@ -2062,18 +2172,23 @@
{
Mutex::Autolock _l(mStateLock);
mScheduler->chooseRefreshRateForContent();
+ setActiveModeInHwcIfNeeded();
}
- ON_MAIN_THREAD(setActiveModeInHwcIfNeeded());
-
updateCursorAsync();
updateInputFlinger();
+ MAIN_THREAD_GUARD(persistDisplayBrightness(mustComposite));
+
return mustComposite && CC_LIKELY(mBootStage != BootStage::BOOTLOADER);
}
void SurfaceFlinger::composite(nsecs_t frameTime) {
ATRACE_CALL();
+ MainThreadScopedGuard mainThreadGuard(SF_MAIN_THREAD);
+ if (mPowerHintSessionData.sessionEnabled) {
+ mPowerHintSessionData.compositeStart = systemTime();
+ }
compositionengine::CompositionRefreshArgs refreshArgs;
const auto& displays = ON_MAIN_THREAD(mDisplays);
@@ -2127,6 +2242,11 @@
const auto presentTime = systemTime();
mCompositionEngine->present(refreshArgs);
+
+ if (mPowerHintSessionData.sessionEnabled) {
+ mPowerHintSessionData.presentEnd = systemTime();
+ }
+
mTimeStats->recordFrameDuration(frameTime, systemTime());
mScheduler->onPostComposition(presentTime);
@@ -2174,6 +2294,13 @@
if (mCompositionEngine->needsAnotherUpdate()) {
scheduleCommit(FrameHint::kNone);
}
+
+ // calculate total render time for performance hinting if adpf cpu hint is enabled,
+ if (mPowerHintSessionData.sessionEnabled) {
+ const nsecs_t flingerDuration =
+ (mPowerHintSessionData.presentEnd - mPowerHintSessionData.commitStart);
+ mPowerAdvisor.sendActualWorkDuration(flingerDuration, mPowerHintSessionData.presentEnd);
+ }
}
void SurfaceFlinger::updateLayerGeometry() {
@@ -3101,6 +3228,34 @@
mInputWindowCommands.clear();
}
+void SurfaceFlinger::persistDisplayBrightness(bool needsComposite) {
+ const bool supportsDisplayBrightnessCommand = getHwComposer().getComposer()->isSupported(
+ Hwc2::Composer::OptionalFeature::DisplayBrightnessCommand);
+ if (!supportsDisplayBrightnessCommand) {
+ return;
+ }
+
+ const auto& displays = ON_MAIN_THREAD(mDisplays);
+
+ for (const auto& [_, display] : displays) {
+ if (const auto brightness = display->getStagedBrightness(); brightness) {
+ if (!needsComposite) {
+ const status_t error =
+ getHwComposer()
+ .setDisplayBrightness(display->getPhysicalId(), *brightness,
+ Hwc2::Composer::DisplayBrightnessOptions{
+ .applyImmediately = true})
+ .get();
+
+ ALOGE_IF(error != NO_ERROR,
+ "Error setting display brightness for display %s: %d (%s)",
+ display->getDebugName().c_str(), error, strerror(error));
+ }
+ display->persistBrightness(needsComposite);
+ }
+ }
+}
+
void SurfaceFlinger::buildWindowInfos(std::vector<WindowInfo>& outWindowInfos,
std::vector<DisplayInfo>& outDisplayInfos) {
struct Details {
@@ -3613,8 +3768,8 @@
}
}
- if (mTransactionTracingEnabled) {
- mTransactionTracing.addCommittedTransactions(transactions, vsyncId);
+ if (mTransactionTracing) {
+ mTransactionTracing->addCommittedTransactions(transactions, vsyncId);
}
return needsTraversal;
}
@@ -3665,9 +3820,9 @@
if (transaction.states.size() == 1) {
const auto& state = transaction.states.begin()->state;
if ((state.flags & ~layer_state_t::eBufferChanged) == 0 &&
- state.bufferData.flags.test(BufferData::BufferDataChange::fenceChanged) &&
- state.bufferData.acquireFence &&
- state.bufferData.acquireFence->getStatus() == Fence::Status::Unsignaled) {
+ state.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged) &&
+ state.bufferData->acquireFence &&
+ state.bufferData->acquireFence->getStatus() == Fence::Status::Unsignaled) {
ATRACE_NAME("transactionCanLatchUnsignaled");
return true;
}
@@ -3732,10 +3887,10 @@
for (const ComposerState& state : states) {
const layer_state_t& s = state.state;
- const bool acquireFenceChanged =
- s.bufferData.flags.test(BufferData::BufferDataChange::fenceChanged);
- if (acquireFenceChanged && s.bufferData.acquireFence && !allowLatchUnsignaled &&
- s.bufferData.acquireFence->getStatus() == Fence::Status::Unsignaled) {
+ const bool acquireFenceChanged = s.bufferData &&
+ s.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged);
+ if (acquireFenceChanged && s.bufferData->acquireFence && !allowLatchUnsignaled &&
+ s.bufferData->acquireFence->getStatus() == Fence::Status::Unsignaled) {
ATRACE_NAME("fence unsignaled");
return false;
}
@@ -3874,8 +4029,8 @@
mBufferCountTracker.increment(state.surface->localBinder());
});
- if (mTransactionTracingEnabled) {
- mTransactionTracing.addQueuedTransaction(state);
+ if (mTransactionTracing) {
+ mTransactionTracing->addQueuedTransaction(state);
}
queueTransaction(state);
@@ -4365,10 +4520,13 @@
}
}
- if (what & layer_state_t::eBufferChanged &&
- layer->setBuffer(s.bufferData, postTime, desiredPresentTime, isAutoTimestamp,
- dequeueBufferTimestamp, frameTimelineInfo)) {
- flags |= eTraversalNeeded;
+ if (what & layer_state_t::eBufferChanged) {
+ std::shared_ptr<renderengine::ExternalTexture> buffer =
+ getExternalTextureFromBufferData(*s.bufferData, layer->getDebugName());
+ if (layer->setBuffer(buffer, *s.bufferData, postTime, desiredPresentTime, isAutoTimestamp,
+ dequeueBufferTimestamp, frameTimelineInfo)) {
+ flags |= eTraversalNeeded;
+ }
} else if (frameTimelineInfo.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) {
layer->setFrameTimelineVsyncForBufferlessTransaction(frameTimelineInfo, postTime);
}
@@ -4408,9 +4566,9 @@
}
*outLayerId = mirrorLayer->sequence;
- if (mTransactionTracingEnabled) {
- mTransactionTracing.onMirrorLayerAdded((*outHandle)->localBinder(), mirrorLayer->sequence,
- args.name, mirrorFrom->sequence);
+ if (mTransactionTracing) {
+ mTransactionTracing->onMirrorLayerAdded((*outHandle)->localBinder(), mirrorLayer->sequence,
+ args.name, mirrorFrom->sequence);
}
return addClientLayer(args.client, *outHandle, mirrorLayer /* layer */, nullptr /* parent */,
false /* addAsRoot */, nullptr /* outTransformHint */);
@@ -4470,9 +4628,9 @@
if (parentSp != nullptr) {
parentId = parentSp->getSequence();
}
- if (mTransactionTracingEnabled) {
- mTransactionTracing.onLayerAdded((*outHandle)->localBinder(), layer->sequence, args.name,
- args.flags, parentId);
+ if (mTransactionTracing) {
+ mTransactionTracing->onLayerAdded((*outHandle)->localBinder(), layer->sequence, args.name,
+ args.flags, parentId);
}
result = addClientLayer(args.client, *outHandle, layer, parent, addToRoot, outTransformHint);
@@ -4562,8 +4720,8 @@
markLayerPendingRemovalLocked(layer);
mBufferCountTracker.remove(handle);
layer.clear();
- if (mTransactionTracingEnabled) {
- mTransactionTracing.onHandleRemoved(handle);
+ if (mTransactionTracing) {
+ mTransactionTracing->onHandleRemoved(handle);
}
}
@@ -4798,7 +4956,9 @@
status_t SurfaceFlinger::dumpCritical(int fd, const DumpArgs&, bool asProto) {
if (asProto) {
mLayerTracing.writeToFile();
- mTransactionTracing.writeToFile();
+ if (mTransactionTracing) {
+ mTransactionTracing->writeToFile();
+ }
}
return doDump(fd, DumpArgs(), asProto);
@@ -5195,9 +5355,15 @@
* Tracing state
*/
mLayerTracing.dump(result);
- result.append("\n");
- mTransactionTracing.dump(result);
- result.append("\n");
+
+ result.append("\nTransaction tracing: ");
+ if (mTransactionTracing) {
+ result.append("enabled\n");
+ mTransactionTracing->dump(result);
+ } else {
+ result.append("disabled\n");
+ }
+ result.push_back('\n');
/*
* HWC layer minidump
@@ -5294,6 +5460,10 @@
case SET_DESIRED_DISPLAY_MODE_SPECS:
case GET_DESIRED_DISPLAY_MODE_SPECS:
case SET_ACTIVE_COLOR_MODE:
+ case GET_BOOT_DISPLAY_MODE_SUPPORT:
+ case SET_BOOT_DISPLAY_MODE:
+ case CLEAR_BOOT_DISPLAY_MODE:
+ case GET_PREFERRED_BOOT_DISPLAY_MODE:
case GET_AUTO_LOW_LATENCY_MODE_SUPPORT:
case SET_AUTO_LOW_LATENCY_MODE:
case GET_GAME_CONTENT_TYPE_SUPPORT:
@@ -5359,6 +5529,7 @@
// special permissions.
case SET_FRAME_RATE:
case GET_DISPLAY_BRIGHTNESS_SUPPORT:
+ case GET_DISPLAY_DECORATION_SUPPORT:
// captureLayers and captureDisplay will handle the permission check in the function
case CAPTURE_LAYERS:
case CAPTURE_DISPLAY:
@@ -5872,15 +6043,17 @@
return NO_ERROR;
}
case 1041: { // Transaction tracing
- if (data.readInt32()) {
- // Transaction tracing is always running but allow the user to temporarily
- // increase the buffer when actively debugging.
- mTransactionTracing.setBufferSize(
- TransactionTracing::ACTIVE_TRACING_BUFFER_SIZE);
- } else {
- mTransactionTracing.setBufferSize(
- TransactionTracing::CONTINUOUS_TRACING_BUFFER_SIZE);
- mTransactionTracing.writeToFile();
+ if (mTransactionTracing) {
+ if (data.readInt32()) {
+ // Transaction tracing is always running but allow the user to temporarily
+ // increase the buffer when actively debugging.
+ mTransactionTracing->setBufferSize(
+ TransactionTracing::ACTIVE_TRACING_BUFFER_SIZE);
+ } else {
+ mTransactionTracing->setBufferSize(
+ TransactionTracing::CONTINUOUS_TRACING_BUFFER_SIZE);
+ mTransactionTracing->writeToFile();
+ }
}
reply->writeInt32(NO_ERROR);
return NO_ERROR;
@@ -6329,9 +6502,10 @@
const status_t bufferStatus = buffer->initCheck();
LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureScreenCommon: Buffer failed to allocate: %d",
bufferStatus);
- const auto texture = std::make_shared<
- renderengine::ExternalTexture>(buffer, getRenderEngine(),
- renderengine::ExternalTexture::Usage::WRITEABLE);
+ const std::shared_ptr<renderengine::ExternalTexture> texture = std::make_shared<
+ renderengine::impl::ExternalTexture>(buffer, getRenderEngine(),
+ renderengine::impl::ExternalTexture::Usage::
+ WRITEABLE);
return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, texture,
false /* regionSampling */, grayscale, captureListener);
}
@@ -6408,7 +6582,7 @@
captureResults.capturedSecureLayers || (layer->isVisible() && layer->isSecure());
});
- const bool useProtected = buffer->getBuffer()->getUsage() & GRALLOC_USAGE_PROTECTED;
+ const bool useProtected = buffer->getUsage() & GRALLOC_USAGE_PROTECTED;
// We allow the system server to take screenshots of secure layers for
// use in situations like the Screen-rotation animation and place
@@ -6721,8 +6895,8 @@
if (!layer->isRemovedFromCurrentState()) {
mScheduler->deregisterLayer(layer);
}
- if (mTransactionTracingEnabled) {
- mTransactionTracing.onLayerRemoved(layer->getSequence());
+ if (mTransactionTracing) {
+ mTransactionTracing->onLayerRemoved(layer->getSequence());
}
}
@@ -7019,6 +7193,36 @@
return NO_ERROR;
}
+std::shared_ptr<renderengine::ExternalTexture> SurfaceFlinger::getExternalTextureFromBufferData(
+ const BufferData& bufferData, const char* layerName) const {
+ bool cacheIdChanged = bufferData.flags.test(BufferData::BufferDataChange::cachedBufferChanged);
+ bool bufferSizeExceedsLimit = false;
+ std::shared_ptr<renderengine::ExternalTexture> buffer = nullptr;
+ if (cacheIdChanged && bufferData.buffer != nullptr) {
+ bufferSizeExceedsLimit = exceedsMaxRenderTargetSize(bufferData.buffer->getWidth(),
+ bufferData.buffer->getHeight());
+ if (!bufferSizeExceedsLimit) {
+ ClientCache::getInstance().add(bufferData.cachedBuffer, bufferData.buffer);
+ buffer = ClientCache::getInstance().get(bufferData.cachedBuffer);
+ }
+ } else if (cacheIdChanged) {
+ buffer = ClientCache::getInstance().get(bufferData.cachedBuffer);
+ } else if (bufferData.buffer != nullptr) {
+ bufferSizeExceedsLimit = exceedsMaxRenderTargetSize(bufferData.buffer->getWidth(),
+ bufferData.buffer->getHeight());
+ if (!bufferSizeExceedsLimit) {
+ buffer = std::make_shared<
+ renderengine::impl::ExternalTexture>(bufferData.buffer, getRenderEngine(),
+ renderengine::impl::ExternalTexture::
+ Usage::READABLE);
+ }
+ }
+ ALOGE_IF(bufferSizeExceedsLimit,
+ "Attempted to create an ExternalTexture for layer %s that exceeds render target size "
+ "limit.",
+ layerName);
+ return buffer;
+}
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index e1b52c5..01709ab 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -252,10 +252,6 @@
static constexpr SkipInitializationTag SkipInitialization;
- // Whether or not SDR layers should be dimmed to the desired SDR white point instead of
- // being treated as native display brightness
- static bool enableSdrDimming;
-
static LatchUnsignaledConfig enableLatchUnsignaledConfig;
// must be called before clients can connect
@@ -330,6 +326,9 @@
virtual void processDisplayAdded(const wp<IBinder>& displayToken, const DisplayDeviceState&)
REQUIRES(mStateLock);
+ virtual std::shared_ptr<renderengine::ExternalTexture> getExternalTextureFromBufferData(
+ const BufferData& bufferData, const char* layerName) const;
+
// Returns true if any display matches a `bool(const DisplayDevice&)` predicate.
template <typename Predicate>
bool hasDisplay(Predicate p) const REQUIRES(mStateLock) {
@@ -535,6 +534,11 @@
status_t getDisplayNativePrimaries(const sp<IBinder>& displayToken,
ui::DisplayPrimaries&) override;
status_t setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode colorMode) override;
+ status_t getBootDisplayModeSupport(bool* outSupport) const override;
+ status_t setBootDisplayMode(const sp<IBinder>& displayToken, ui::DisplayModeId id) override;
+ status_t clearBootDisplayMode(const sp<IBinder>& displayToken) override;
+ status_t getPreferredBootDisplayMode(const sp<IBinder>& displayToken,
+ ui::DisplayModeId* id) override;
void setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on) override;
void setGameContentType(const sp<IBinder>& displayToken, bool on) override;
void setPowerMode(const sp<IBinder>& displayToken, int mode) override;
@@ -594,6 +598,8 @@
status_t notifyPowerBoost(int32_t boostId) override;
status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
float lightPosY, float lightPosZ, float lightRadius) override;
+ status_t getDisplayDecorationSupport(const sp<IBinder>& displayToken,
+ bool* outSupport) const override;
status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
int8_t compatibility, int8_t changeFrameRateStrategy) override;
@@ -674,6 +680,9 @@
void setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode)
REQUIRES(mStateLock);
+ // Returns true if the display has a visible HDR layer in its layer stack.
+ bool hasVisibleHdrLayer(const sp<DisplayDevice>& display) REQUIRES(mStateLock);
+
// Sets the desired display mode specs.
status_t setDesiredDisplayModeSpecsInternal(
const sp<DisplayDevice>& display,
@@ -690,6 +699,7 @@
void updateLayerGeometry();
void updateInputFlinger();
+ void persistDisplayBrightness(bool needsComposite) REQUIRES(SF_MAIN_THREAD);
void buildWindowInfos(std::vector<gui::WindowInfo>& outWindowInfos,
std::vector<gui::DisplayInfo>& outDisplayInfos);
void commitInputWindowCommands() REQUIRES(mStateLock);
@@ -1187,8 +1197,7 @@
LayerTracing mLayerTracing{*this};
bool mLayerTracingEnabled = false;
- TransactionTracing mTransactionTracing;
- bool mTransactionTracingEnabled = false;
+ std::optional<TransactionTracing> mTransactionTracing;
std::atomic<bool> mTracingEnabledChanged = false;
const std::shared_ptr<TimeStats> mTimeStats;
@@ -1357,6 +1366,13 @@
float getLayerFramerate(nsecs_t now, int32_t id) const {
return mScheduler->getLayerFramerate(now, id);
}
+
+ struct {
+ bool sessionEnabled = false;
+ nsecs_t commitStart;
+ nsecs_t compositeStart;
+ nsecs_t presentEnd;
+ } mPowerHintSessionData GUARDED_BY(SF_MAIN_THREAD);
};
} // namespace android
diff --git a/services/surfaceflinger/TracedOrdinal.h b/services/surfaceflinger/TracedOrdinal.h
index eee4bec..558b3be 100644
--- a/services/surfaceflinger/TracedOrdinal.h
+++ b/services/surfaceflinger/TracedOrdinal.h
@@ -15,11 +15,14 @@
*/
#pragma once
-#include <android-base/stringprintf.h>
+
+#include <chrono>
+#include <cmath>
+#include <functional>
+#include <string>
+
#include <cutils/compiler.h>
#include <utils/Trace.h>
-#include <cmath>
-#include <string>
namespace std {
template <class Rep, class Period>
@@ -75,7 +78,7 @@
}
if (mNameNegative.empty()) {
- mNameNegative = base::StringPrintf("%sNegative", mName.c_str());
+ mNameNegative = mName + "Negative";
}
if (!std::signbit(mData)) {
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
index 378deb0..a91698f 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -31,6 +31,7 @@
proto.set_vsync_id(t.frameTimelineInfo.vsyncId);
proto.set_input_event_id(t.frameTimelineInfo.inputEventId);
proto.set_post_time(t.postTime);
+ proto.set_transaction_id(t.id);
for (auto& layerState : t.states) {
proto.mutable_layer_changes()->Add(std::move(toProto(layerState.state, getLayerId)));
@@ -52,6 +53,9 @@
bufferProto->set_buffer_id(state.bufferId);
bufferProto->set_width(state.bufferWidth);
bufferProto->set_height(state.bufferHeight);
+ bufferProto->set_pixel_format(
+ static_cast<proto::LayerState_BufferData_PixelFormat>(state.pixelFormat));
+ bufferProto->set_usage(state.bufferUsage);
}
layerProto.set_has_sideband_stream(state.hasSidebandStream);
layerProto.set_layer_id(state.layerId);
@@ -132,14 +136,17 @@
}
if (layer.what & layer_state_t::eBufferChanged) {
proto::LayerState_BufferData* bufferProto = proto.mutable_buffer_data();
- if (layer.bufferData.buffer) {
- bufferProto->set_buffer_id(layer.bufferData.buffer->getId());
- bufferProto->set_width(layer.bufferData.buffer->getWidth());
- bufferProto->set_height(layer.bufferData.buffer->getHeight());
+ if (layer.bufferData->buffer) {
+ bufferProto->set_buffer_id(layer.bufferData->getId());
+ bufferProto->set_width(layer.bufferData->getWidth());
+ bufferProto->set_height(layer.bufferData->getHeight());
+ bufferProto->set_pixel_format(static_cast<proto::LayerState_BufferData_PixelFormat>(
+ layer.bufferData->getPixelFormat()));
+ bufferProto->set_usage(layer.bufferData->getUsage());
}
- bufferProto->set_frame_number(layer.bufferData.frameNumber);
- bufferProto->set_flags(layer.bufferData.flags.get());
- bufferProto->set_cached_buffer_id(layer.bufferData.cachedBuffer.id);
+ bufferProto->set_frame_number(layer.bufferData->frameNumber);
+ bufferProto->set_flags(layer.bufferData->flags.get());
+ bufferProto->set_cached_buffer_id(layer.bufferData->cachedBuffer.id);
}
if (layer.what & layer_state_t::eSidebandStreamChanged) {
proto.set_has_sideband_stream(layer.sidebandStream != nullptr);
@@ -169,6 +176,7 @@
? getLayerId(layer.relativeLayerSurfaceControl->getHandle())
: -1;
proto.set_relative_parent_id(layerId);
+ proto.set_z(layer.z);
}
if (layer.what & layer_state_t::eInputInfoChanged) {
@@ -291,10 +299,13 @@
t.frameTimelineInfo.vsyncId = proto.vsync_id();
t.frameTimelineInfo.inputEventId = proto.input_event_id();
t.postTime = proto.post_time();
+ t.id = proto.transaction_id();
+
int32_t layerCount = proto.layer_changes_size();
t.states.reserve(static_cast<size_t>(layerCount));
for (int i = 0; i < layerCount; i++) {
ComposerState s;
+ s.state.what = 0;
fromProto(proto.layer_changes(i), getLayerHandle, s.state);
t.states.add(s);
}
@@ -316,27 +327,31 @@
outArgs.mirrorFromId = proto.mirror_from_id();
}
-void TransactionProtoParser::fromProto(const proto::LayerState& proto,
- LayerIdToHandleFn getLayerHandle,
- TracingLayerState& outState) {
- fromProto(proto, getLayerHandle, static_cast<layer_state_t&>(outState));
- if (proto.what() & layer_state_t::eReparent) {
+void TransactionProtoParser::mergeFromProto(const proto::LayerState& proto,
+ LayerIdToHandleFn getLayerHandle,
+ TracingLayerState& outState) {
+ layer_state_t state;
+ fromProto(proto, getLayerHandle, state);
+ outState.merge(state);
+
+ if (state.what & layer_state_t::eReparent) {
outState.parentId = proto.parent_id();
- outState.args.parentId = outState.parentId;
}
- if (proto.what() & layer_state_t::eRelativeLayerChanged) {
+ if (state.what & layer_state_t::eRelativeLayerChanged) {
outState.relativeParentId = proto.relative_parent_id();
}
- if (proto.what() & layer_state_t::eInputInfoChanged) {
+ if (state.what & layer_state_t::eInputInfoChanged) {
outState.inputCropId = proto.window_info_handle().crop_layer_id();
}
- if (proto.what() & layer_state_t::eBufferChanged) {
+ if (state.what & layer_state_t::eBufferChanged) {
const proto::LayerState_BufferData& bufferProto = proto.buffer_data();
outState.bufferId = bufferProto.buffer_id();
outState.bufferWidth = bufferProto.width();
outState.bufferHeight = bufferProto.height();
+ outState.pixelFormat = bufferProto.pixel_format();
+ outState.bufferUsage = bufferProto.usage();
}
- if (proto.what() & layer_state_t::eSidebandStreamChanged) {
+ if (state.what & layer_state_t::eSidebandStreamChanged) {
outState.hasSidebandStream = proto.has_sideband_stream();
}
}
@@ -405,10 +420,13 @@
LayerProtoHelper::readFromProto(proto.crop(), layer.crop);
}
if (proto.what() & layer_state_t::eBufferChanged) {
+ if (!layer.bufferData) {
+ layer.bufferData = std::make_shared<BufferData>();
+ }
const proto::LayerState_BufferData& bufferProto = proto.buffer_data();
- layer.bufferData.frameNumber = bufferProto.frame_number();
- layer.bufferData.flags = Flags<BufferData::BufferDataChange>(bufferProto.flags());
- layer.bufferData.cachedBuffer.id = bufferProto.cached_buffer_id();
+ layer.bufferData->frameNumber = bufferProto.frame_number();
+ layer.bufferData->flags = Flags<BufferData::BufferDataChange>(bufferProto.flags());
+ layer.bufferData->cachedBuffer.id = bufferProto.cached_buffer_id();
}
if (proto.what() & layer_state_t::eApiChanged) {
@@ -429,15 +447,24 @@
if ((proto.what() & layer_state_t::eReparent) && (getLayerHandle != nullptr)) {
int32_t layerId = proto.parent_id();
- layer.parentSurfaceControlForChild =
- new SurfaceControl(SurfaceComposerClient::getDefault(), getLayerHandle(layerId),
- nullptr, layerId);
+ if (layerId == -1) {
+ layer.parentSurfaceControlForChild = nullptr;
+ } else {
+ layer.parentSurfaceControlForChild =
+ new SurfaceControl(SurfaceComposerClient::getDefault(), getLayerHandle(layerId),
+ nullptr, layerId);
+ }
}
- if ((proto.what() & layer_state_t::eRelativeLayerChanged) && (getLayerHandle != nullptr)) {
+ if (proto.what() & layer_state_t::eRelativeLayerChanged) {
int32_t layerId = proto.relative_parent_id();
- layer.relativeLayerSurfaceControl =
- new SurfaceControl(SurfaceComposerClient::getDefault(), getLayerHandle(layerId),
- nullptr, layerId);
+ if (layerId == -1) {
+ layer.relativeLayerSurfaceControl = nullptr;
+ } else if (getLayerHandle != nullptr) {
+ layer.relativeLayerSurfaceControl =
+ new SurfaceControl(SurfaceComposerClient::getDefault(), getLayerHandle(layerId),
+ nullptr, layerId);
+ }
+ layer.z = proto.z();
}
if ((proto.what() & layer_state_t::eInputInfoChanged) && proto.has_window_info_handle()) {
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.h b/services/surfaceflinger/Tracing/TransactionProtoParser.h
index b78d3d9..d589936 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.h
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.h
@@ -34,6 +34,8 @@
uint64_t bufferId;
uint32_t bufferHeight;
uint32_t bufferWidth;
+ int32_t pixelFormat;
+ uint64_t bufferUsage;
bool hasSidebandStream;
int32_t parentId;
int32_t relativeParentId;
@@ -58,8 +60,8 @@
static TransactionState fromProto(const proto::TransactionState&,
LayerIdToHandleFn getLayerHandleFn,
DisplayIdToHandleFn getDisplayHandleFn);
- static void fromProto(const proto::LayerState&, LayerIdToHandleFn getLayerHandleFn,
- TracingLayerState& outState);
+ static void mergeFromProto(const proto::LayerState&, LayerIdToHandleFn getLayerHandleFn,
+ TracingLayerState& outState);
static void fromProto(const proto::LayerCreationArgs&, TracingLayerCreationArgs& outArgs);
private:
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.cpp b/services/surfaceflinger/Tracing/TransactionTracing.cpp
index b5966d5..5136295 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.cpp
+++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp
@@ -23,35 +23,22 @@
#include <utils/SystemClock.h>
#include <utils/Trace.h>
-#include "RingBuffer.h"
#include "TransactionTracing.h"
namespace android {
TransactionTracing::TransactionTracing() {
- mBuffer = std::make_unique<
- RingBuffer<proto::TransactionTraceFile, proto::TransactionTraceEntry>>();
-}
-
-TransactionTracing::~TransactionTracing() = default;
-
-bool TransactionTracing::enable() {
std::scoped_lock lock(mTraceLock);
- if (mEnabled) {
- return false;
- }
- mBuffer->setSize(mBufferSizeInBytes);
+
+ mBuffer.setSize(mBufferSizeInBytes);
mStartingTimestamp = systemTime();
- mEnabled = true;
{
std::scoped_lock lock(mMainThreadLock);
- mDone = false;
mThread = std::thread(&TransactionTracing::loop, this);
}
- return true;
}
-bool TransactionTracing::disable() {
+TransactionTracing::~TransactionTracing() {
std::thread thread;
{
std::scoped_lock lock(mMainThreadLock);
@@ -63,43 +50,20 @@
thread.join();
}
- std::scoped_lock lock(mTraceLock);
- if (!mEnabled) {
- return false;
- }
- mEnabled = false;
-
- writeToFileLocked();
- mBuffer->reset();
- mQueuedTransactions.clear();
- mStartingStates.clear();
- mLayerHandles.clear();
- return true;
-}
-
-bool TransactionTracing::isEnabled() const {
- std::scoped_lock lock(mTraceLock);
- return mEnabled;
+ writeToFile();
}
status_t TransactionTracing::writeToFile() {
std::scoped_lock lock(mTraceLock);
- if (!mEnabled) {
- return STATUS_OK;
- }
- return writeToFileLocked();
-}
-
-status_t TransactionTracing::writeToFileLocked() {
proto::TransactionTraceFile fileProto = createTraceFileProto();
addStartingStateToProtoLocked(fileProto);
- return mBuffer->writeToFile(fileProto, FILE_NAME);
+ return mBuffer.writeToFile(fileProto, FILE_NAME);
}
void TransactionTracing::setBufferSize(size_t bufferSizeInBytes) {
std::scoped_lock lock(mTraceLock);
mBufferSizeInBytes = bufferSizeInBytes;
- mBuffer->setSize(mBufferSizeInBytes);
+ mBuffer.setSize(mBufferSizeInBytes);
}
proto::TransactionTraceFile TransactionTracing::createTraceFileProto() const {
@@ -111,21 +75,16 @@
void TransactionTracing::dump(std::string& result) const {
std::scoped_lock lock(mTraceLock);
- base::StringAppendF(&result, "Transaction tracing state: %s\n",
- mEnabled ? "enabled" : "disabled");
base::StringAppendF(&result,
" queued transactions=%zu created layers=%zu handles=%zu states=%zu\n",
mQueuedTransactions.size(), mCreatedLayers.size(), mLayerHandles.size(),
mStartingStates.size());
- mBuffer->dump(result);
+ mBuffer.dump(result);
}
void TransactionTracing::addQueuedTransaction(const TransactionState& transaction) {
std::scoped_lock lock(mTraceLock);
ATRACE_CALL();
- if (!mEnabled) {
- return;
- }
mQueuedTransactions[transaction.id] =
TransactionProtoParser::toProto(transaction,
std::bind(&TransactionTracing::getLayerIdLocked, this,
@@ -206,10 +165,17 @@
std::string serializedProto;
entryProto.SerializeToString(&serializedProto);
entryProto.Clear();
- std::vector<std::string> entries = mBuffer->emplace(std::move(serializedProto));
+ std::vector<std::string> entries = mBuffer.emplace(std::move(serializedProto));
removedEntries.reserve(removedEntries.size() + entries.size());
removedEntries.insert(removedEntries.end(), std::make_move_iterator(entries.begin()),
std::make_move_iterator(entries.end()));
+
+ entryProto.mutable_removed_layer_handles()->Reserve(
+ static_cast<int32_t>(mRemovedLayerHandles.size()));
+ for (auto& handle : mRemovedLayerHandles) {
+ entryProto.mutable_removed_layer_handles()->Add(handle);
+ }
+ mRemovedLayerHandles.clear();
}
proto::TransactionTraceEntry removedEntryProto;
@@ -229,10 +195,10 @@
base::ScopedLockAssertion assumeLocked(mTraceLock);
mTransactionsAddedToBufferCv.wait(lock, [&]() REQUIRES(mTraceLock) {
proto::TransactionTraceEntry entry;
- if (mBuffer->used() > 0) {
- entry.ParseFromString(mBuffer->back());
+ if (mBuffer.used() > 0) {
+ entry.ParseFromString(mBuffer.back());
}
- return mBuffer->used() > 0 && entry.vsync_id() >= vsyncId;
+ return mBuffer.used() > 0 && entry.vsync_id() >= vsyncId;
});
}
@@ -267,7 +233,14 @@
void TransactionTracing::onHandleRemoved(BBinder* layerHandle) {
std::scoped_lock lock(mTraceLock);
- mLayerHandles.erase(layerHandle);
+ auto it = mLayerHandles.find(layerHandle);
+ if (it == mLayerHandles.end()) {
+ ALOGW("handle not found. %p", layerHandle);
+ return;
+ }
+
+ mRemovedLayerHandles.push_back(it->second);
+ mLayerHandles.erase(it);
}
void TransactionTracing::tryPushToTracingThread() {
@@ -318,7 +291,7 @@
ALOGW("Could not find layer id %d", layerState.layer_id());
continue;
}
- TransactionProtoParser::fromProto(layerState, nullptr, it->second);
+ TransactionProtoParser::mergeFromProto(layerState, nullptr, it->second);
}
}
@@ -352,7 +325,7 @@
std::scoped_lock<std::mutex> lock(mTraceLock);
proto::TransactionTraceFile proto = createTraceFileProto();
addStartingStateToProtoLocked(proto);
- mBuffer->writeToProto(proto);
+ mBuffer.writeToProto(proto);
return proto;
}
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.h b/services/surfaceflinger/Tracing/TransactionTracing.h
index 26a3758..d5d98ce 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.h
+++ b/services/surfaceflinger/Tracing/TransactionTracing.h
@@ -25,17 +25,16 @@
#include <mutex>
#include <thread>
+#include "RingBuffer.h"
#include "TransactionProtoParser.h"
using namespace android::surfaceflinger;
namespace android {
-template <typename FileProto, typename EntryProto>
-class RingBuffer;
-
class SurfaceFlinger;
class TransactionTracingTest;
+
/*
* Records all committed transactions into a ring bufffer.
*
@@ -54,10 +53,6 @@
TransactionTracing();
~TransactionTracing();
- bool enable();
- bool disable();
- bool isEnabled() const;
-
void addQueuedTransaction(const TransactionState&);
void addCommittedTransactions(std::vector<TransactionState>& transactions, int64_t vsyncId);
status_t writeToFile();
@@ -78,8 +73,7 @@
static constexpr auto FILE_NAME = "/data/misc/wmtrace/transactions_trace.winscope";
mutable std::mutex mTraceLock;
- bool mEnabled GUARDED_BY(mTraceLock) = false;
- std::unique_ptr<RingBuffer<proto::TransactionTraceFile, proto::TransactionTraceEntry>> mBuffer
+ RingBuffer<proto::TransactionTraceFile, proto::TransactionTraceEntry> mBuffer
GUARDED_BY(mTraceLock);
size_t mBufferSizeInBytes GUARDED_BY(mTraceLock) = CONTINUOUS_TRACING_BUFFER_SIZE;
std::unordered_map<uint64_t, proto::TransactionState> mQueuedTransactions
@@ -88,6 +82,7 @@
std::vector<proto::LayerCreationArgs> mCreatedLayers GUARDED_BY(mTraceLock);
std::unordered_map<BBinder* /* layerHandle */, int32_t /* layerId */> mLayerHandles
GUARDED_BY(mTraceLock);
+ std::vector<int32_t /* layerId */> mRemovedLayerHandles GUARDED_BY(mTraceLock);
std::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,
@@ -116,7 +111,6 @@
void tryPushToTracingThread() EXCLUDES(mMainThreadLock);
void addStartingStateToProtoLocked(proto::TransactionTraceFile& proto) REQUIRES(mTraceLock);
void updateStartingStateLocked(const proto::TransactionTraceEntry& entry) REQUIRES(mTraceLock);
- status_t writeToFileLocked() REQUIRES(mTraceLock);
// TEST
// Wait until all the committed transactions for the specified vsync id are added to the buffer.
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
index b93d127..72434e9 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
@@ -25,24 +25,21 @@
using gui::IWindowInfosListener;
using gui::WindowInfo;
-struct WindowInfosReportedListener : gui::BnWindowInfosReportedListener {
- explicit WindowInfosReportedListener(std::function<void()> listenerCb)
- : mListenerCb(listenerCb) {}
+struct WindowInfosListenerInvoker::WindowInfosReportedListener
+ : gui::BnWindowInfosReportedListener {
+ explicit WindowInfosReportedListener(WindowInfosListenerInvoker& invoker) : mInvoker(invoker) {}
binder::Status onWindowInfosReported() override {
- if (mListenerCb != nullptr) {
- mListenerCb();
- }
+ mInvoker.windowInfosReported();
return binder::Status::ok();
}
- std::function<void()> mListenerCb;
+ WindowInfosListenerInvoker& mInvoker;
};
-WindowInfosListenerInvoker::WindowInfosListenerInvoker(const sp<SurfaceFlinger>& sf) : mSf(sf) {
- mWindowInfosReportedListener =
- new WindowInfosReportedListener([&]() { windowInfosReported(); });
-}
+WindowInfosListenerInvoker::WindowInfosListenerInvoker(SurfaceFlinger& flinger)
+ : mFlinger(flinger),
+ mWindowInfosReportedListener(sp<WindowInfosReportedListener>::make(*this)) {}
void WindowInfosListenerInvoker::addWindowInfosListener(
const sp<IWindowInfosListener>& windowInfosListener) {
@@ -91,8 +88,8 @@
void WindowInfosListenerInvoker::windowInfosReported() {
mCallbacksPending--;
if (mCallbacksPending == 0) {
- mSf->windowInfosReported();
+ mFlinger.windowInfosReported();
}
}
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h
index 4e08393..2eabf48 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.h
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.h
@@ -31,7 +31,8 @@
class WindowInfosListenerInvoker : public IBinder::DeathRecipient {
public:
- WindowInfosListenerInvoker(const sp<SurfaceFlinger>& sf);
+ explicit WindowInfosListenerInvoker(SurfaceFlinger&);
+
void addWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener);
void removeWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener);
@@ -42,13 +43,15 @@
void binderDied(const wp<IBinder>& who) override;
private:
+ struct WindowInfosReportedListener;
void windowInfosReported();
- const sp<SurfaceFlinger> mSf;
+ SurfaceFlinger& mFlinger;
std::mutex mListenersMutex;
std::unordered_map<wp<IBinder>, const sp<gui::IWindowInfosListener>, WpHash>
mWindowInfosListeners GUARDED_BY(mListenersMutex);
sp<gui::IWindowInfosReportedListener> mWindowInfosReportedListener;
std::atomic<size_t> mCallbacksPending{0};
};
-} // namespace android
\ No newline at end of file
+
+} // namespace android
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index 4529905..2e9e659 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -155,6 +155,7 @@
uint32 height = 2;
uint32 stride = 3;
int32 format = 4;
+ uint64 usage = 5;
}
message BarrierLayerProto {
diff --git a/services/surfaceflinger/layerproto/transactions.proto b/services/surfaceflinger/layerproto/transactions.proto
index e31b502..9b076bd 100644
--- a/services/surfaceflinger/layerproto/transactions.proto
+++ b/services/surfaceflinger/layerproto/transactions.proto
@@ -46,6 +46,7 @@
repeated int32 removed_layers = 5;
repeated DisplayState added_displays = 6;
repeated int32 removed_displays = 7;
+ repeated int32 removed_layer_handles = 8;
}
message LayerCreationArgs {
@@ -62,8 +63,9 @@
int64 vsync_id = 3;
int32 input_event_id = 4;
int64 post_time = 5;
- repeated LayerState layer_changes = 6;
- repeated DisplayState display_changes = 7;
+ uint64 transaction_id = 6;
+ repeated LayerState layer_changes = 7;
+ repeated DisplayState display_changes = 8;
}
// Keep insync with layer_state_t
@@ -78,28 +80,35 @@
eLayerChanged = 0x00000002;
eSizeChanged = 0x00000004;
eAlphaChanged = 0x00000008;
+
eMatrixChanged = 0x00000010;
eTransparentRegionChanged = 0x00000020;
eFlagsChanged = 0x00000040;
eLayerStackChanged = 0x00000080;
+
eReleaseBufferListenerChanged = 0x00000400;
eShadowRadiusChanged = 0x00000800;
+
eLayerCreated = 0x00001000;
eBufferCropChanged = 0x00002000;
eRelativeLayerChanged = 0x00004000;
eReparent = 0x00008000;
+
eColorChanged = 0x00010000;
eDestroySurface = 0x00020000;
eTransformChanged = 0x00040000;
eTransformToDisplayInverseChanged = 0x00080000;
+
eCropChanged = 0x00100000;
eBufferChanged = 0x00200000;
eAcquireFenceChanged = 0x00400000;
eDataspaceChanged = 0x00800000;
+
eHdrMetadataChanged = 0x01000000;
eSurfaceDamageRegionChanged = 0x02000000;
eApiChanged = 0x04000000;
eSidebandStreamChanged = 0x08000000;
+
eColorTransformChanged = 0x10000000;
eHasListenerCallbacksChanged = 0x20000000;
eInputInfoChanged = 0x40000000;
@@ -139,6 +148,7 @@
eLayerSkipScreenshot = 0x40;
eLayerSecure = 0x80;
eEnableBackpressure = 0x100;
+ eLayerIsDisplayDecoration = 0x200;
};
uint32 flags = 9;
uint32 mask = 10;
@@ -181,6 +191,26 @@
}
uint32 flags = 5;
uint64 cached_buffer_id = 6;
+
+ enum PixelFormat {
+ PIXEL_FORMAT_UNKNOWN = 0;
+ PIXEL_FORMAT_CUSTOM = -4;
+ PIXEL_FORMAT_TRANSLUCENT = -3;
+ PIXEL_FORMAT_TRANSPARENT = -2;
+ PIXEL_FORMAT_OPAQUE = -1;
+ PIXEL_FORMAT_RGBA_8888 = 1;
+ PIXEL_FORMAT_RGBX_8888 = 2;
+ PIXEL_FORMAT_RGB_888 = 3;
+ PIXEL_FORMAT_RGB_565 = 4;
+ PIXEL_FORMAT_BGRA_8888 = 5;
+ PIXEL_FORMAT_RGBA_5551 = 6;
+ PIXEL_FORMAT_RGBA_4444 = 7;
+ PIXEL_FORMAT_RGBA_FP16 = 22;
+ PIXEL_FORMAT_RGBA_1010102 = 43;
+ PIXEL_FORMAT_R_8 = 0x38;
+ }
+ PixelFormat pixel_format = 7;
+ uint64 usage = 8;
}
BufferData buffer_data = 22;
int32 api = 23;
diff --git a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
index f6b0def..027a15e 100644
--- a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
+++ b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
@@ -85,7 +85,7 @@
sp<Fence> fence, CallbackHelper& callback, const ReleaseCallbackId& id,
ReleaseBufferCallbackHelper& releaseCallback) {
Transaction t;
- t.setBuffer(layer, buffer, fence, id.framenumber, id, releaseCallback.getCallback());
+ t.setBuffer(layer, buffer, fence, id.framenumber, releaseCallback.getCallback());
t.addTransactionCompletedCallback(callback.function, callback.getContext());
t.apply();
}
@@ -300,7 +300,7 @@
nsecs_t time = systemTime() + std::chrono::nanoseconds(100ms).count();
Transaction t;
- t.setBuffer(layer, firstBuffer, std::nullopt, std::nullopt, firstBufferCallbackId,
+ t.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber,
releaseCallback->getCallback());
t.addTransactionCompletedCallback(transactionCallback.function,
transactionCallback.getContext());
@@ -316,7 +316,7 @@
// Dropping frames in transaction queue emits a callback
sp<GraphicBuffer> secondBuffer = getBuffer();
ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber());
- t.setBuffer(layer, secondBuffer, std::nullopt, std::nullopt, secondBufferCallbackId,
+ t.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber,
releaseCallback->getCallback());
t.addTransactionCompletedCallback(transactionCallback.function,
transactionCallback.getContext());
@@ -360,7 +360,7 @@
Transaction transaction1;
transaction1.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber,
- secondBufferCallbackId, releaseCallback->getCallback());
+ releaseCallback->getCallback());
transaction1.addTransactionCompletedCallback(callback1.function, callback1.getContext());
// Set a different TransactionCompletedListener to mimic a second process
@@ -395,14 +395,14 @@
// Create transaction with a buffer.
Transaction transaction;
transaction.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber,
- firstBufferCallbackId, releaseCallback->getCallback());
+ releaseCallback->getCallback());
sp<GraphicBuffer> secondBuffer = getBuffer();
ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber());
// Call setBuffer on the same transaction with a different buffer.
transaction.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber,
- secondBufferCallbackId, releaseCallback->getCallback());
+ releaseCallback->getCallback());
ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId));
}
@@ -417,7 +417,7 @@
// Create transaction with a buffer.
Transaction transaction1;
transaction1.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber,
- firstBufferCallbackId, releaseCallback->getCallback());
+ releaseCallback->getCallback());
sp<GraphicBuffer> secondBuffer = getBuffer();
ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber());
@@ -425,7 +425,7 @@
// Create a second transaction with a new buffer for the same layer.
Transaction transaction2;
transaction2.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber,
- secondBufferCallbackId, releaseCallback->getCallback());
+ releaseCallback->getCallback());
// merge transaction1 into transaction2 so ensure we get a proper buffer release callback.
transaction1.merge(std::move(transaction2));
@@ -446,7 +446,7 @@
Transaction transaction1;
transaction1.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber,
- firstBufferCallbackId, releaseCallback->getCallback());
+ releaseCallback->getCallback());
// Sent a second buffer to allow the first buffer to get released.
sp<GraphicBuffer> secondBuffer = getBuffer();
@@ -454,7 +454,7 @@
Transaction transaction2;
transaction2.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber,
- secondBufferCallbackId, releaseCallback->getCallback());
+ releaseCallback->getCallback());
// Set a different TransactionCompletedListener to mimic a second process
TransactionCompletedListener::setInstance(secondCompletedListener);
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 5568418..d3be0ea 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -55,6 +55,7 @@
"DisplayTransactionTest.cpp",
"DisplayDevice_GetBestColorModeTest.cpp",
"DisplayDevice_InitiateModeChange.cpp",
+ "DisplayDevice_SetDisplayBrightnessTest.cpp",
"DisplayDevice_SetProjectionTest.cpp",
"EventThreadTest.cpp",
"FlagManagerTest.cpp",
@@ -81,7 +82,6 @@
"SurfaceFlinger_SetPowerModeInternalTest.cpp",
"SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp",
"SchedulerTest.cpp",
- "SchedulerUtilsTest.cpp",
"SetFrameRateTest.cpp",
"RefreshRateConfigsTest.cpp",
"RefreshRateSelectionTest.cpp",
@@ -89,7 +89,6 @@
"RegionSamplingTest.cpp",
"TimeStatsTest.cpp",
"FrameTracerTest.cpp",
- "TimerTest.cpp",
"TransactionApplicationTest.cpp",
"TransactionFrameTracerTest.cpp",
"TransactionProtoParserTest.cpp",
@@ -178,11 +177,12 @@
"server_configurable_flags",
],
header_libs: [
+ "android.hardware.graphics.composer3-command-buffer",
"android.hardware.graphics.composer@2.1-command-buffer",
"android.hardware.graphics.composer@2.2-command-buffer",
"android.hardware.graphics.composer@2.3-command-buffer",
"android.hardware.graphics.composer@2.4-command-buffer",
- "android.hardware.graphics.composer3-command-buffer",
+ "libscheduler_test_headers",
"libsurfaceflinger_headers",
],
}
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index f1e9b31..3716f59 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -30,6 +30,7 @@
#include <gui/IProducerListener.h>
#include <gui/LayerMetadata.h>
#include <log/log.h>
+#include <renderengine/mock/FakeExternalTexture.h>
#include <renderengine/mock/Framebuffer.h>
#include <renderengine/mock/Image.h>
#include <renderengine/mock/RenderEngine.h>
@@ -143,11 +144,10 @@
.WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
- constexpr scheduler::ISchedulerCallback* kCallback = nullptr;
- constexpr bool kHasMultipleConfigs = true;
mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
- std::move(eventThread), std::move(sfEventThread), kCallback,
- kHasMultipleConfigs);
+ std::move(eventThread), std::move(sfEventThread),
+ TestableSurfaceFlinger::SchedulerCallbackImpl::kNoOp,
+ TestableSurfaceFlinger::kTwoDisplayModes);
}
void setupForceGeometryDirty() {
@@ -234,15 +234,13 @@
CaptureArgs::UNSET_UID, visitor);
};
- // TODO: Eliminate expensive/real allocation if possible.
const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
- mCaptureScreenBuffer = std::make_shared<
- renderengine::ExternalTexture>(new GraphicBuffer(renderArea->getReqWidth(),
- renderArea->getReqHeight(),
- HAL_PIXEL_FORMAT_RGBA_8888, 1, usage,
- "screenshot"),
- *mRenderEngine, true);
+ mCaptureScreenBuffer =
+ std::make_shared<renderengine::mock::FakeExternalTexture>(renderArea->getReqWidth(),
+ renderArea->getReqHeight(),
+ HAL_PIXEL_FORMAT_RGBA_8888, 1,
+ usage);
auto result = mFlinger.renderScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer,
forSystem, regionSampling);
@@ -621,7 +619,8 @@
// TODO: use COLOR
EXPECT_CALL(*test->mComposer,
setLayerColor(HWC_DISPLAY, HWC_LAYER,
- IComposerClient::Color({0xff, 0xff, 0xff, 0xff})))
+ aidl::android::hardware::graphics::composer3::Color(
+ {1.0f, 1.0f, 1.0f, 1.0f})))
.Times(1);
}
}
diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
index a9ad249..f613e43 100644
--- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
@@ -37,12 +37,11 @@
class MockVSyncDispatch : public scheduler::VSyncDispatch {
public:
- MOCK_METHOD2(registerCallback,
- CallbackToken(std::function<void(nsecs_t, nsecs_t, nsecs_t)> const&, std::string));
- MOCK_METHOD1(unregisterCallback, void(CallbackToken));
- MOCK_METHOD2(schedule, scheduler::ScheduleResult(CallbackToken, ScheduleTiming));
- MOCK_METHOD1(cancel, scheduler::CancelResult(CallbackToken token));
- MOCK_CONST_METHOD1(dump, void(std::string&));
+ MOCK_METHOD(CallbackToken, registerCallback, (Callback, std::string), (override));
+ MOCK_METHOD(void, unregisterCallback, (CallbackToken), (override));
+ MOCK_METHOD(scheduler::ScheduleResult, schedule, (CallbackToken, ScheduleTiming), (override));
+ MOCK_METHOD(scheduler::CancelResult, cancel, (CallbackToken), (override));
+ MOCK_METHOD(void, dump, (std::string&), (const, override));
MockVSyncDispatch() {
ON_CALL(*this, registerCallback)
diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp
index 5a0033e..40a9b1a 100644
--- a/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp
@@ -44,8 +44,8 @@
mFlinger.onComposerHalHotplug(PrimaryDisplayVariant::HWC_DISPLAY_ID, Connection::CONNECTED);
mDisplay = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this)
- .setSupportedModes({kDisplayMode60, kDisplayMode90, kDisplayMode120})
- .setActiveMode(kDisplayModeId60)
+ .setDisplayModes({kDisplayMode60, kDisplayMode90, kDisplayMode120},
+ kDisplayModeId60)
.inject();
}
diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp
new file mode 100644
index 0000000..73c60e1
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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 "LibSurfaceFlingerUnittests"
+
+#include "DisplayTransactionTestHelpers.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace {
+
+using hal::RenderIntent;
+
+using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
+
+class SetDisplayBrightnessTest : public DisplayTransactionTest {
+public:
+ sp<DisplayDevice> getDisplayDevice() { return injectDefaultInternalDisplay({}); }
+};
+
+TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessNoComposite) {
+ MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD);
+ sp<DisplayDevice> displayDevice = getDisplayDevice();
+
+ EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
+
+ constexpr float kDisplayBrightness = 0.5f;
+ displayDevice->stageBrightness(kDisplayBrightness);
+
+ EXPECT_EQ(0.5f, displayDevice->getStagedBrightness());
+
+ displayDevice->persistBrightness(false);
+
+ EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
+ EXPECT_EQ(std::nullopt, displayDevice->getCompositionDisplay()->getState().displayBrightness);
+}
+
+TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessWithComposite) {
+ MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD);
+ sp<DisplayDevice> displayDevice = getDisplayDevice();
+
+ EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
+
+ constexpr float kDisplayBrightness = 0.5f;
+ displayDevice->stageBrightness(kDisplayBrightness);
+
+ EXPECT_EQ(0.5f, displayDevice->getStagedBrightness());
+
+ displayDevice->persistBrightness(true);
+
+ EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
+ EXPECT_EQ(kDisplayBrightness,
+ displayDevice->getCompositionDisplay()->getState().displayBrightness);
+}
+
+TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessWithCompositeShortCircuitsOnNoOp) {
+ MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD);
+ sp<DisplayDevice> displayDevice = getDisplayDevice();
+
+ EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
+
+ constexpr float kDisplayBrightness = 0.5f;
+ displayDevice->stageBrightness(kDisplayBrightness);
+
+ EXPECT_EQ(0.5f, displayDevice->getStagedBrightness());
+
+ displayDevice->persistBrightness(true);
+
+ EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
+ EXPECT_EQ(kDisplayBrightness,
+ displayDevice->getCompositionDisplay()->getState().displayBrightness);
+ displayDevice->getCompositionDisplay()->editState().displayBrightness = std::nullopt;
+
+ displayDevice->stageBrightness(kDisplayBrightness);
+ EXPECT_EQ(0.5f, displayDevice->getStagedBrightness());
+ displayDevice->persistBrightness(true);
+
+ EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
+ EXPECT_EQ(std::nullopt, displayDevice->getCompositionDisplay()->getState().displayBrightness);
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index b1f704a..2425862 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -60,6 +60,7 @@
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+ mFlinger.resetScheduler(nullptr);
}
void DisplayTransactionTest::injectMockScheduler() {
@@ -76,7 +77,8 @@
mFlinger.setupScheduler(std::unique_ptr<scheduler::VsyncController>(mVsyncController),
std::unique_ptr<scheduler::VSyncTracker>(mVSyncTracker),
std::unique_ptr<EventThread>(mEventThread),
- std::unique_ptr<EventThread>(mSFEventThread), &mSchedulerCallback);
+ std::unique_ptr<EventThread>(mSFEventThread),
+ TestableSurfaceFlinger::SchedulerCallbackImpl::kMock);
}
void DisplayTransactionTest::injectMockComposer(int virtualDisplayCount) {
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index 69ac26e..45eceff 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -48,7 +48,6 @@
#include "mock/DisplayHardware/MockPowerAdvisor.h"
#include "mock/MockEventThread.h"
#include "mock/MockNativeWindowSurface.h"
-#include "mock/MockSchedulerCallback.h"
#include "mock/MockSurfaceInterceptor.h"
#include "mock/MockVsyncController.h"
#include "mock/system/window/MockNativeWindow.h"
@@ -121,7 +120,6 @@
mock::VsyncController* mVsyncController = new mock::VsyncController;
mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker;
- scheduler::mock::SchedulerCallback mSchedulerCallback;
mock::EventThread* mEventThread = new mock::EventThread;
mock::EventThread* mSFEventThread = new mock::EventThread;
diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
index bd4dc59..1dd7dea 100644
--- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
@@ -56,12 +56,11 @@
};
struct MockVSyncDispatch : scheduler::VSyncDispatch {
- MOCK_METHOD2(registerCallback,
- CallbackToken(const std::function<void(nsecs_t, nsecs_t, nsecs_t)>&, std::string));
- MOCK_METHOD1(unregisterCallback, void(CallbackToken));
- MOCK_METHOD2(schedule, scheduler::ScheduleResult(CallbackToken, ScheduleTiming));
- MOCK_METHOD1(cancel, scheduler::CancelResult(CallbackToken token));
- MOCK_CONST_METHOD1(dump, void(std::string&));
+ MOCK_METHOD(CallbackToken, registerCallback, (Callback, std::string), (override));
+ MOCK_METHOD(void, unregisterCallback, (CallbackToken), (override));
+ MOCK_METHOD(scheduler::ScheduleResult, schedule, (CallbackToken, ScheduleTiming), (override));
+ MOCK_METHOD(scheduler::CancelResult, cancel, (CallbackToken token), (override));
+ MOCK_METHOD(void, dump, (std::string&), (const, override));
};
struct MockTokenManager : frametimeline::TokenManager {
diff --git a/services/surfaceflinger/tests/unittests/SchedulerUtilsTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerUtilsTest.cpp
deleted file mode 100644
index 5f6a715..0000000
--- a/services/surfaceflinger/tests/unittests/SchedulerUtilsTest.cpp
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
-#undef LOG_TAG
-#define LOG_TAG "SchedulerUnittests"
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include <array>
-
-#include "Scheduler/SchedulerUtils.h"
-
-namespace android {
-namespace scheduler {
-
-class SchedulerUtilsTest : public testing::Test {
-public:
- SchedulerUtilsTest() = default;
- ~SchedulerUtilsTest() override = default;
-};
-
-namespace {
-TEST_F(SchedulerUtilsTest, calculate_mean) {
- std::array<int64_t, 30> testArray{};
- // Calling the function on empty array returns 0.
- EXPECT_EQ(0, calculate_mean(testArray));
-
- testArray[0] = 33;
- EXPECT_EQ(1, calculate_mean(testArray));
- testArray[1] = 33;
- testArray[2] = 33;
- EXPECT_EQ(3, calculate_mean(testArray));
- testArray[3] = 42;
- EXPECT_EQ(4, calculate_mean(testArray));
- testArray[4] = 33;
- EXPECT_EQ(5, calculate_mean(testArray));
- testArray[5] = 42;
- EXPECT_EQ(7, calculate_mean(testArray));
- for (int i = 6; i < 30; i++) {
- testArray[i] = 33;
- }
- EXPECT_EQ(33, calculate_mean(testArray));
-}
-
-TEST_F(SchedulerUtilsTest, calculate_median) {
- std::vector<int64_t> testVector;
- // Calling the function on empty vector returns 0.
- EXPECT_EQ(0, calculate_median(&testVector));
-
- testVector.push_back(33);
- EXPECT_EQ(33, calculate_median(&testVector));
- testVector.push_back(33);
- testVector.push_back(33);
- EXPECT_EQ(33, calculate_median(&testVector));
- testVector.push_back(42);
- EXPECT_EQ(33, calculate_median(&testVector));
- testVector.push_back(33);
- EXPECT_EQ(33, calculate_median(&testVector));
- testVector.push_back(42);
- EXPECT_EQ(33, calculate_median(&testVector));
- testVector.push_back(42);
- EXPECT_EQ(33, calculate_median(&testVector));
- testVector.push_back(42);
- EXPECT_EQ(42, calculate_median(&testVector));
- testVector.push_back(60);
- EXPECT_EQ(42, calculate_median(&testVector));
- testVector.push_back(60);
- EXPECT_EQ(42, calculate_median(&testVector));
- testVector.push_back(33);
- EXPECT_EQ(42, calculate_median(&testVector));
- testVector.push_back(33);
- EXPECT_EQ(42, calculate_median(&testVector));
- testVector.push_back(33);
- EXPECT_EQ(33, calculate_median(&testVector));
-}
-
-TEST_F(SchedulerUtilsTest, calculate_mode) {
- std::vector<int64_t> testVector;
- // Calling the function on empty vector returns 0.
- EXPECT_EQ(0, calculate_mode(testVector));
-
- testVector.push_back(33);
- EXPECT_EQ(33, calculate_mode(testVector));
- testVector.push_back(33);
- testVector.push_back(33);
- EXPECT_EQ(33, calculate_mode(testVector));
- testVector.push_back(42);
- EXPECT_EQ(33, calculate_mode(testVector));
- testVector.push_back(33);
- EXPECT_EQ(33, calculate_mode(testVector));
- testVector.push_back(42);
- EXPECT_EQ(33, calculate_mode(testVector));
- testVector.push_back(42);
- EXPECT_EQ(33, calculate_mode(testVector));
- testVector.push_back(42);
- EXPECT_EQ(33, calculate_mode(testVector));
- testVector.push_back(60);
- EXPECT_EQ(33, calculate_mode(testVector));
- testVector.push_back(60);
- EXPECT_EQ(33, calculate_mode(testVector));
- testVector.push_back(33);
- // 5 occurences of 33.
- EXPECT_EQ(33, calculate_mode(testVector));
- testVector.push_back(42);
- // 5 occurences of 33, 5 occurences of 42. We choose the first one.
- EXPECT_EQ(33, calculate_mode(testVector));
- testVector.push_back(42);
- // 5 occurences of 33, 6 occurences of 42.
- EXPECT_EQ(42, calculate_mode(testVector));
- testVector.push_back(42);
- // 5 occurences of 33, 7 occurences of 42.
- EXPECT_EQ(42, calculate_mode(testVector));
-}
-
-} // namespace
-} // namespace scheduler
-} // namespace android
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
index fe5f9e0..2b69f13 100644
--- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -164,8 +164,9 @@
.WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
- std::move(eventThread), std::move(sfEventThread), /*callback*/ nullptr,
- /*hasMultipleModes*/ true);
+ std::move(eventThread), std::move(sfEventThread),
+ TestableSurfaceFlinger::SchedulerCallbackImpl::kNoOp,
+ TestableSurfaceFlinger::kTwoDisplayModes);
}
namespace {
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
index 56a0506..3205952 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
@@ -42,13 +42,18 @@
mFlinger.onComposerHalHotplug(PrimaryDisplayVariant::HWC_DISPLAY_ID, Connection::CONNECTED);
- mDisplay = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this)
- .setSupportedModes({kDisplayMode60, kDisplayMode90, kDisplayMode120,
- kDisplayMode90DifferentResolution})
- .setActiveMode(kDisplayModeId60)
- .inject();
+ {
+ DisplayModes modes = {kDisplayMode60, kDisplayMode90, kDisplayMode120,
+ kDisplayMode90DifferentResolution};
+ const DisplayModeId activeModeId = kDisplayModeId60;
+ auto configs = std::make_shared<scheduler::RefreshRateConfigs>(modes, activeModeId);
- setupScheduler();
+ mDisplay = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this)
+ .setDisplayModes(modes, activeModeId, std::move(configs))
+ .inject();
+ }
+
+ setupScheduler(mDisplay->holdRefreshRateConfigs());
// isVsyncPeriodSwitchSupported should return true, otherwise the SF's HWC proxy
// will call setActiveConfig instead of setActiveConfigWithConstraints.
@@ -57,7 +62,7 @@
}
protected:
- void setupScheduler();
+ void setupScheduler(std::shared_ptr<scheduler::RefreshRateConfigs>);
void testChangeRefreshRate(bool isDisplayActive, bool isRefreshRequired);
sp<DisplayDevice> mDisplay;
@@ -108,7 +113,8 @@
.build();
};
-void DisplayModeSwitchingTest::setupScheduler() {
+void DisplayModeSwitchingTest::setupScheduler(
+ std::shared_ptr<scheduler::RefreshRateConfigs> configs) {
auto eventThread = std::make_unique<mock::EventThread>();
mAppEventThread = eventThread.get();
auto sfEventThread = std::make_unique<mock::EventThread>();
@@ -132,8 +138,9 @@
Return(TestableSurfaceFlinger::FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
- std::move(eventThread), std::move(sfEventThread), /*callback*/ nullptr,
- /*hasMultipleModes*/ true);
+ std::move(eventThread), std::move(sfEventThread),
+ TestableSurfaceFlinger::SchedulerCallbackImpl::kNoOp,
+ std::move(configs));
}
TEST_F(DisplayModeSwitchingTest, changeRefreshRate_OnActiveDisplay_WithRefreshRequired) {
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
index b57feff..7948e60 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
@@ -61,7 +61,7 @@
struct EventThreadBaseSupportedVariant {
static void setupVsyncAndEventThreadNoCallExpectations(DisplayTransactionTest* test) {
// The callback should not be notified to toggle VSYNC.
- EXPECT_CALL(test->mSchedulerCallback, setVsyncEnabled(_)).Times(0);
+ EXPECT_CALL(test->mFlinger.mockSchedulerCallback(), setVsyncEnabled(_)).Times(0);
// The event thread should not be notified.
EXPECT_CALL(*test->mEventThread, onScreenReleased()).Times(0);
@@ -88,7 +88,7 @@
struct EventThreadIsSupportedVariant : public EventThreadBaseSupportedVariant {
static void setupAcquireAndEnableVsyncCallExpectations(DisplayTransactionTest* test) {
// The callback should be notified to enable VSYNC.
- EXPECT_CALL(test->mSchedulerCallback, setVsyncEnabled(true)).Times(1);
+ EXPECT_CALL(test->mFlinger.mockSchedulerCallback(), setVsyncEnabled(true)).Times(1);
// The event thread should be notified that the screen was acquired.
EXPECT_CALL(*test->mEventThread, onScreenAcquired()).Times(1);
@@ -96,7 +96,7 @@
static void setupReleaseAndDisableVsyncCallExpectations(DisplayTransactionTest* test) {
// The callback should be notified to disable VSYNC.
- EXPECT_CALL(test->mSchedulerCallback, setVsyncEnabled(false)).Times(1);
+ EXPECT_CALL(test->mFlinger.mockSchedulerCallback(), setVsyncEnabled(false)).Times(1);
// The event thread should not be notified that the screen was released.
EXPECT_CALL(*test->mEventThread, onScreenReleased()).Times(1);
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 0067997..d292e08 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -16,6 +16,9 @@
#pragma once
+#include <algorithm>
+#include <variant>
+
#include <compositionengine/Display.h>
#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/OutputLayer.h>
@@ -24,7 +27,6 @@
#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <compositionengine/mock/DisplaySurface.h>
#include <gui/ScreenCaptureResults.h>
-#include <algorithm>
#include "BufferQueueLayer.h"
#include "BufferStateLayer.h"
@@ -45,6 +47,7 @@
#include "mock/DisplayHardware/MockComposer.h"
#include "mock/MockFrameTimeline.h"
#include "mock/MockFrameTracer.h"
+#include "mock/MockSchedulerCallback.h"
namespace android {
@@ -170,7 +173,7 @@
} // namespace surfaceflinger::test
-class TestableSurfaceFlinger final : private scheduler::ISchedulerCallback {
+class TestableSurfaceFlinger {
public:
using HotplugEvent = SurfaceFlinger::HotplugEvent;
@@ -193,42 +196,64 @@
mFlinger->mCompositionEngine->setTimeStats(timeStats);
}
- // The ISchedulerCallback argument can be nullptr for a no-op implementation.
+ enum class SchedulerCallbackImpl { kNoOp, kMock };
+
+ static constexpr struct OneDisplayMode {
+ } kOneDisplayMode;
+
+ static constexpr struct TwoDisplayModes {
+ } kTwoDisplayModes;
+
+ using RefreshRateConfigsPtr = std::shared_ptr<scheduler::RefreshRateConfigs>;
+
+ using DisplayModesVariant =
+ std::variant<OneDisplayMode, TwoDisplayModes, RefreshRateConfigsPtr>;
+
void setupScheduler(std::unique_ptr<scheduler::VsyncController> vsyncController,
std::unique_ptr<scheduler::VSyncTracker> vsyncTracker,
std::unique_ptr<EventThread> appEventThread,
std::unique_ptr<EventThread> sfEventThread,
- scheduler::ISchedulerCallback* callback = nullptr,
- bool hasMultipleModes = false) {
- DisplayModes modes{DisplayMode::Builder(0)
- .setId(DisplayModeId(0))
- .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
- .setVsyncPeriod(16'666'667)
- .setGroup(0)
- .build()};
+ SchedulerCallbackImpl callbackImpl = SchedulerCallbackImpl::kNoOp,
+ DisplayModesVariant modesVariant = kOneDisplayMode) {
+ RefreshRateConfigsPtr configs;
+ if (std::holds_alternative<RefreshRateConfigsPtr>(modesVariant)) {
+ configs = std::move(std::get<RefreshRateConfigsPtr>(modesVariant));
+ } else {
+ DisplayModes modes = {DisplayMode::Builder(0)
+ .setId(DisplayModeId(0))
+ .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
+ .setVsyncPeriod(16'666'667)
+ .setGroup(0)
+ .build()};
- if (hasMultipleModes) {
- modes.emplace_back(DisplayMode::Builder(1)
- .setId(DisplayModeId(1))
- .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
- .setVsyncPeriod(11'111'111)
- .setGroup(0)
- .build());
+ if (std::holds_alternative<TwoDisplayModes>(modesVariant)) {
+ modes.emplace_back(DisplayMode::Builder(1)
+ .setId(DisplayModeId(1))
+ .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
+ .setVsyncPeriod(11'111'111)
+ .setGroup(0)
+ .build());
+ }
+
+ configs = std::make_shared<scheduler::RefreshRateConfigs>(modes, DisplayModeId(0));
}
- const auto currMode = DisplayModeId(0);
- mRefreshRateConfigs = std::make_shared<scheduler::RefreshRateConfigs>(modes, currMode);
- const auto currFps = mRefreshRateConfigs->getCurrentRefreshRate().getFps();
+ const auto currFps = configs->getCurrentRefreshRate().getFps();
mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(currFps);
mFlinger->mVsyncModulator = sp<scheduler::VsyncModulator>::make(
mFlinger->mVsyncConfiguration->getCurrentConfigs());
mFlinger->mRefreshRateStats =
std::make_unique<scheduler::RefreshRateStats>(*mFlinger->mTimeStats, currFps,
- /*powerMode=*/hal::PowerMode::OFF);
+ hal::PowerMode::OFF);
+
+ using Callback = scheduler::ISchedulerCallback;
+ Callback& callback = callbackImpl == SchedulerCallbackImpl::kNoOp
+ ? static_cast<Callback&>(mNoOpSchedulerCallback)
+ : static_cast<Callback&>(mSchedulerCallback);
mScheduler = new scheduler::TestableScheduler(std::move(vsyncController),
- std::move(vsyncTracker), mRefreshRateConfigs,
- *(callback ?: this));
+ std::move(vsyncTracker), std::move(configs),
+ callback);
mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread));
mFlinger->mSfConnectionHandle = mScheduler->createConnection(std::move(sfEventThread));
@@ -237,7 +262,8 @@
void resetScheduler(scheduler::Scheduler* scheduler) { mFlinger->mScheduler.reset(scheduler); }
- scheduler::TestableScheduler& mutableScheduler() const { return *mScheduler; }
+ scheduler::TestableScheduler& mutableScheduler() { return *mScheduler; }
+ scheduler::mock::SchedulerCallback& mockSchedulerCallback() { return mSchedulerCallback; }
using CreateBufferQueueFunction = surfaceflinger::test::Factory::CreateBufferQueueFunction;
void setCreateBufferQueueFunction(CreateBufferQueueFunction f) {
@@ -347,6 +373,11 @@
auto notifyPowerBoost(int32_t boostId) { return mFlinger->notifyPowerBoost(boostId); }
+ auto setDisplayBrightness(const sp<IBinder>& display,
+ const gui::DisplayBrightness& brightness) {
+ return mFlinger->setDisplayBrightness(display, brightness);
+ }
+
// Allow reading display state without locking, as if called on the SF main thread.
auto setPowerModeInternal(const sp<DisplayDevice>& display,
hal::PowerMode mode) NO_THREAD_SAFETY_ANALYSIS {
@@ -657,23 +688,6 @@
mHwcDisplayId(hwcDisplayId) {
mCreationArgs.connectionType = connectionType;
mCreationArgs.isPrimary = isPrimary;
-
- mCreationArgs.activeModeId = DisplayModeId(0);
- DisplayModePtr activeMode =
- DisplayMode::Builder(FakeHwcDisplayInjector::DEFAULT_ACTIVE_CONFIG)
- .setId(mCreationArgs.activeModeId)
- .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
- .setWidth(FakeHwcDisplayInjector::DEFAULT_WIDTH)
- .setHeight(FakeHwcDisplayInjector::DEFAULT_HEIGHT)
- .setVsyncPeriod(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)
- .setDpiX(FakeHwcDisplayInjector::DEFAULT_DPI)
- .setDpiY(FakeHwcDisplayInjector::DEFAULT_DPI)
- .setGroup(0)
- .build();
-
- DisplayModes modes{activeMode};
- mCreationArgs.supportedModes = modes;
- mCreationArgs.refreshRateConfigs = flinger.mRefreshRateConfigs;
}
sp<IBinder> token() const { return mDisplayToken; }
@@ -696,13 +710,16 @@
auto& mutableDisplayDevice() { return mFlinger.mutableDisplays()[mDisplayToken]; }
- auto& setActiveMode(DisplayModeId mode) {
- mCreationArgs.activeModeId = mode;
- return *this;
- }
-
- auto& setSupportedModes(DisplayModes mode) {
- mCreationArgs.supportedModes = mode;
+ // If `configs` is nullptr, the injector creates RefreshRateConfigs from the `modes`.
+ // Otherwise, it uses `configs`, which the caller must create using the same `modes`.
+ //
+ // TODO(b/182939859): Once `modes` can be retrieved from RefreshRateConfigs, remove
+ // the `configs` parameter in favor of an alternative setRefreshRateConfigs API.
+ auto& setDisplayModes(DisplayModes modes, DisplayModeId activeModeId,
+ std::shared_ptr<scheduler::RefreshRateConfigs> configs = nullptr) {
+ mCreationArgs.supportedModes = std::move(modes);
+ mCreationArgs.activeModeId = activeModeId;
+ mCreationArgs.refreshRateConfigs = std::move(configs);
return *this;
}
@@ -744,39 +761,58 @@
}
sp<DisplayDevice> inject() NO_THREAD_SAFETY_ANALYSIS {
- const auto displayId = mCreationArgs.compositionDisplay->getDisplayId();
+ auto& modes = mCreationArgs.supportedModes;
+ auto& activeModeId = mCreationArgs.activeModeId;
+
+ if (!mCreationArgs.refreshRateConfigs) {
+ if (modes.empty()) {
+ activeModeId = DisplayModeId(0);
+ modes.emplace_back(
+ DisplayMode::Builder(FakeHwcDisplayInjector::DEFAULT_ACTIVE_CONFIG)
+ .setId(activeModeId)
+ .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
+ .setWidth(FakeHwcDisplayInjector::DEFAULT_WIDTH)
+ .setHeight(FakeHwcDisplayInjector::DEFAULT_HEIGHT)
+ .setVsyncPeriod(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)
+ .setDpiX(FakeHwcDisplayInjector::DEFAULT_DPI)
+ .setDpiY(FakeHwcDisplayInjector::DEFAULT_DPI)
+ .setGroup(0)
+ .build());
+ }
+
+ mCreationArgs.refreshRateConfigs =
+ std::make_shared<scheduler::RefreshRateConfigs>(modes, activeModeId);
+ }
DisplayDeviceState state;
if (const auto type = mCreationArgs.connectionType) {
+ const auto displayId = mCreationArgs.compositionDisplay->getDisplayId();
LOG_ALWAYS_FATAL_IF(!displayId);
const auto physicalId = PhysicalDisplayId::tryCast(*displayId);
LOG_ALWAYS_FATAL_IF(!physicalId);
LOG_ALWAYS_FATAL_IF(!mHwcDisplayId);
- const DisplayModePtr activeModePtr =
- *std::find_if(mCreationArgs.supportedModes.begin(),
- mCreationArgs.supportedModes.end(), [&](DisplayModePtr mode) {
- return mode->getId() == mCreationArgs.activeModeId;
- });
+ const auto it = std::find_if(modes.begin(), modes.end(),
+ [&activeModeId](const DisplayModePtr& mode) {
+ return mode->getId() == activeModeId;
+ });
+ LOG_ALWAYS_FATAL_IF(it == modes.end());
+
state.physical = {.id = *physicalId,
.type = *type,
.hwcDisplayId = *mHwcDisplayId,
.deviceProductInfo = {},
- .supportedModes = mCreationArgs.supportedModes,
- .activeMode = activeModePtr};
+ .supportedModes = modes,
+ .activeMode = *it};
}
state.isSecure = mCreationArgs.isSecure;
- mCreationArgs.refreshRateConfigs =
- std::make_shared<scheduler::RefreshRateConfigs>(mCreationArgs.supportedModes,
- mCreationArgs.activeModeId);
-
- sp<DisplayDevice> device = new DisplayDevice(mCreationArgs);
- if (!device->isVirtual()) {
- device->setActiveMode(mCreationArgs.activeModeId);
+ sp<DisplayDevice> display = sp<DisplayDevice>::make(mCreationArgs);
+ if (!display->isVirtual()) {
+ display->setActiveMode(activeModeId);
}
- mFlinger.mutableDisplays().emplace(mDisplayToken, device);
+ mFlinger.mutableDisplays().emplace(mDisplayToken, display);
mFlinger.mutableCurrentState().displays.add(mDisplayToken, state);
mFlinger.mutableDrawingState().displays.add(mDisplayToken, state);
@@ -784,7 +820,7 @@
mFlinger.mutablePhysicalDisplayTokens()[physical->id] = mDisplayToken;
}
- return device;
+ return display;
}
private:
@@ -795,16 +831,12 @@
};
private:
- void scheduleComposite(FrameHint) override {}
- void setVsyncEnabled(bool) override {}
- void changeRefreshRate(const RefreshRate&, DisplayModeEvent) override {}
- void kernelTimerChanged(bool) override {}
- void triggerOnFrameRateOverridesChanged() {}
-
surfaceflinger::test::Factory mFactory;
sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization);
+
+ scheduler::mock::SchedulerCallback mSchedulerCallback;
+ scheduler::mock::NoOpSchedulerCallback mNoOpSchedulerCallback;
scheduler::TestableScheduler* mScheduler = nullptr;
- std::shared_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs;
};
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index 16d4b59..1ce0309 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -434,9 +434,10 @@
static ComposerState createComposerState(int layerId, sp<Fence> fence,
uint32_t stateFlags = layer_state_t::eBufferChanged) {
ComposerState composer_state;
- composer_state.state.bufferData.acquireFence = std::move(fence);
+ composer_state.state.bufferData = std::make_shared<BufferData>();
+ composer_state.state.bufferData->acquireFence = std::move(fence);
composer_state.state.layerId = layerId;
- composer_state.state.bufferData.flags = BufferData::BufferDataChange::fenceChanged;
+ composer_state.state.bufferData->flags = BufferData::BufferDataChange::fenceChanged;
composer_state.state.flags = stateFlags;
return composer_state;
}
diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
index deeb785..5364630 100644
--- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
@@ -22,6 +22,7 @@
#include <gui/SurfaceComposerClient.h>
#include <log/log.h>
#include <renderengine/ExternalTexture.h>
+#include <renderengine/mock/FakeExternalTexture.h>
#include <renderengine/mock/RenderEngine.h>
#include <utils/String8.h>
@@ -101,9 +102,8 @@
sp<BufferStateLayer> layer = createBufferStateLayer();
sp<Fence> fence(new Fence());
- const auto buffer = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0);
int32_t layerId = layer->getSequence();
- uint64_t bufferId = buffer->getId();
+ uint64_t bufferId = 42;
uint64_t frameNumber = 5;
nsecs_t dequeueTime = 10;
nsecs_t postTime = 20;
@@ -115,13 +115,16 @@
traceTimestamp(layerId, bufferId, frameNumber, postTime,
FrameTracer::FrameEvent::QUEUE, /*duration*/ 0));
BufferData bufferData;
- bufferData.buffer = buffer;
bufferData.acquireFence = fence;
bufferData.frameNumber = frameNumber;
bufferData.flags |= BufferData::BufferDataChange::fenceChanged;
bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged;
- layer->setBuffer(bufferData, postTime, /*desiredPresentTime*/ 30, false, dequeueTime,
- FrameTimelineInfo{});
+ std::shared_ptr<renderengine::ExternalTexture> externalTexture = std::make_shared<
+ renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/, bufferId,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0ULL /*usage*/);
+ layer->setBuffer(externalTexture, bufferData, postTime, /*desiredPresentTime*/ 30, false,
+ dequeueTime, FrameTimelineInfo{});
commitTransaction(layer.get());
bool computeVisisbleRegions;
diff --git a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
index 6e00748..271b1c0 100644
--- a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
@@ -39,6 +39,7 @@
layer_state_t layer;
layer.layerId = 6;
layer.what = std::numeric_limits<uint64_t>::max();
+ layer.what &= ~static_cast<uint64_t>(layer_state_t::eBufferChanged);
layer.x = 7;
layer.matrix.dsdx = 15;
diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
index 704340d..5bb4c92 100644
--- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
@@ -22,6 +22,7 @@
#include <gui/SurfaceComposerClient.h>
#include <log/log.h>
#include <renderengine/ExternalTexture.h>
+#include <renderengine/mock/FakeExternalTexture.h>
#include <renderengine/mock/RenderEngine.h>
#include <utils/String8.h>
@@ -114,14 +115,17 @@
sp<BufferStateLayer> layer = createBufferStateLayer();
sp<Fence> fence(new Fence());
auto acquireFence = fenceFactory.createFenceTimeForTest(fence);
- const auto buffer = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0);
BufferData bufferData;
- bufferData.buffer = buffer;
bufferData.acquireFence = fence;
bufferData.frameNumber = 1;
bufferData.flags |= BufferData::BufferDataChange::fenceChanged;
bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged;
- layer->setBuffer(bufferData, 10, 20, false, std::nullopt,
+ std::shared_ptr<renderengine::ExternalTexture> externalTexture = std::make_shared<
+ renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/,
+ 1ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0ULL /*usage*/);
+ layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt,
{/*vsyncId*/ 1, /*inputEventId*/ 0});
acquireFence->signalForTest(12);
@@ -145,14 +149,17 @@
sp<Fence> fence1(new Fence());
auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1);
- const auto buffer1 = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0);
BufferData bufferData;
- bufferData.buffer = buffer1;
bufferData.acquireFence = fence1;
bufferData.frameNumber = 1;
bufferData.flags |= BufferData::BufferDataChange::fenceChanged;
bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged;
- layer->setBuffer(bufferData, 10, 20, false, std::nullopt,
+ std::shared_ptr<renderengine::ExternalTexture> externalTexture1 = std::make_shared<
+ renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/,
+ 1ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0ULL /*usage*/);
+ layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt,
{/*vsyncId*/ 1, /*inputEventId*/ 0});
EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
@@ -160,14 +167,17 @@
sp<Fence> fence2(new Fence());
auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2);
- const auto buffer2 = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0);
nsecs_t start = systemTime();
- bufferData.buffer = buffer2;
bufferData.acquireFence = fence2;
bufferData.frameNumber = 1;
bufferData.flags |= BufferData::BufferDataChange::fenceChanged;
bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged;
- layer->setBuffer(bufferData, 10, 20, false, std::nullopt,
+ std::shared_ptr<renderengine::ExternalTexture> externalTexture2 = std::make_shared<
+ renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/,
+ 2ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0ULL /*usage*/);
+ layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt,
{/*vsyncId*/ 1, /*inputEventId*/ 0});
nsecs_t end = systemTime();
acquireFence2->signalForTest(12);
@@ -203,14 +213,17 @@
sp<Fence> fence(new Fence());
auto acquireFence = fenceFactory.createFenceTimeForTest(fence);
- const auto buffer = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0);
BufferData bufferData;
- bufferData.buffer = buffer;
bufferData.acquireFence = fence;
bufferData.frameNumber = 1;
bufferData.flags |= BufferData::BufferDataChange::fenceChanged;
bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged;
- layer->setBuffer(bufferData, 10, 20, false, std::nullopt,
+ std::shared_ptr<renderengine::ExternalTexture> externalTexture = std::make_shared<
+ renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/,
+ 1ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0ULL /*usage*/);
+ layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt,
{/*vsyncId*/ 1, /*inputEventId*/ 0});
acquireFence->signalForTest(12);
@@ -234,14 +247,17 @@
sp<BufferStateLayer> layer = createBufferStateLayer();
sp<Fence> fence(new Fence());
auto acquireFence = fenceFactory.createFenceTimeForTest(fence);
- const auto buffer = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0);
BufferData bufferData;
- bufferData.buffer = buffer;
bufferData.acquireFence = fence;
bufferData.frameNumber = 1;
bufferData.flags |= BufferData::BufferDataChange::fenceChanged;
bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged;
- layer->setBuffer(bufferData, 10, 20, false, std::nullopt,
+ std::shared_ptr<renderengine::ExternalTexture> externalTexture = std::make_shared<
+ renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/,
+ 1ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0ULL /*usage*/);
+ layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt,
{/*vsyncId*/ 1, /*inputEventId*/ 0});
EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
@@ -269,14 +285,17 @@
sp<Fence> fence(new Fence());
auto acquireFence = fenceFactory.createFenceTimeForTest(fence);
- const auto buffer = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0);
BufferData bufferData;
- bufferData.buffer = buffer;
bufferData.acquireFence = fence;
bufferData.frameNumber = 1;
bufferData.flags |= BufferData::BufferDataChange::fenceChanged;
bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged;
- layer->setBuffer(bufferData, 10, 20, false, std::nullopt,
+ std::shared_ptr<renderengine::ExternalTexture> externalTexture = std::make_shared<
+ renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/,
+ 1ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0ULL /*usage*/);
+ layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt,
{/*vsyncId*/ 3, /*inputEventId*/ 0});
EXPECT_EQ(2u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
@@ -310,27 +329,33 @@
sp<Fence> fence1(new Fence());
auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1);
- const auto buffer1 = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0);
BufferData bufferData;
- bufferData.buffer = buffer1;
bufferData.acquireFence = fence1;
bufferData.frameNumber = 1;
bufferData.flags |= BufferData::BufferDataChange::fenceChanged;
bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged;
- layer->setBuffer(bufferData, 10, 20, false, std::nullopt,
+ std::shared_ptr<renderengine::ExternalTexture> externalTexture1 = std::make_shared<
+ renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/,
+ 1ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0ULL /*usage*/);
+ layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt,
{/*vsyncId*/ 1, /*inputEventId*/ 0});
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
const auto droppedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX;
sp<Fence> fence2(new Fence());
auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2);
- const auto buffer2 = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0);
- bufferData.buffer = buffer2;
bufferData.acquireFence = fence2;
bufferData.frameNumber = 1;
bufferData.flags |= BufferData::BufferDataChange::fenceChanged;
bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged;
- layer->setBuffer(bufferData, 10, 20, false, std::nullopt,
+ std::shared_ptr<renderengine::ExternalTexture> externalTexture2 = std::make_shared<
+ renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/,
+ 1ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0ULL /*usage*/);
+ layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt,
{/*vsyncId*/ 1, /*inputEventId*/ 0});
acquireFence2->signalForTest(12);
@@ -356,14 +381,17 @@
sp<Fence> fence1(new Fence());
auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1);
- const auto buffer1 = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0);
BufferData bufferData;
- bufferData.buffer = buffer1;
bufferData.acquireFence = fence1;
bufferData.frameNumber = 1;
bufferData.flags |= BufferData::BufferDataChange::fenceChanged;
bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged;
- layer->setBuffer(bufferData, 10, 20, false, std::nullopt,
+ std::shared_ptr<renderengine::ExternalTexture> externalTexture1 = std::make_shared<
+ renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/,
+ 1ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0ULL /*usage*/);
+ layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt,
{/*vsyncId*/ 1, /*inputEventId*/ 0});
EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
@@ -371,14 +399,17 @@
sp<Fence> fence2(new Fence());
auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2);
- const auto buffer2 = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0);
auto dropStartTime1 = systemTime();
- bufferData.buffer = buffer2;
bufferData.acquireFence = fence2;
bufferData.frameNumber = 1;
bufferData.flags |= BufferData::BufferDataChange::fenceChanged;
bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged;
- layer->setBuffer(bufferData, 10, 20, false, std::nullopt,
+ std::shared_ptr<renderengine::ExternalTexture> externalTexture2 = std::make_shared<
+ renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/,
+ 1ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0ULL /*usage*/);
+ layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt,
{/*vsyncId*/ FrameTimelineInfo::INVALID_VSYNC_ID, /*inputEventId*/ 0});
auto dropEndTime1 = systemTime();
EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
@@ -387,14 +418,17 @@
sp<Fence> fence3(new Fence());
auto acquireFence3 = fenceFactory.createFenceTimeForTest(fence3);
- const auto buffer3 = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0);
auto dropStartTime2 = systemTime();
- bufferData.buffer = buffer3;
bufferData.acquireFence = fence3;
bufferData.frameNumber = 1;
bufferData.flags |= BufferData::BufferDataChange::fenceChanged;
bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged;
- layer->setBuffer(bufferData, 10, 20, false, std::nullopt,
+ std::shared_ptr<renderengine::ExternalTexture> externalTexture3 = std::make_shared<
+ renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/,
+ 1ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0ULL /*usage*/);
+ layer->setBuffer(externalTexture3, bufferData, 10, 20, false, std::nullopt,
{/*vsyncId*/ 2, /*inputEventId*/ 0});
auto dropEndTime2 = systemTime();
acquireFence3->signalForTest(12);
@@ -432,14 +466,17 @@
std::vector<std::shared_ptr<frametimeline::SurfaceFrame>> bufferlessSurfaceFrames;
for (int i = 0; i < 10; i += 2) {
sp<Fence> fence(new Fence());
- const auto buffer = new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0);
BufferData bufferData;
- bufferData.buffer = buffer;
bufferData.acquireFence = fence;
bufferData.frameNumber = 1;
bufferData.flags |= BufferData::BufferDataChange::fenceChanged;
bufferData.flags |= BufferData::BufferDataChange::frameNumberChanged;
- layer->setBuffer(bufferData, 10, 20, false, std::nullopt,
+ std::shared_ptr<renderengine::ExternalTexture> externalTexture = std::make_shared<
+ renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/,
+ 1ULL /* bufferId */,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ 0ULL /*usage*/);
+ layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt,
{/*vsyncId*/ 1, /*inputEventId*/ 0});
layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 2,
/*inputEventId*/ 0},
diff --git a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
index 43b09fd..5ac5812 100644
--- a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
@@ -29,79 +29,32 @@
class TransactionTracingTest : public testing::Test {
protected:
static constexpr size_t SMALL_BUFFER_SIZE = 1024;
- std::unique_ptr<android::TransactionTracing> mTracing;
- void SetUp() override { mTracing = std::make_unique<android::TransactionTracing>(); }
+ TransactionTracing mTracing;
- void TearDown() override {
- mTracing->disable();
- mTracing.reset();
- }
+ void flush(int64_t vsyncId) { mTracing.flush(vsyncId); }
+ proto::TransactionTraceFile writeToProto() { return mTracing.writeToProto(); }
- auto getCommittedTransactions() {
- std::scoped_lock<std::mutex> lock(mTracing->mMainThreadLock);
- return mTracing->mCommittedTransactions;
- }
-
- auto getQueuedTransactions() {
- std::scoped_lock<std::mutex> lock(mTracing->mTraceLock);
- return mTracing->mQueuedTransactions;
- }
-
- auto getUsedBufferSize() {
- std::scoped_lock<std::mutex> lock(mTracing->mTraceLock);
- return mTracing->mBuffer->used();
- }
-
- auto flush(int64_t vsyncId) { return mTracing->flush(vsyncId); }
-
- auto bufferFront() {
- std::scoped_lock<std::mutex> lock(mTracing->mTraceLock);
+ proto::TransactionTraceEntry bufferFront() {
+ std::scoped_lock<std::mutex> lock(mTracing.mTraceLock);
proto::TransactionTraceEntry entry;
- entry.ParseFromString(mTracing->mBuffer->front());
+ entry.ParseFromString(mTracing.mBuffer.front());
return entry;
}
- bool threadIsJoinable() {
- std::scoped_lock lock(mTracing->mMainThreadLock);
- return mTracing->mThread.joinable();
- }
-
- proto::TransactionTraceFile writeToProto() { return mTracing->writeToProto(); }
-
- auto getCreatedLayers() {
- std::scoped_lock<std::mutex> lock(mTracing->mTraceLock);
- return mTracing->mCreatedLayers;
- }
-
- auto getStartingStates() {
- std::scoped_lock<std::mutex> lock(mTracing->mTraceLock);
- return mTracing->mStartingStates;
- }
-
void queueAndCommitTransaction(int64_t vsyncId) {
TransactionState transaction;
transaction.id = static_cast<uint64_t>(vsyncId * 3);
transaction.originUid = 1;
transaction.originPid = 2;
- mTracing->addQueuedTransaction(transaction);
+ mTracing.addQueuedTransaction(transaction);
std::vector<TransactionState> transactions;
transactions.emplace_back(transaction);
- mTracing->addCommittedTransactions(transactions, vsyncId);
+ mTracing.addCommittedTransactions(transactions, vsyncId);
flush(vsyncId);
}
- // Test that we clean up the tracing thread and free any memory allocated.
- void verifyDisabledTracingState() {
- EXPECT_FALSE(mTracing->isEnabled());
- EXPECT_FALSE(threadIsJoinable());
- EXPECT_EQ(getCommittedTransactions().size(), 0u);
- EXPECT_EQ(getQueuedTransactions().size(), 0u);
- EXPECT_EQ(getUsedBufferSize(), 0u);
- EXPECT_EQ(getStartingStates().size(), 0u);
- }
-
void verifyEntry(const proto::TransactionTraceEntry& actualProto,
- const std::vector<TransactionState> expectedTransactions,
+ const std::vector<TransactionState>& expectedTransactions,
int64_t expectedVsyncId) {
EXPECT_EQ(actualProto.vsync_id(), expectedVsyncId);
EXPECT_EQ(actualProto.transactions().size(),
@@ -113,16 +66,7 @@
}
};
-TEST_F(TransactionTracingTest, enable) {
- EXPECT_FALSE(mTracing->isEnabled());
- mTracing->enable();
- EXPECT_TRUE(mTracing->isEnabled());
- mTracing->disable();
- verifyDisabledTracingState();
-}
-
TEST_F(TransactionTracingTest, addTransactions) {
- mTracing->enable();
std::vector<TransactionState> transactions;
transactions.reserve(100);
for (uint64_t i = 0; i < 100; i++) {
@@ -130,7 +74,7 @@
transaction.id = i;
transaction.originPid = static_cast<int32_t>(i);
transactions.emplace_back(transaction);
- mTracing->addQueuedTransaction(transaction);
+ mTracing.addQueuedTransaction(transaction);
}
// Split incoming transactions into two and commit them in reverse order to test out of order
@@ -138,12 +82,12 @@
std::vector<TransactionState> firstTransactionSet =
std::vector<TransactionState>(transactions.begin() + 50, transactions.end());
int64_t firstTransactionSetVsyncId = 42;
- mTracing->addCommittedTransactions(firstTransactionSet, firstTransactionSetVsyncId);
+ mTracing.addCommittedTransactions(firstTransactionSet, firstTransactionSetVsyncId);
int64_t secondTransactionSetVsyncId = 43;
std::vector<TransactionState> secondTransactionSet =
std::vector<TransactionState>(transactions.begin(), transactions.begin() + 50);
- mTracing->addCommittedTransactions(secondTransactionSet, secondTransactionSetVsyncId);
+ mTracing.addCommittedTransactions(secondTransactionSet, secondTransactionSetVsyncId);
flush(secondTransactionSetVsyncId);
proto::TransactionTraceFile proto = writeToProto();
@@ -151,24 +95,19 @@
// skip starting entry
verifyEntry(proto.entry(1), firstTransactionSet, firstTransactionSetVsyncId);
verifyEntry(proto.entry(2), secondTransactionSet, secondTransactionSetVsyncId);
-
- mTracing->disable();
- verifyDisabledTracingState();
}
class TransactionTracingLayerHandlingTest : public TransactionTracingTest {
protected:
void SetUp() override {
- TransactionTracingTest::SetUp();
- mTracing->enable();
// add layers
- mTracing->setBufferSize(SMALL_BUFFER_SIZE);
+ mTracing.setBufferSize(SMALL_BUFFER_SIZE);
const sp<IBinder> fakeLayerHandle = new BBinder();
- mTracing->onLayerAdded(fakeLayerHandle->localBinder(), mParentLayerId, "parent",
- 123 /* flags */, -1 /* parentId */);
+ mTracing.onLayerAdded(fakeLayerHandle->localBinder(), mParentLayerId, "parent",
+ 123 /* flags */, -1 /* parentId */);
const sp<IBinder> fakeChildLayerHandle = new BBinder();
- mTracing->onLayerAdded(fakeChildLayerHandle->localBinder(), mChildLayerId, "child",
- 456 /* flags */, mParentLayerId);
+ mTracing.onLayerAdded(fakeChildLayerHandle->localBinder(), mChildLayerId, "child",
+ 456 /* flags */, mParentLayerId);
// add some layer transaction
{
@@ -184,12 +123,12 @@
childState.state.what = layer_state_t::eLayerChanged;
childState.state.z = 43;
transaction.states.add(childState);
- mTracing->addQueuedTransaction(transaction);
+ mTracing.addQueuedTransaction(transaction);
std::vector<TransactionState> transactions;
transactions.emplace_back(transaction);
VSYNC_ID_FIRST_LAYER_CHANGE = ++mVsyncId;
- mTracing->addCommittedTransactions(transactions, VSYNC_ID_FIRST_LAYER_CHANGE);
+ mTracing.addCommittedTransactions(transactions, VSYNC_ID_FIRST_LAYER_CHANGE);
flush(VSYNC_ID_FIRST_LAYER_CHANGE);
}
@@ -204,31 +143,25 @@
layerState.state.z = 41;
layerState.state.x = 22;
transaction.states.add(layerState);
- mTracing->addQueuedTransaction(transaction);
+ mTracing.addQueuedTransaction(transaction);
std::vector<TransactionState> transactions;
transactions.emplace_back(transaction);
VSYNC_ID_SECOND_LAYER_CHANGE = ++mVsyncId;
- mTracing->addCommittedTransactions(transactions, VSYNC_ID_SECOND_LAYER_CHANGE);
+ mTracing.addCommittedTransactions(transactions, VSYNC_ID_SECOND_LAYER_CHANGE);
flush(VSYNC_ID_SECOND_LAYER_CHANGE);
}
// remove child layer
- mTracing->onLayerRemoved(2);
+ mTracing.onLayerRemoved(2);
VSYNC_ID_CHILD_LAYER_REMOVED = ++mVsyncId;
queueAndCommitTransaction(VSYNC_ID_CHILD_LAYER_REMOVED);
// remove layer
- mTracing->onLayerRemoved(1);
+ mTracing.onLayerRemoved(1);
queueAndCommitTransaction(++mVsyncId);
}
- void TearDown() override {
- mTracing->disable();
- verifyDisabledTracingState();
- TransactionTracingTest::TearDown();
- }
-
int mParentLayerId = 1;
int mChildLayerId = 2;
int64_t mVsyncId = 0;
@@ -298,16 +231,14 @@
class TransactionTracingMirrorLayerTest : public TransactionTracingTest {
protected:
void SetUp() override {
- TransactionTracingTest::SetUp();
- mTracing->enable();
// add layers
- mTracing->setBufferSize(SMALL_BUFFER_SIZE);
+ mTracing.setBufferSize(SMALL_BUFFER_SIZE);
const sp<IBinder> fakeLayerHandle = new BBinder();
- mTracing->onLayerAdded(fakeLayerHandle->localBinder(), mLayerId, "Test Layer",
- 123 /* flags */, -1 /* parentId */);
+ mTracing.onLayerAdded(fakeLayerHandle->localBinder(), mLayerId, "Test Layer",
+ 123 /* flags */, -1 /* parentId */);
const sp<IBinder> fakeMirrorLayerHandle = new BBinder();
- mTracing->onMirrorLayerAdded(fakeMirrorLayerHandle->localBinder(), mMirrorLayerId, "Mirror",
- mLayerId);
+ mTracing.onMirrorLayerAdded(fakeMirrorLayerHandle->localBinder(), mMirrorLayerId, "Mirror",
+ mLayerId);
// add some layer transaction
{
@@ -323,21 +254,15 @@
mirrorState.state.what = layer_state_t::eLayerChanged;
mirrorState.state.z = 43;
transaction.states.add(mirrorState);
- mTracing->addQueuedTransaction(transaction);
+ mTracing.addQueuedTransaction(transaction);
std::vector<TransactionState> transactions;
transactions.emplace_back(transaction);
- mTracing->addCommittedTransactions(transactions, ++mVsyncId);
+ mTracing.addCommittedTransactions(transactions, ++mVsyncId);
flush(mVsyncId);
}
}
- void TearDown() override {
- mTracing->disable();
- verifyDisabledTracingState();
- TransactionTracingTest::TearDown();
- }
-
int mLayerId = 5;
int mMirrorLayerId = 55;
int64_t mVsyncId = 0;
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
index 42b1993..2da266b 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
@@ -14,14 +14,15 @@
* limitations under the License.
*/
-#include "Scheduler/TimeKeeper.h"
-#include "Scheduler/Timer.h"
-#include "Scheduler/VSyncDispatchTimerQueue.h"
-#include "Scheduler/VSyncTracker.h"
+#include <thread>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-#include <thread>
+
+#include <scheduler/Timer.h>
+
+#include "Scheduler/VSyncDispatchTimerQueue.h"
+#include "Scheduler/VSyncTracker.h"
using namespace testing;
using namespace std::literals;
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
index ddc02bf..b7f968d 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -23,16 +23,19 @@
#define LOG_TAG "LibSurfaceFlingerUnittests"
#define LOG_NDEBUG 0
-#include "Scheduler/TimeKeeper.h"
-#include "Scheduler/VSyncDispatchTimerQueue.h"
-#include "Scheduler/VSyncTracker.h"
+#include <thread>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-#include <thread>
+
+#include <scheduler/TimeKeeper.h>
+
+#include "Scheduler/VSyncDispatchTimerQueue.h"
+#include "Scheduler/VSyncTracker.h"
using namespace testing;
using namespace std::literals;
+
namespace android::scheduler {
class MockVSyncTracker : public VSyncTracker {
@@ -71,10 +74,10 @@
ON_CALL(*this, now()).WillByDefault(Invoke(this, &ControllableClock::fakeTime));
}
- MOCK_CONST_METHOD0(now, nsecs_t());
- MOCK_METHOD2(alarmAt, void(std::function<void()> const&, nsecs_t time));
- MOCK_METHOD0(alarmCancel, void());
- MOCK_CONST_METHOD1(dump, void(std::string&));
+ MOCK_METHOD(nsecs_t, now, (), (const));
+ MOCK_METHOD(void, alarmAt, (std::function<void()>, nsecs_t), (override));
+ MOCK_METHOD(void, alarmCancel, (), (override));
+ MOCK_METHOD(void, dump, (std::string&), (const, override));
void alarmAtDefaultBehavior(std::function<void()> const& callback, nsecs_t time) {
mCallback = callback;
@@ -196,11 +199,14 @@
class TimeKeeperWrapper : public TimeKeeper {
public:
TimeKeeperWrapper(TimeKeeper& control) : mControllableClock(control) {}
- void alarmAt(std::function<void()> const& callback, nsecs_t time) final {
- mControllableClock.alarmAt(callback, time);
- }
- void alarmCancel() final { mControllableClock.alarmCancel(); }
+
nsecs_t now() const final { return mControllableClock.now(); }
+
+ void alarmAt(std::function<void()> callback, nsecs_t time) final {
+ mControllableClock.alarmAt(std::move(callback), time);
+ }
+
+ void alarmCancel() final { mControllableClock.alarmCancel(); }
void dump(std::string&) const final {}
private:
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index 5826a9b..4eb9055 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -22,19 +22,22 @@
#define LOG_TAG "LibSurfaceFlingerUnittests"
#define LOG_NDEBUG 0
-#include "Scheduler/TimeKeeper.h"
-#include "Scheduler/VSyncDispatch.h"
-#include "Scheduler/VSyncReactor.h"
-#include "Scheduler/VSyncTracker.h"
+#include <array>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <ui/Fence.h>
#include <ui/FenceTime.h>
-#include <array>
+
+#include <scheduler/TimeKeeper.h>
+
+#include "Scheduler/VSyncDispatch.h"
+#include "Scheduler/VSyncReactor.h"
+#include "Scheduler/VSyncTracker.h"
using namespace testing;
using namespace std::literals;
+
namespace android::scheduler {
class MockVSyncTracker : public VSyncTracker {
@@ -65,14 +68,12 @@
std::shared_ptr<Clock> const mClock;
};
-class MockVSyncDispatch : public VSyncDispatch {
-public:
- MOCK_METHOD2(registerCallback,
- CallbackToken(std::function<void(nsecs_t, nsecs_t, nsecs_t)> const&, std::string));
- MOCK_METHOD1(unregisterCallback, void(CallbackToken));
- MOCK_METHOD2(schedule, ScheduleResult(CallbackToken, ScheduleTiming));
- MOCK_METHOD1(cancel, CancelResult(CallbackToken token));
- MOCK_CONST_METHOD1(dump, void(std::string&));
+struct MockVSyncDispatch : VSyncDispatch {
+ MOCK_METHOD(CallbackToken, registerCallback, (Callback, std::string), (override));
+ MOCK_METHOD(void, unregisterCallback, (CallbackToken), (override));
+ MOCK_METHOD(ScheduleResult, schedule, (CallbackToken, ScheduleTiming), (override));
+ MOCK_METHOD(CancelResult, cancel, (CallbackToken), (override));
+ MOCK_METHOD(void, dump, (std::string&), (const, override));
};
std::shared_ptr<android::FenceTime> generateInvalidFence() {
@@ -497,4 +498,4 @@
} // namespace android::scheduler
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wextra"
\ No newline at end of file
+#pragma clang diagnostic pop // ignored "-Wextra"
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 8c51313..4273401 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -97,7 +97,8 @@
MOCK_METHOD3(setLayerSurfaceDamage,
Error(Display, Layer, const std::vector<IComposerClient::Rect>&));
MOCK_METHOD3(setLayerBlendMode, Error(Display, Layer, IComposerClient::BlendMode));
- MOCK_METHOD3(setLayerColor, Error(Display, Layer, const IComposerClient::Color&));
+ MOCK_METHOD3(setLayerColor,
+ Error(Display, Layer, const aidl::android::hardware::graphics::composer3::Color&));
MOCK_METHOD3(setLayerCompositionType,
Error(Display, Layer, aidl::android::hardware::graphics::composer3::Composition));
MOCK_METHOD3(setLayerDataspace, Error(Display, Layer, Dataspace));
@@ -120,7 +121,7 @@
Error(Display, uint64_t, uint64_t, DisplayedFrameStats*));
MOCK_METHOD3(setLayerPerFrameMetadataBlobs,
Error(Display, Layer, const std::vector<IComposerClient::PerFrameMetadataBlob>&));
- MOCK_METHOD2(setDisplayBrightness, Error(Display, float));
+ MOCK_METHOD3(setDisplayBrightness, Error(Display, float, const DisplayBrightnessOptions&));
MOCK_METHOD2(
getDisplayCapabilities,
Error(Display,
@@ -134,6 +135,10 @@
V2_4::Error(Display, Config, const IComposerClient::VsyncPeriodChangeConstraints&,
VsyncPeriodChangeTimeline*));
MOCK_METHOD2(setAutoLowLatencyMode, V2_4::Error(Display, bool));
+ MOCK_METHOD2(getBootDisplayConfigSupport, Error(Display, bool*));
+ MOCK_METHOD2(setBootDisplayConfig, Error(Display, Config));
+ MOCK_METHOD1(clearBootDisplayConfig, Error(Display));
+ MOCK_METHOD2(getPreferredBootDisplayConfig, Error(Display, Config*));
MOCK_METHOD2(getSupportedContentTypes,
V2_4::Error(Display, std::vector<IComposerClient::ContentType>*));
MOCK_METHOD2(setContentType, V2_4::Error(Display, IComposerClient::ContentType));
@@ -145,6 +150,8 @@
MOCK_METHOD3(getClientTargetProperty,
Error(Display, IComposerClient::ClientTargetProperty*, float*));
MOCK_METHOD3(setLayerWhitePointNits, Error(Display, Layer, float));
+ MOCK_METHOD3(setLayerBlockingRegion,
+ Error(Display, Layer, const std::vector<IComposerClient::Rect>&));
};
} // namespace Hwc2::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
index 821fc8f..9015944 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
@@ -80,11 +80,15 @@
MOCK_METHOD(hal::Error, presentOrValidate,
(nsecs_t, uint32_t *, uint32_t *, android::sp<android::Fence> *, uint32_t *),
(override));
- MOCK_METHOD(std::future<hal::Error>, setDisplayBrightness, (float), (override));
+ MOCK_METHOD(std::future<hal::Error>, setDisplayBrightness,
+ (float, const Hwc2::Composer::DisplayBrightnessOptions &), (override));
MOCK_METHOD(hal::Error, setActiveConfigWithConstraints,
(hal::HWConfigId, const hal::VsyncPeriodChangeConstraints &,
hal::VsyncPeriodChangeTimeline *),
(override));
+ MOCK_METHOD(hal::Error, setBootDisplayConfig, (hal::HWConfigId), (override));
+ MOCK_METHOD(hal::Error, clearBootDisplayConfig, (), (override));
+ MOCK_METHOD(hal::Error, getPreferredBootDisplayConfig, (hal::HWConfigId *), (const, override));
MOCK_METHOD(hal::Error, setAutoLowLatencyMode, (bool), (override));
MOCK_METHOD(hal::Error, getSupportedContentTypes, (std::vector<hal::ContentType> *),
(const, override));
@@ -106,7 +110,8 @@
(override));
MOCK_METHOD(hal::Error, setSurfaceDamage, (const android::Region &), (override));
MOCK_METHOD(hal::Error, setBlendMode, (hal::BlendMode), (override));
- MOCK_METHOD(hal::Error, setColor, (hal::Color), (override));
+ MOCK_METHOD(hal::Error, setColor, (aidl::android::hardware::graphics::composer3::Color),
+ (override));
MOCK_METHOD(hal::Error, setCompositionType,
(aidl::android::hardware::graphics::composer3::Composition), (override));
MOCK_METHOD(hal::Error, setDataspace, (android::ui::Dataspace), (override));
@@ -123,6 +128,7 @@
MOCK_METHOD(hal::Error, setLayerGenericMetadata,
(const std::string &, bool, const std::vector<uint8_t> &), (override));
MOCK_METHOD(hal::Error, setWhitePointNits, (float whitePointNits), (override));
+ MOCK_METHOD(hal::Error, setBlockingRegion, (const android::Region &), (override));
};
} // namespace android::HWC2::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
index 23b849a..c598cbc 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
@@ -37,11 +37,10 @@
MOCK_METHOD(bool, supportsPowerHintSession, (), (override));
MOCK_METHOD(bool, isPowerHintSessionRunning, (), (override));
MOCK_METHOD(void, setTargetWorkDuration, (int64_t targetDurationNanos), (override));
- MOCK_METHOD(void, setPowerHintSessionThreadIds, (const std::vector<int32_t>& threadIds),
- (override));
MOCK_METHOD(void, sendActualWorkDuration, (int64_t actualDurationNanos, nsecs_t timestamp),
(override));
MOCK_METHOD(void, enablePowerHint, (bool enabled), (override));
+ MOCK_METHOD(bool, startPowerHintSession, (const std::vector<int32_t>& threadIds), (override));
};
} // namespace android::Hwc2::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
index 8b48e1c..0840a2f 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
@@ -34,6 +34,7 @@
MOCK_METHOD0(createClone, sp<Layer>());
MOCK_CONST_METHOD0(getFrameRateForLayerTree, FrameRate());
MOCK_CONST_METHOD0(getOwnerUid, uid_t());
+ MOCK_CONST_METHOD0(getDataSpace, ui::Dataspace());
};
} // namespace android::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
index 849e308..c90b8ed 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
@@ -35,7 +35,7 @@
void setVsyncEnabled(bool) override {}
void changeRefreshRate(const RefreshRate&, DisplayModeEvent) override {}
void kernelTimerChanged(bool) override {}
- void triggerOnFrameRateOverridesChanged() {}
+ void triggerOnFrameRateOverridesChanged() override {}
};
} // namespace android::scheduler::mock