Merge "Remove toggle for display brightness apis."
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 34ccb21..8da1352 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -11,6 +11,286 @@
# Grant unix world read/write permissions to kernel tracepoints.
# Access control to these files is now entirely in selinux policy.
+ chmod 0755 /sys/kernel/debug/tracing/events
+ chmod 0755 /sys/kernel/debug/tracing/events/binder
+ chmod 0755 /sys/kernel/debug/tracing/events/binder/binder_lock
+ chmod 0755 /sys/kernel/debug/tracing/events/binder/binder_locked
+ chmod 0755 /sys/kernel/debug/tracing/events/binder/binder_set_priority
+ chmod 0755 /sys/kernel/debug/tracing/events/binder/binder_transaction
+ chmod 0755 /sys/kernel/debug/tracing/events/binder/binder_transaction_alloc_buf
+ chmod 0755 /sys/kernel/debug/tracing/events/binder/binder_transaction_received
+ chmod 0755 /sys/kernel/debug/tracing/events/binder/binder_unlock
+ chmod 0755 /sys/kernel/debug/tracing/events/block
+ chmod 0755 /sys/kernel/debug/tracing/events/block/block_rq_complete
+ chmod 0755 /sys/kernel/debug/tracing/events/block/block_rq_issue
+ chmod 0755 /sys/kernel/debug/tracing/events/cgroup
+ chmod 0755 /sys/kernel/debug/tracing/events/clk
+ chmod 0755 /sys/kernel/debug/tracing/events/clk/clk_disable
+ chmod 0755 /sys/kernel/debug/tracing/events/clk/clk_enable
+ chmod 0755 /sys/kernel/debug/tracing/events/clk/clk_set_rate
+ chmod 0755 /sys/kernel/debug/tracing/events/cpufreq_interactive
+ chmod 0755 /sys/kernel/debug/tracing/events/cpuhp
+ chmod 0755 /sys/kernel/debug/tracing/events/cpuhp/cpuhp_enter
+ chmod 0755 /sys/kernel/debug/tracing/events/cpuhp/cpuhp_exit
+ chmod 0755 /sys/kernel/debug/tracing/events/cpuhp/cpuhp_pause
+ chmod 0755 /sys/kernel/debug/tracing/events/dma_fence
+ chmod 0755 /sys/kernel/debug/tracing/events/ext4
+ chmod 0755 /sys/kernel/debug/tracing/events/ext4/ext4_da_write_begin
+ chmod 0755 /sys/kernel/debug/tracing/events/ext4/ext4_da_write_end
+ chmod 0755 /sys/kernel/debug/tracing/events/ext4/ext4_es_lookup_extent_enter
+ chmod 0755 /sys/kernel/debug/tracing/events/ext4/ext4_es_lookup_extent_exit
+ chmod 0755 /sys/kernel/debug/tracing/events/ext4/ext4_load_inode
+ chmod 0755 /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter
+ chmod 0755 /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit
+ chmod 0755 /sys/kernel/debug/tracing/events/f2fs
+ chmod 0755 /sys/kernel/debug/tracing/events/f2fs/f2fs_get_data_block
+ chmod 0755 /sys/kernel/debug/tracing/events/f2fs/f2fs_iget
+ chmod 0755 /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_enter
+ chmod 0755 /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_exit
+ chmod 0755 /sys/kernel/debug/tracing/events/f2fs/f2fs_write_begin
+ chmod 0755 /sys/kernel/debug/tracing/events/f2fs/f2fs_write_end
+ chmod 0755 /sys/kernel/debug/tracing/events/fence
+ chmod 0755 /sys/kernel/debug/tracing/events/filemap
+ chmod 0755 /sys/kernel/debug/tracing/events/filemap/mm_filemap_add_to_page_cache
+ chmod 0755 /sys/kernel/debug/tracing/events/filemap/mm_filemap_delete_from_page_cache
+ chmod 0755 /sys/kernel/debug/tracing/events/gpu_mem
+ chmod 0755 /sys/kernel/debug/tracing/events/gpu_mem/gpu_mem_total
+ chmod 0755 /sys/kernel/debug/tracing/events/i2c
+ chmod 0755 /sys/kernel/debug/tracing/events/i2c/i2c_read
+ chmod 0755 /sys/kernel/debug/tracing/events/i2c/i2c_reply
+ chmod 0755 /sys/kernel/debug/tracing/events/i2c/i2c_result
+ chmod 0755 /sys/kernel/debug/tracing/events/i2c/i2c_write
+ chmod 0755 /sys/kernel/debug/tracing/events/i2c/smbus_read
+ chmod 0755 /sys/kernel/debug/tracing/events/i2c/smbus_reply
+ chmod 0755 /sys/kernel/debug/tracing/events/i2c/smbus_result
+ chmod 0755 /sys/kernel/debug/tracing/events/i2c/smbus_write
+ chmod 0755 /sys/kernel/debug/tracing/events/ion
+ chmod 0755 /sys/kernel/debug/tracing/events/ion/ion_stat
+ chmod 0755 /sys/kernel/debug/tracing/events/ipi
+ chmod 0755 /sys/kernel/debug/tracing/events/ipi/ipi_entry
+ chmod 0755 /sys/kernel/debug/tracing/events/ipi/ipi_exit
+ chmod 0755 /sys/kernel/debug/tracing/events/ipi/ipi_raise
+ chmod 0755 /sys/kernel/debug/tracing/events/irq
+ chmod 0755 /sys/kernel/debug/tracing/events/irq/irq_handler_entry
+ chmod 0755 /sys/kernel/debug/tracing/events/irq/irq_handler_exit
+ chmod 0755 /sys/kernel/debug/tracing/events/irq/softirq_entry
+ chmod 0755 /sys/kernel/debug/tracing/events/irq/softirq_exit
+ chmod 0755 /sys/kernel/debug/tracing/events/irq/softirq_raise
+ chmod 0755 /sys/kernel/debug/tracing/events/irq/tasklet_entry
+ chmod 0755 /sys/kernel/debug/tracing/events/irq/tasklet_exit
+ chmod 0755 /sys/kernel/debug/tracing/events/irq/tasklet_hi_entry
+ chmod 0755 /sys/kernel/debug/tracing/events/irq/tasklet_hi_exit
+ chmod 0755 /sys/kernel/debug/tracing/events/kmem
+ chmod 0755 /sys/kernel/debug/tracing/events/kmem/ion_heap_grow
+ chmod 0755 /sys/kernel/debug/tracing/events/kmem/ion_heap_shrink
+ chmod 0755 /sys/kernel/debug/tracing/events/kmem/rss_stat
+ chmod 0755 /sys/kernel/debug/tracing/events/lowmemorykiller
+ chmod 0755 /sys/kernel/debug/tracing/events/lowmemorykiller/lowmemory_kill
+ chmod 0755 /sys/kernel/debug/tracing/events/mm_event
+ chmod 0755 /sys/kernel/debug/tracing/events/mm_event/mm_event_record
+ chmod 0755 /sys/kernel/debug/tracing/events/oom
+ chmod 0755 /sys/kernel/debug/tracing/events/oom/mark_victim
+ chmod 0755 /sys/kernel/debug/tracing/events/oom/oom_score_adj_update
+ chmod 0755 /sys/kernel/debug/tracing/events/power
+ chmod 0755 /sys/kernel/debug/tracing/events/power/clock_disable
+ chmod 0755 /sys/kernel/debug/tracing/events/power/clock_enable
+ chmod 0755 /sys/kernel/debug/tracing/events/power/clock_set_rate
+ chmod 0755 /sys/kernel/debug/tracing/events/power/cpu_frequency
+ chmod 0755 /sys/kernel/debug/tracing/events/power/cpu_frequency_limits
+ chmod 0755 /sys/kernel/debug/tracing/events/power/cpu_idle
+ chmod 0755 /sys/kernel/debug/tracing/events/power/gpu_frequency
+ chmod 0755 /sys/kernel/debug/tracing/events/power/suspend_resume
+ chmod 0755 /sys/kernel/debug/tracing/events/sched
+ chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_blocked_reason
+ chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug
+ chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_pi_setprio
+ chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_process_exit
+ chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_process_free
+ chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_switch
+ chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_wakeup
+ chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_wakeup_new
+ chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_waking
+ chmod 0755 /sys/kernel/debug/tracing/events/signal
+ chmod 0755 /sys/kernel/debug/tracing/events/signal/signal_deliver
+ chmod 0755 /sys/kernel/debug/tracing/events/signal/signal_generate
+ chmod 0755 /sys/kernel/debug/tracing/events/sync
+ chmod 0755 /sys/kernel/debug/tracing/events/task
+ chmod 0755 /sys/kernel/debug/tracing/events/task/task_newtask
+ chmod 0755 /sys/kernel/debug/tracing/events/task/task_rename
+ chmod 0755 /sys/kernel/debug/tracing/events/thermal
+ chmod 0755 /sys/kernel/debug/tracing/events/thermal/cdev_update
+ chmod 0755 /sys/kernel/debug/tracing/events/thermal/thermal_temperature
+ chmod 0755 /sys/kernel/debug/tracing/events/vmscan
+ chmod 0755 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin
+ chmod 0755 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end
+ chmod 0755 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep
+ chmod 0755 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake
+ chmod 0755 /sys/kernel/debug/tracing/options
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu0
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu1
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu2
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu3
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu4
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu5
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu6
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu7
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu8
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu9
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu10
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu11
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu12
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu13
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu14
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu15
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu16
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu17
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu18
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu19
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu20
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu21
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu22
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu23
+ chmod 0755 /sys/kernel/tracing/events
+ chmod 0755 /sys/kernel/tracing/events/binder
+ chmod 0755 /sys/kernel/tracing/events/binder/binder_lock
+ chmod 0755 /sys/kernel/tracing/events/binder/binder_locked
+ chmod 0755 /sys/kernel/tracing/events/binder/binder_set_priority
+ chmod 0755 /sys/kernel/tracing/events/binder/binder_transaction
+ chmod 0755 /sys/kernel/tracing/events/binder/binder_transaction_alloc_buf
+ chmod 0755 /sys/kernel/tracing/events/binder/binder_transaction_received
+ chmod 0755 /sys/kernel/tracing/events/binder/binder_unlock
+ chmod 0755 /sys/kernel/tracing/events/block
+ chmod 0755 /sys/kernel/tracing/events/block/block_rq_complete
+ chmod 0755 /sys/kernel/tracing/events/block/block_rq_issue
+ chmod 0755 /sys/kernel/tracing/events/cgroup
+ chmod 0755 /sys/kernel/tracing/events/clk
+ chmod 0755 /sys/kernel/tracing/events/clk/clk_disable
+ chmod 0755 /sys/kernel/tracing/events/clk/clk_enable
+ chmod 0755 /sys/kernel/tracing/events/clk/clk_set_rate
+ chmod 0755 /sys/kernel/tracing/events/cpufreq_interactive
+ chmod 0755 /sys/kernel/tracing/events/cpuhp
+ chmod 0755 /sys/kernel/tracing/events/cpuhp/cpuhp_enter
+ chmod 0755 /sys/kernel/tracing/events/cpuhp/cpuhp_exit
+ chmod 0755 /sys/kernel/tracing/events/cpuhp/cpuhp_pause
+ chmod 0755 /sys/kernel/tracing/events/dma_fence
+ chmod 0755 /sys/kernel/tracing/events/ext4
+ chmod 0755 /sys/kernel/tracing/events/ext4/ext4_da_write_begin
+ chmod 0755 /sys/kernel/tracing/events/ext4/ext4_da_write_end
+ chmod 0755 /sys/kernel/tracing/events/ext4/ext4_es_lookup_extent_enter
+ chmod 0755 /sys/kernel/tracing/events/ext4/ext4_es_lookup_extent_exit
+ chmod 0755 /sys/kernel/tracing/events/ext4/ext4_load_inode
+ chmod 0755 /sys/kernel/tracing/events/ext4/ext4_sync_file_enter
+ chmod 0755 /sys/kernel/tracing/events/ext4/ext4_sync_file_exit
+ chmod 0755 /sys/kernel/tracing/events/f2fs
+ chmod 0755 /sys/kernel/tracing/events/f2fs/f2fs_get_data_block
+ chmod 0755 /sys/kernel/tracing/events/f2fs/f2fs_iget
+ chmod 0755 /sys/kernel/tracing/events/f2fs/f2fs_sync_file_enter
+ chmod 0755 /sys/kernel/tracing/events/f2fs/f2fs_sync_file_exit
+ chmod 0755 /sys/kernel/tracing/events/f2fs/f2fs_write_begin
+ chmod 0755 /sys/kernel/tracing/events/f2fs/f2fs_write_end
+ chmod 0755 /sys/kernel/tracing/events/fence
+ chmod 0755 /sys/kernel/tracing/events/filemap
+ chmod 0755 /sys/kernel/tracing/events/filemap/mm_filemap_add_to_page_cache
+ chmod 0755 /sys/kernel/tracing/events/filemap/mm_filemap_delete_from_page_cache
+ chmod 0755 /sys/kernel/tracing/events/gpu_mem
+ chmod 0755 /sys/kernel/tracing/events/gpu_mem/gpu_mem_total
+ chmod 0755 /sys/kernel/tracing/events/i2c
+ chmod 0755 /sys/kernel/tracing/events/i2c/i2c_read
+ chmod 0755 /sys/kernel/tracing/events/i2c/i2c_reply
+ chmod 0755 /sys/kernel/tracing/events/i2c/i2c_result
+ chmod 0755 /sys/kernel/tracing/events/i2c/i2c_write
+ chmod 0755 /sys/kernel/tracing/events/i2c/smbus_read
+ chmod 0755 /sys/kernel/tracing/events/i2c/smbus_reply
+ chmod 0755 /sys/kernel/tracing/events/i2c/smbus_result
+ chmod 0755 /sys/kernel/tracing/events/i2c/smbus_write
+ chmod 0755 /sys/kernel/tracing/events/ion
+ chmod 0755 /sys/kernel/tracing/events/ion/ion_stat
+ chmod 0755 /sys/kernel/tracing/events/ipi
+ chmod 0755 /sys/kernel/tracing/events/ipi/ipi_entry
+ chmod 0755 /sys/kernel/tracing/events/ipi/ipi_exit
+ chmod 0755 /sys/kernel/tracing/events/ipi/ipi_raise
+ chmod 0755 /sys/kernel/tracing/events/irq
+ chmod 0755 /sys/kernel/tracing/events/irq/irq_handler_entry
+ chmod 0755 /sys/kernel/tracing/events/irq/irq_handler_exit
+ chmod 0755 /sys/kernel/tracing/events/irq/softirq_entry
+ chmod 0755 /sys/kernel/tracing/events/irq/softirq_exit
+ chmod 0755 /sys/kernel/tracing/events/irq/softirq_raise
+ chmod 0755 /sys/kernel/tracing/events/irq/tasklet_entry
+ chmod 0755 /sys/kernel/tracing/events/irq/tasklet_exit
+ chmod 0755 /sys/kernel/tracing/events/irq/tasklet_hi_entry
+ chmod 0755 /sys/kernel/tracing/events/irq/tasklet_hi_exit
+ chmod 0755 /sys/kernel/tracing/events/kmem
+ chmod 0755 /sys/kernel/tracing/events/kmem/ion_heap_grow
+ chmod 0755 /sys/kernel/tracing/events/kmem/ion_heap_shrink
+ chmod 0755 /sys/kernel/tracing/events/kmem/rss_stat
+ chmod 0755 /sys/kernel/tracing/events/lowmemorykiller
+ chmod 0755 /sys/kernel/tracing/events/lowmemorykiller/lowmemory_kill
+ chmod 0755 /sys/kernel/tracing/events/mm_event
+ chmod 0755 /sys/kernel/tracing/events/mm_event/mm_event_record
+ chmod 0755 /sys/kernel/tracing/events/oom
+ chmod 0755 /sys/kernel/tracing/events/oom/mark_victim
+ chmod 0755 /sys/kernel/tracing/events/oom/oom_score_adj_update
+ chmod 0755 /sys/kernel/tracing/events/power
+ chmod 0755 /sys/kernel/tracing/events/power/clock_disable
+ chmod 0755 /sys/kernel/tracing/events/power/clock_enable
+ chmod 0755 /sys/kernel/tracing/events/power/clock_set_rate
+ chmod 0755 /sys/kernel/tracing/events/power/cpu_frequency
+ chmod 0755 /sys/kernel/tracing/events/power/cpu_frequency_limits
+ chmod 0755 /sys/kernel/tracing/events/power/cpu_idle
+ chmod 0755 /sys/kernel/tracing/events/power/gpu_frequency
+ chmod 0755 /sys/kernel/tracing/events/power/suspend_resume
+ chmod 0755 /sys/kernel/tracing/events/sched
+ chmod 0755 /sys/kernel/tracing/events/sched/sched_blocked_reason
+ chmod 0755 /sys/kernel/tracing/events/sched/sched_cpu_hotplug
+ chmod 0755 /sys/kernel/tracing/events/sched/sched_pi_setprio
+ chmod 0755 /sys/kernel/tracing/events/sched/sched_process_exit
+ chmod 0755 /sys/kernel/tracing/events/sched/sched_process_free
+ chmod 0755 /sys/kernel/tracing/events/sched/sched_switch
+ chmod 0755 /sys/kernel/tracing/events/sched/sched_wakeup
+ chmod 0755 /sys/kernel/tracing/events/sched/sched_wakeup_new
+ chmod 0755 /sys/kernel/tracing/events/sched/sched_waking
+ chmod 0755 /sys/kernel/tracing/events/signal
+ chmod 0755 /sys/kernel/tracing/events/signal/signal_deliver
+ chmod 0755 /sys/kernel/tracing/events/signal/signal_generate
+ chmod 0755 /sys/kernel/tracing/events/sync
+ chmod 0755 /sys/kernel/tracing/events/task
+ chmod 0755 /sys/kernel/tracing/events/task/task_newtask
+ chmod 0755 /sys/kernel/tracing/events/task/task_rename
+ chmod 0755 /sys/kernel/tracing/events/thermal
+ chmod 0755 /sys/kernel/tracing/events/thermal/cdev_update
+ chmod 0755 /sys/kernel/tracing/events/thermal/thermal_temperature
+ chmod 0755 /sys/kernel/tracing/events/vmscan
+ chmod 0755 /sys/kernel/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin
+ chmod 0755 /sys/kernel/tracing/events/vmscan/mm_vmscan_direct_reclaim_end
+ chmod 0755 /sys/kernel/tracing/events/vmscan/mm_vmscan_kswapd_sleep
+ chmod 0755 /sys/kernel/tracing/events/vmscan/mm_vmscan_kswapd_wake
+ chmod 0755 /sys/kernel/tracing/options
+ chmod 0755 /sys/kernel/tracing/per_cpu
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu0
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu1
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu2
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu3
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu4
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu5
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu6
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu7
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu8
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu9
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu10
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu11
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu12
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu13
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu14
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu15
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu16
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu17
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu18
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu19
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu20
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu21
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu22
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu23
chmod 0666 /sys/kernel/debug/tracing/trace_clock
chmod 0666 /sys/kernel/tracing/trace_clock
chmod 0666 /sys/kernel/debug/tracing/buffer_size_kb
diff --git a/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/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 6aa32b8..e978e79 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -140,8 +140,8 @@
PrepareEnvironmentVariables();
- if (!EnsureBootImageAndDalvikCache()) {
- LOG(ERROR) << "Bad boot image.";
+ if (!EnsureDalvikCache()) {
+ LOG(ERROR) << "Bad dalvik cache.";
return 5;
}
@@ -349,8 +349,8 @@
}
}
- // Ensure that we have the right boot image and cache file structures.
- bool EnsureBootImageAndDalvikCache() const {
+ // Ensure that we have the right cache file structures.
+ bool EnsureDalvikCache() const {
if (parameters_.instruction_set == nullptr) {
LOG(ERROR) << "Instruction set missing.";
return false;
@@ -376,15 +376,6 @@
}
}
- // Check whether we have a boot image.
- // TODO: check that the files are correct wrt/ jars.
- std::string preopted_boot_art_path =
- StringPrintf("/apex/com.android.art/javalib/%s/boot.art", isa);
- if (access(preopted_boot_art_path.c_str(), F_OK) != 0) {
- PLOG(ERROR) << "Bad access() to " << preopted_boot_art_path;
- return false;
- }
-
return true;
}
diff --git a/cmds/installd/run_dex2oat.cpp b/cmds/installd/run_dex2oat.cpp
index b661684..51c4589 100644
--- a/cmds/installd/run_dex2oat.cpp
+++ b/cmds/installd/run_dex2oat.cpp
@@ -50,10 +50,6 @@
static constexpr const char* kMinidebugDex2oatFlag = "--generate-mini-debug-info";
static constexpr const char* kDisableCompactDexFlag = "--compact-dex-level=none";
-// Location of the JIT Zygote image.
-static const char* kJitZygoteImage =
- "boot.art:/nonx/boot-framework.art!/system/etc/boot-image.prof";
-
std::vector<std::string> SplitBySpaces(const std::string& str) {
if (str.empty()) {
return {};
@@ -84,9 +80,9 @@
int target_sdk_version,
bool enable_hidden_api_checks,
bool generate_compact_dex,
- bool use_jitzygote_image,
+ bool use_jitzygote,
const char* compilation_reason) {
- PrepareBootImageFlags(use_jitzygote_image);
+ PrepareBootImageFlags(use_jitzygote);
PrepareInputFileFlags(output_oat, output_vdex, output_image, input_dex, input_vdex,
dex_metadata, profile, swap_fd, class_loader_context,
@@ -112,14 +108,14 @@
RunDex2Oat::~RunDex2Oat() {}
-void RunDex2Oat::PrepareBootImageFlags(bool use_jitzygote_image) {
- std::string boot_image;
- if (use_jitzygote_image) {
- boot_image = StringPrintf("--boot-image=%s", kJitZygoteImage);
+void RunDex2Oat::PrepareBootImageFlags(bool use_jitzygote) {
+ if (use_jitzygote) {
+ // Don't pass a boot image because JIT Zygote should decide which image to use. Typically,
+ // it does not use any boot image on disk.
+ AddArg("--force-jit-zygote");
} else {
- boot_image = MapPropertyToArg("dalvik.vm.boot-image", "--boot-image=%s");
+ AddArg(MapPropertyToArg("dalvik.vm.boot-image", "--boot-image=%s"));
}
- AddArg(boot_image);
}
void RunDex2Oat::PrepareInputFileFlags(const UniqueFile& output_oat,
diff --git a/cmds/installd/run_dex2oat.h b/cmds/installd/run_dex2oat.h
index 475e124..559244f 100644
--- a/cmds/installd/run_dex2oat.h
+++ b/cmds/installd/run_dex2oat.h
@@ -50,13 +50,13 @@
int target_sdk_version,
bool enable_hidden_api_checks,
bool generate_compact_dex,
- bool use_jitzygote_image,
+ bool use_jitzygote,
const char* compilation_reason);
void Exec(int exit_code);
protected:
- void PrepareBootImageFlags(bool use_jitzygote_image);
+ void PrepareBootImageFlags(bool use_jitzygote);
void PrepareInputFileFlags(const UniqueFile& output_oat,
const UniqueFile& output_vdex,
const UniqueFile& output_image,
diff --git a/cmds/installd/run_dex2oat_test.cpp b/cmds/installd/run_dex2oat_test.cpp
index 0a638cd..2a8135a 100644
--- a/cmds/installd/run_dex2oat_test.cpp
+++ b/cmds/installd/run_dex2oat_test.cpp
@@ -114,7 +114,7 @@
int target_sdk_version = 0;
bool enable_hidden_api_checks = false;
bool generate_compact_dex = true;
- bool use_jitzygote_image = false;
+ bool use_jitzygote = false;
const char* compilation_reason = nullptr;
};
@@ -175,6 +175,7 @@
default_expected_flags_["--swap-fd"] = FLAG_UNUSED;
default_expected_flags_["--class-loader-context"] = FLAG_UNUSED;
default_expected_flags_["--class-loader-context-fds"] = FLAG_UNUSED;
+ default_expected_flags_["--boot-image"] = FLAG_UNUSED;
// Arch
default_expected_flags_["--instruction-set"] = "=arm64";
@@ -190,6 +191,7 @@
default_expected_flags_["--max-image-block-size"] = FLAG_UNUSED;
default_expected_flags_["--very-large-app-threshold"] = FLAG_UNUSED;
default_expected_flags_["--resolve-startup-const-strings"] = FLAG_UNUSED;
+ default_expected_flags_["--force-jit-zygote"] = FLAG_UNUSED;
// Debug
default_expected_flags_["--debuggable"] = FLAG_UNUSED;
@@ -256,7 +258,7 @@
args->target_sdk_version,
args->enable_hidden_api_checks,
args->generate_compact_dex,
- args->use_jitzygote_image,
+ args->use_jitzygote,
args->compilation_reason);
runner.Exec(/*exit_code=*/ 0);
}
@@ -557,5 +559,22 @@
VerifyExpectedFlags();
}
+TEST_F(RunDex2OatTest, UseJitZygoteImage) {
+ auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+ args->use_jitzygote = true;
+ CallRunDex2Oat(std::move(args));
+
+ SetExpectedFlagUsed("--force-jit-zygote", "");
+ VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, BootImage) {
+ setSystemProperty("dalvik.vm.boot-image", "foo.art:bar.art");
+ CallRunDex2Oat(RunDex2OatArgs::MakeDefaultTestArgs());
+
+ SetExpectedFlagUsed("--boot-image", "=foo.art:bar.art");
+ VerifyExpectedFlags();
+}
+
} // namespace installd
} // namespace android
diff --git a/data/etc/android.hardware.type.automotive.xml b/data/etc/android.hardware.type.automotive.xml
index a9b4b05..113945b 100644
--- a/data/etc/android.hardware.type.automotive.xml
+++ b/data/etc/android.hardware.type.automotive.xml
@@ -17,4 +17,6 @@
<!-- These features determine that the device running android is a car. -->
<permissions>
<feature name="android.hardware.type.automotive" />
+ <!-- TODO: Revert this after enabling work profiles refer b/170332519 -->
+ <unavailable-feature name="android.software.managed_users"/>
</permissions>
diff --git a/data/etc/android.software.opengles.deqp.level-2022-03-01.xml b/data/etc/android.software.opengles.deqp.level-2022-03-01.xml
new file mode 100644
index 0000000..0a11835
--- /dev/null
+++ b/data/etc/android.software.opengles.deqp.level-2022-03-01.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- This is the standard feature indicating that the device passes OpenGL ES
+ dEQP tests associated with date 2022-03-01 (0x07E60301). -->
+<permissions>
+ <feature name="android.software.opengles.deqp.level" version="132514561" />
+</permissions>
diff --git a/data/etc/android.software.vulkan.deqp.level-2022-03-01.xml b/data/etc/android.software.vulkan.deqp.level-2022-03-01.xml
new file mode 100644
index 0000000..8deebc0
--- /dev/null
+++ b/data/etc/android.software.vulkan.deqp.level-2022-03-01.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- This is the standard feature indicating that the device passes Vulkan dEQP
+ tests associated with date 2022-03-01 (0x07E60301). -->
+<permissions>
+ <feature name="android.software.vulkan.deqp.level" version="132514561" />
+</permissions>
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/Android.bp b/libs/binder/Android.bp
index f60b32e..7448308 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -202,7 +202,6 @@
sanitize: {
misc_undefined: ["integer"],
},
- min_sdk_version: "30",
tidy: true,
tidy_flags: [
@@ -330,7 +329,6 @@
cc_library {
name: "libbinder_rpc_unstable",
srcs: ["libbinder_rpc_unstable.cpp"],
- defaults: ["libbinder_ndk_host_user"],
shared_libs: [
"libbase",
"libbinder",
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 55d3d70..13f0a4c 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -352,11 +352,6 @@
return gDisableBackgroundScheduling.load(std::memory_order_relaxed);
}
-sp<ProcessState> IPCThreadState::process()
-{
- return mProcess;
-}
-
status_t IPCThreadState::clearLastError()
{
const status_t err = mLastError;
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 93ed50e..ace5cd5 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -287,8 +287,8 @@
RpcConnectionHeader header;
if (status == OK) {
- status = client->interruptableReadFully(server->mShutdownTrigger.get(), &header,
- sizeof(header), {});
+ iovec iov{&header, sizeof(header)};
+ status = client->interruptableReadFully(server->mShutdownTrigger.get(), &iov, 1, {});
if (status != OK) {
ALOGE("Failed to read ID for client connecting to RPC server: %s",
statusToString(status).c_str());
@@ -301,8 +301,9 @@
if (header.sessionIdSize > 0) {
if (header.sessionIdSize == kSessionIdBytes) {
sessionId.resize(header.sessionIdSize);
- status = client->interruptableReadFully(server->mShutdownTrigger.get(),
- sessionId.data(), sessionId.size(), {});
+ iovec iov{sessionId.data(), sessionId.size()};
+ status =
+ client->interruptableReadFully(server->mShutdownTrigger.get(), &iov, 1, {});
if (status != OK) {
ALOGE("Failed to read session ID for client connecting to RPC server: %s",
statusToString(status).c_str());
@@ -331,8 +332,8 @@
.version = protocolVersion,
};
- status = client->interruptableWriteFully(server->mShutdownTrigger.get(), &response,
- sizeof(response), {});
+ iovec iov{&response, sizeof(response)};
+ status = client->interruptableWriteFully(server->mShutdownTrigger.get(), &iov, 1, {});
if (status != OK) {
ALOGE("Failed to send new session response: %s", statusToString(status).c_str());
// still need to cleanup before we can return
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index a5a2bb1..b84395e 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -615,8 +615,9 @@
header.options |= RPC_CONNECTION_OPTION_INCOMING;
}
+ iovec headerIov{&header, sizeof(header)};
auto sendHeaderStatus =
- server->interruptableWriteFully(mShutdownTrigger.get(), &header, sizeof(header), {});
+ server->interruptableWriteFully(mShutdownTrigger.get(), &headerIov, 1, {});
if (sendHeaderStatus != OK) {
ALOGE("Could not write connection header to socket: %s",
statusToString(sendHeaderStatus).c_str());
@@ -624,9 +625,10 @@
}
if (sessionId.size() > 0) {
+ iovec sessionIov{const_cast<void*>(static_cast<const void*>(sessionId.data())),
+ sessionId.size()};
auto sendSessionIdStatus =
- server->interruptableWriteFully(mShutdownTrigger.get(), sessionId.data(),
- sessionId.size(), {});
+ server->interruptableWriteFully(mShutdownTrigger.get(), &sessionIov, 1, {});
if (sendSessionIdStatus != OK) {
ALOGE("Could not write session ID ('%s') to socket: %s",
base::HexString(sessionId.data(), sessionId.size()).c_str(),
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 09b3d68..6286c9c 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -19,6 +19,7 @@
#include "RpcState.h"
#include <android-base/hex.h>
+#include <android-base/macros.h>
#include <android-base/scopeguard.h>
#include <binder/BpBinder.h>
#include <binder/IPCThreadState.h>
@@ -309,22 +310,18 @@
}
status_t RpcState::rpcSend(const sp<RpcSession::RpcConnection>& connection,
- const sp<RpcSession>& session, const char* what, const void* data,
- size_t size, const std::function<status_t()>& altPoll) {
- LOG_RPC_DETAIL("Sending %s on RpcTransport %p: %s", what, connection->rpcTransport.get(),
- android::base::HexString(data, size).c_str());
-
- if (size > std::numeric_limits<ssize_t>::max()) {
- ALOGE("Cannot send %s at size %zu (too big)", what, size);
- (void)session->shutdownAndWait(false);
- return BAD_VALUE;
+ const sp<RpcSession>& session, const char* what, iovec* iovs,
+ size_t niovs, const std::function<status_t()>& altPoll) {
+ for (size_t i = 0; i < niovs; i++) {
+ LOG_RPC_DETAIL("Sending %s on RpcTransport %p: %s", what, connection->rpcTransport.get(),
+ android::base::HexString(iovs[i].iov_base, iovs[i].iov_len).c_str());
}
if (status_t status =
connection->rpcTransport->interruptableWriteFully(session->mShutdownTrigger.get(),
- data, size, altPoll);
+ iovs, niovs, altPoll);
status != OK) {
- LOG_RPC_DETAIL("Failed to write %s (%zu bytes) on RpcTransport %p, error: %s", what, size,
+ LOG_RPC_DETAIL("Failed to write %s (%zu iovs) on RpcTransport %p, error: %s", what, niovs,
connection->rpcTransport.get(), statusToString(status).c_str());
(void)session->shutdownAndWait(false);
return status;
@@ -334,34 +331,30 @@
}
status_t RpcState::rpcRec(const sp<RpcSession::RpcConnection>& connection,
- const sp<RpcSession>& session, const char* what, void* data,
- size_t size) {
- if (size > std::numeric_limits<ssize_t>::max()) {
- ALOGE("Cannot rec %s at size %zu (too big)", what, size);
- (void)session->shutdownAndWait(false);
- return BAD_VALUE;
- }
-
+ const sp<RpcSession>& session, const char* what, iovec* iovs,
+ size_t niovs) {
if (status_t status =
connection->rpcTransport->interruptableReadFully(session->mShutdownTrigger.get(),
- data, size, {});
+ iovs, niovs, {});
status != OK) {
- LOG_RPC_DETAIL("Failed to read %s (%zu bytes) on RpcTransport %p, error: %s", what, size,
+ LOG_RPC_DETAIL("Failed to read %s (%zu iovs) on RpcTransport %p, error: %s", what, niovs,
connection->rpcTransport.get(), statusToString(status).c_str());
(void)session->shutdownAndWait(false);
return status;
}
- LOG_RPC_DETAIL("Received %s on RpcTransport %p: %s", what, connection->rpcTransport.get(),
- android::base::HexString(data, size).c_str());
+ for (size_t i = 0; i < niovs; i++) {
+ LOG_RPC_DETAIL("Received %s on RpcTransport %p: %s", what, connection->rpcTransport.get(),
+ android::base::HexString(iovs[i].iov_base, iovs[i].iov_len).c_str());
+ }
return OK;
}
status_t RpcState::readNewSessionResponse(const sp<RpcSession::RpcConnection>& connection,
const sp<RpcSession>& session, uint32_t* version) {
RpcNewSessionResponse response;
- if (status_t status =
- rpcRec(connection, session, "new session response", &response, sizeof(response));
+ iovec iov{&response, sizeof(response)};
+ if (status_t status = rpcRec(connection, session, "new session response", &iov, 1);
status != OK) {
return status;
}
@@ -374,14 +367,15 @@
RpcOutgoingConnectionInit init{
.msg = RPC_CONNECTION_INIT_OKAY,
};
- return rpcSend(connection, session, "connection init", &init, sizeof(init));
+ iovec iov{&init, sizeof(init)};
+ return rpcSend(connection, session, "connection init", &iov, 1);
}
status_t RpcState::readConnectionInit(const sp<RpcSession::RpcConnection>& connection,
const sp<RpcSession>& session) {
RpcOutgoingConnectionInit init;
- if (status_t status = rpcRec(connection, session, "connection init", &init, sizeof(init));
- status != OK)
+ iovec iov{&init, sizeof(init)};
+ if (status_t status = rpcRec(connection, session, "connection init", &iov, 1); status != OK)
return status;
static_assert(sizeof(init.msg) == sizeof(RPC_CONNECTION_INIT_OKAY));
@@ -514,17 +508,6 @@
.flags = flags,
.asyncNumber = asyncNumber,
};
- CommandData transactionData(sizeof(RpcWireHeader) + sizeof(RpcWireTransaction) +
- data.dataSize());
- if (!transactionData.valid()) {
- return NO_MEMORY;
- }
-
- memcpy(transactionData.data() + 0, &command, sizeof(RpcWireHeader));
- memcpy(transactionData.data() + sizeof(RpcWireHeader), &transaction,
- sizeof(RpcWireTransaction));
- memcpy(transactionData.data() + sizeof(RpcWireHeader) + sizeof(RpcWireTransaction), data.data(),
- data.dataSize());
constexpr size_t kWaitMaxUs = 1000000;
constexpr size_t kWaitLogUs = 10000;
@@ -550,8 +533,13 @@
return drainCommands(connection, session, CommandType::CONTROL_ONLY);
};
- if (status_t status = rpcSend(connection, session, "transaction", transactionData.data(),
- transactionData.size(), drainRefs);
+ iovec iovs[]{
+ {&command, sizeof(RpcWireHeader)},
+ {&transaction, sizeof(RpcWireTransaction)},
+ {const_cast<uint8_t*>(data.data()), data.dataSize()},
+ };
+ if (status_t status =
+ rpcSend(connection, session, "transaction", iovs, arraysize(iovs), drainRefs);
status != OK) {
// TODO(b/167966510): need to undo onBinderLeaving - we know the
// refcount isn't successfully transferred.
@@ -584,8 +572,8 @@
const sp<RpcSession>& session, Parcel* reply) {
RpcWireHeader command;
while (true) {
- if (status_t status = rpcRec(connection, session, "command header (for reply)", &command,
- sizeof(command));
+ iovec iov{&command, sizeof(command)};
+ if (status_t status = rpcRec(connection, session, "command header (for reply)", &iov, 1);
status != OK)
return status;
@@ -599,8 +587,8 @@
CommandData data(command.bodySize);
if (!data.valid()) return NO_MEMORY;
- if (status_t status = rpcRec(connection, session, "reply body", data.data(), command.bodySize);
- status != OK)
+ iovec iov{data.data(), command.bodySize};
+ if (status_t status = rpcRec(connection, session, "reply body", &iov, 1); status != OK)
return status;
if (command.bodySize < sizeof(RpcWireReply)) {
@@ -653,11 +641,8 @@
.command = RPC_COMMAND_DEC_STRONG,
.bodySize = sizeof(RpcDecStrong),
};
- if (status_t status = rpcSend(connection, session, "dec ref header", &cmd, sizeof(cmd));
- status != OK)
- return status;
-
- return rpcSend(connection, session, "dec ref body", &body, sizeof(body));
+ iovec iovs[]{{&cmd, sizeof(cmd)}, {&body, sizeof(body)}};
+ return rpcSend(connection, session, "dec ref", iovs, arraysize(iovs));
}
status_t RpcState::getAndExecuteCommand(const sp<RpcSession::RpcConnection>& connection,
@@ -665,8 +650,8 @@
LOG_RPC_DETAIL("getAndExecuteCommand on RpcTransport %p", connection->rpcTransport.get());
RpcWireHeader command;
- if (status_t status = rpcRec(connection, session, "command header (for server)", &command,
- sizeof(command));
+ iovec iov{&command, sizeof(command)};
+ if (status_t status = rpcRec(connection, session, "command header (for server)", &iov, 1);
status != OK)
return status;
@@ -726,9 +711,8 @@
if (!transactionData.valid()) {
return NO_MEMORY;
}
- if (status_t status = rpcRec(connection, session, "transaction body", transactionData.data(),
- transactionData.size());
- status != OK)
+ iovec iov{transactionData.data(), transactionData.size()};
+ if (status_t status = rpcRec(connection, session, "transaction body", &iov, 1); status != OK)
return status;
return processTransactInternal(connection, session, std::move(transactionData));
@@ -965,16 +949,12 @@
.status = replyStatus,
};
- CommandData replyData(sizeof(RpcWireHeader) + sizeof(RpcWireReply) + reply.dataSize());
- if (!replyData.valid()) {
- return NO_MEMORY;
- }
- memcpy(replyData.data() + 0, &cmdReply, sizeof(RpcWireHeader));
- memcpy(replyData.data() + sizeof(RpcWireHeader), &rpcReply, sizeof(RpcWireReply));
- memcpy(replyData.data() + sizeof(RpcWireHeader) + sizeof(RpcWireReply), reply.data(),
- reply.dataSize());
-
- return rpcSend(connection, session, "reply", replyData.data(), replyData.size());
+ iovec iovs[]{
+ {&cmdReply, sizeof(RpcWireHeader)},
+ {&rpcReply, sizeof(RpcWireReply)},
+ {const_cast<uint8_t*>(reply.data()), reply.dataSize()},
+ };
+ return rpcSend(connection, session, "reply", iovs, arraysize(iovs));
}
status_t RpcState::processDecStrong(const sp<RpcSession::RpcConnection>& connection,
@@ -985,9 +965,8 @@
if (!commandData.valid()) {
return NO_MEMORY;
}
- if (status_t status =
- rpcRec(connection, session, "dec ref body", commandData.data(), commandData.size());
- status != OK)
+ iovec iov{commandData.data(), commandData.size()};
+ if (status_t status = rpcRec(connection, session, "dec ref body", &iov, 1); status != OK)
return status;
if (command.bodySize != sizeof(RpcDecStrong)) {
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index dba0a43..5cad394 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -24,6 +24,8 @@
#include <optional>
#include <queue>
+#include <sys/uio.h>
+
namespace android {
struct RpcWireHeader;
@@ -177,12 +179,12 @@
};
[[nodiscard]] status_t rpcSend(const sp<RpcSession::RpcConnection>& connection,
- const sp<RpcSession>& session, const char* what,
- const void* data, size_t size,
+ const sp<RpcSession>& session, const char* what, iovec* iovs,
+ size_t niovs,
const std::function<status_t()>& altPoll = nullptr);
[[nodiscard]] status_t rpcRec(const sp<RpcSession::RpcConnection>& connection,
- const sp<RpcSession>& session, const char* what, void* data,
- size_t size);
+ const sp<RpcSession>& session, const char* what, iovec* iovs,
+ size_t niovs);
[[nodiscard]] status_t waitForReply(const sp<RpcSession::RpcConnection>& connection,
const sp<RpcSession>& session, Parcel* reply);
diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp
index 7669518..2182e18 100644
--- a/libs/binder/RpcTransportRaw.cpp
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -43,12 +43,10 @@
return ret;
}
- template <typename Buffer, typename SendOrReceive>
- status_t interruptableReadOrWrite(FdTrigger* fdTrigger, Buffer buffer, size_t size,
+ template <typename SendOrReceive>
+ status_t interruptableReadOrWrite(FdTrigger* fdTrigger, iovec* iovs, size_t niovs,
SendOrReceive sendOrReceiveFun, const char* funName,
int16_t event, const std::function<status_t()>& altPoll) {
- const Buffer end = buffer + size;
-
MAYBE_WAIT_IN_FLAKE_MODE;
// Since we didn't poll, we need to manually check to see if it was triggered. Otherwise, we
@@ -57,26 +55,61 @@
return DEAD_OBJECT;
}
+ // If iovs has one or more empty vectors at the end and
+ // we somehow advance past all the preceding vectors and
+ // pass some or all of the empty ones to sendmsg/recvmsg,
+ // the call will return processSize == 0. In that case
+ // we should be returning OK but instead return DEAD_OBJECT.
+ // To avoid this problem, we make sure here that the last
+ // vector at iovs[niovs - 1] has a non-zero length.
+ while (niovs > 0 && iovs[niovs - 1].iov_len == 0) {
+ niovs--;
+ }
+ if (niovs == 0) {
+ // The vectors are all empty, so we have nothing to send.
+ return OK;
+ }
+
bool havePolled = false;
while (true) {
- ssize_t processSize = TEMP_FAILURE_RETRY(
- sendOrReceiveFun(mSocket.get(), buffer, end - buffer, MSG_NOSIGNAL));
+ msghdr msg{
+ .msg_iov = iovs,
+ .msg_iovlen = niovs,
+ };
+ ssize_t processSize =
+ TEMP_FAILURE_RETRY(sendOrReceiveFun(mSocket.get(), &msg, MSG_NOSIGNAL));
if (processSize < 0) {
int savedErrno = errno;
// Still return the error on later passes, since it would expose
// a problem with polling
- if (havePolled ||
- (!havePolled && savedErrno != EAGAIN && savedErrno != EWOULDBLOCK)) {
+ if (havePolled || (savedErrno != EAGAIN && savedErrno != EWOULDBLOCK)) {
LOG_RPC_DETAIL("RpcTransport %s(): %s", funName, strerror(savedErrno));
return -savedErrno;
}
} else if (processSize == 0) {
return DEAD_OBJECT;
} else {
- buffer += processSize;
- if (buffer == end) {
+ while (processSize > 0 && niovs > 0) {
+ auto& iov = iovs[0];
+ if (static_cast<size_t>(processSize) < iov.iov_len) {
+ // Advance the base of the current iovec
+ iov.iov_base = reinterpret_cast<char*>(iov.iov_base) + processSize;
+ iov.iov_len -= processSize;
+ break;
+ }
+
+ // The current iovec was fully written
+ processSize -= iov.iov_len;
+ iovs++;
+ niovs--;
+ }
+ if (niovs == 0) {
+ LOG_ALWAYS_FATAL_IF(processSize > 0,
+ "Reached the end of iovecs "
+ "with %zd bytes remaining",
+ processSize);
return OK;
}
}
@@ -95,16 +128,16 @@
}
}
- status_t interruptableWriteFully(FdTrigger* fdTrigger, const void* data, size_t size,
+ status_t interruptableWriteFully(FdTrigger* fdTrigger, iovec* iovs, size_t niovs,
const std::function<status_t()>& altPoll) override {
- return interruptableReadOrWrite(fdTrigger, reinterpret_cast<const uint8_t*>(data), size,
- send, "send", POLLOUT, altPoll);
+ return interruptableReadOrWrite(fdTrigger, iovs, niovs, sendmsg, "sendmsg", POLLOUT,
+ altPoll);
}
- status_t interruptableReadFully(FdTrigger* fdTrigger, void* data, size_t size,
+ status_t interruptableReadFully(FdTrigger* fdTrigger, iovec* iovs, size_t niovs,
const std::function<status_t()>& altPoll) override {
- return interruptableReadOrWrite(fdTrigger, reinterpret_cast<uint8_t*>(data), size, recv,
- "recv", POLLIN, altPoll);
+ return interruptableReadOrWrite(fdTrigger, iovs, niovs, recvmsg, "recvmsg", POLLIN,
+ altPoll);
}
private:
diff --git a/libs/binder/RpcTransportTls.cpp b/libs/binder/RpcTransportTls.cpp
index 7f810b1..c05ea15 100644
--- a/libs/binder/RpcTransportTls.cpp
+++ b/libs/binder/RpcTransportTls.cpp
@@ -275,9 +275,9 @@
RpcTransportTls(android::base::unique_fd socket, Ssl ssl)
: mSocket(std::move(socket)), mSsl(std::move(ssl)) {}
Result<size_t> peek(void* buf, size_t size) override;
- status_t interruptableWriteFully(FdTrigger* fdTrigger, const void* data, size_t size,
+ status_t interruptableWriteFully(FdTrigger* fdTrigger, iovec* iovs, size_t niovs,
const std::function<status_t()>& altPoll) override;
- status_t interruptableReadFully(FdTrigger* fdTrigger, void* data, size_t size,
+ status_t interruptableReadFully(FdTrigger* fdTrigger, iovec* iovs, size_t niovs,
const std::function<status_t()>& altPoll) override;
private:
@@ -303,68 +303,83 @@
return ret;
}
-status_t RpcTransportTls::interruptableWriteFully(FdTrigger* fdTrigger, const void* data,
- size_t size,
+status_t RpcTransportTls::interruptableWriteFully(FdTrigger* fdTrigger, iovec* iovs, size_t niovs,
const std::function<status_t()>& altPoll) {
- auto buffer = reinterpret_cast<const uint8_t*>(data);
- const uint8_t* end = buffer + size;
-
MAYBE_WAIT_IN_FLAKE_MODE;
// Before doing any I/O, check trigger once. This ensures the trigger is checked at least
// once. The trigger is also checked via triggerablePoll() after every SSL_write().
if (fdTrigger->isTriggered()) return DEAD_OBJECT;
- while (buffer < end) {
- size_t todo = std::min<size_t>(end - buffer, std::numeric_limits<int>::max());
- auto [writeSize, errorQueue] = mSsl.call(SSL_write, buffer, todo);
- if (writeSize > 0) {
- buffer += writeSize;
- errorQueue.clear();
+ size_t size = 0;
+ for (size_t i = 0; i < niovs; i++) {
+ const iovec& iov = iovs[i];
+ if (iov.iov_len == 0) {
continue;
}
- // SSL_write() should never return 0 unless BIO_write were to return 0.
- int sslError = mSsl.getError(writeSize);
- // TODO(b/195788248): BIO should contain the FdTrigger, and send(2) / recv(2) should be
- // triggerablePoll()-ed. Then additionalEvent is no longer necessary.
- status_t pollStatus = errorQueue.pollForSslError(mSocket.get(), sslError, fdTrigger,
- "SSL_write", POLLIN, altPoll);
- if (pollStatus != OK) return pollStatus;
- // Do not advance buffer. Try SSL_write() again.
+ size += iov.iov_len;
+
+ auto buffer = reinterpret_cast<const uint8_t*>(iov.iov_base);
+ const uint8_t* end = buffer + iov.iov_len;
+ while (buffer < end) {
+ size_t todo = std::min<size_t>(end - buffer, std::numeric_limits<int>::max());
+ auto [writeSize, errorQueue] = mSsl.call(SSL_write, buffer, todo);
+ if (writeSize > 0) {
+ buffer += writeSize;
+ errorQueue.clear();
+ continue;
+ }
+ // SSL_write() should never return 0 unless BIO_write were to return 0.
+ int sslError = mSsl.getError(writeSize);
+ // TODO(b/195788248): BIO should contain the FdTrigger, and send(2) / recv(2) should be
+ // triggerablePoll()-ed. Then additionalEvent is no longer necessary.
+ status_t pollStatus = errorQueue.pollForSslError(mSocket.get(), sslError, fdTrigger,
+ "SSL_write", POLLIN, altPoll);
+ if (pollStatus != OK) return pollStatus;
+ // Do not advance buffer. Try SSL_write() again.
+ }
}
LOG_TLS_DETAIL("TLS: Sent %zu bytes!", size);
return OK;
}
-status_t RpcTransportTls::interruptableReadFully(FdTrigger* fdTrigger, void* data, size_t size,
+status_t RpcTransportTls::interruptableReadFully(FdTrigger* fdTrigger, iovec* iovs, size_t niovs,
const std::function<status_t()>& altPoll) {
- auto buffer = reinterpret_cast<uint8_t*>(data);
- uint8_t* end = buffer + size;
-
MAYBE_WAIT_IN_FLAKE_MODE;
// Before doing any I/O, check trigger once. This ensures the trigger is checked at least
// once. The trigger is also checked via triggerablePoll() after every SSL_write().
if (fdTrigger->isTriggered()) return DEAD_OBJECT;
- while (buffer < end) {
- size_t todo = std::min<size_t>(end - buffer, std::numeric_limits<int>::max());
- auto [readSize, errorQueue] = mSsl.call(SSL_read, buffer, todo);
- if (readSize > 0) {
- buffer += readSize;
- errorQueue.clear();
+ size_t size = 0;
+ for (size_t i = 0; i < niovs; i++) {
+ const iovec& iov = iovs[i];
+ if (iov.iov_len == 0) {
continue;
}
- if (readSize == 0) {
- // SSL_read() only returns 0 on EOF.
- errorQueue.clear();
- return DEAD_OBJECT;
+ size += iov.iov_len;
+
+ auto buffer = reinterpret_cast<uint8_t*>(iov.iov_base);
+ const uint8_t* end = buffer + iov.iov_len;
+ while (buffer < end) {
+ size_t todo = std::min<size_t>(end - buffer, std::numeric_limits<int>::max());
+ auto [readSize, errorQueue] = mSsl.call(SSL_read, buffer, todo);
+ if (readSize > 0) {
+ buffer += readSize;
+ errorQueue.clear();
+ continue;
+ }
+ if (readSize == 0) {
+ // SSL_read() only returns 0 on EOF.
+ errorQueue.clear();
+ return DEAD_OBJECT;
+ }
+ int sslError = mSsl.getError(readSize);
+ status_t pollStatus = errorQueue.pollForSslError(mSocket.get(), sslError, fdTrigger,
+ "SSL_read", 0, altPoll);
+ if (pollStatus != OK) return pollStatus;
+ // Do not advance buffer. Try SSL_read() again.
}
- int sslError = mSsl.getError(readSize);
- status_t pollStatus = errorQueue.pollForSslError(mSocket.get(), sslError, fdTrigger,
- "SSL_read", 0, altPoll);
- if (pollStatus != OK) return pollStatus;
- // Do not advance buffer. Try SSL_read() again.
}
LOG_TLS_DETAIL("TLS: Received %zu bytes!", size);
return OK;
diff --git a/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl b/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl
index bffab5e..949835b 100644
--- a/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl
+++ b/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl
@@ -27,7 +27,5 @@
@utf8InCpp String diskImagePath;
long versionCode;
@utf8InCpp String versionName;
- boolean hasBootClassPathJars;
- boolean hasDex2OatBootClassPathJars;
- boolean hasSystemServerClassPathJars;
+ boolean hasClassPathJars;
}
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index 82bebc9..bf02099 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -54,8 +54,6 @@
static status_t getProcessFreezeInfo(pid_t pid, uint32_t *sync_received,
uint32_t *async_received);
- sp<ProcessState> process();
-
status_t clearLastError();
/**
diff --git a/libs/binder/include/binder/RpcTransport.h b/libs/binder/include/binder/RpcTransport.h
index db8b5e9..348bfeb 100644
--- a/libs/binder/include/binder/RpcTransport.h
+++ b/libs/binder/include/binder/RpcTransport.h
@@ -28,6 +28,8 @@
#include <binder/RpcCertificateFormat.h>
+#include <sys/uio.h>
+
namespace android {
class FdTrigger;
@@ -44,6 +46,9 @@
/**
* Read (or write), but allow to be interrupted by a trigger.
*
+ * iovs - array of iovecs to perform the operation on. The elements
+ * of the array may be modified by this method.
+ *
* altPoll - function to be called instead of polling, when needing to wait
* to read/write data. If this returns an error, that error is returned from
* this function.
@@ -53,10 +58,10 @@
* error - interrupted (failure or trigger)
*/
[[nodiscard]] virtual status_t interruptableWriteFully(
- FdTrigger *fdTrigger, const void *buf, size_t size,
+ FdTrigger *fdTrigger, iovec *iovs, size_t niovs,
const std::function<status_t()> &altPoll) = 0;
[[nodiscard]] virtual status_t interruptableReadFully(
- FdTrigger *fdTrigger, void *buf, size_t size,
+ FdTrigger *fdTrigger, iovec *iovs, size_t niovs,
const std::function<status_t()> &altPoll) = 0;
protected:
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 4289574..77493b3 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -32,17 +32,10 @@
],
}
+// TODO(b/211908498): remove this
cc_defaults {
name: "libbinder_ndk_host_user",
target: {
- host: {
- cflags: [
- "-D__INTRODUCED_IN(n)=",
- "-D__assert(a,b,c)=do { syslog(LOG_ERR, a \": \" c); abort(); } while(false)",
- // We want all the APIs to be available on the host.
- "-D__ANDROID_API__=10000",
- ],
- },
darwin: {
enabled: false,
},
@@ -52,7 +45,6 @@
cc_library {
name: "libbinder_ndk",
- defaults: ["libbinder_ndk_host_user"],
host_supported: true,
recovery_available: true,
diff --git a/libs/binder/ndk/include_ndk/android/binder_status.h b/libs/binder/ndk/include_ndk/android/binder_status.h
index 6f1fdfc..76c7aac 100644
--- a/libs/binder/ndk/include_ndk/android/binder_status.h
+++ b/libs/binder/ndk/include_ndk/android/binder_status.h
@@ -32,11 +32,26 @@
__BEGIN_DECLS
-#ifndef __ANDROID_API__
-#error Android builds must be compiled against a specific API. If this is an \
- android platform host build, you must use libbinder_ndk_host_user.
+#ifndef __BIONIC__
+
+#ifndef __INTRODUCED_IN
+#define __INTRODUCED_IN(n)
#endif
+#ifndef __assert
+#define __assert(a, b, c) \
+ do { \
+ syslog(LOG_ERR, a ": " c); \
+ abort(); \
+ } while (false)
+#endif
+
+#ifndef __ANDROID_API__
+#define __ANDROID_API__ 10000
+#endif
+
+#endif // __BIONIC__
+
/**
* Low-level status types for use in binder. This is the least preferable way to
* return an error for binder services (where binder_exception_t should be used,
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index e2fc18d..e4df98a 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -127,14 +127,6 @@
// Currently necessary for host builds
// TODO(b/31559095): bionic on host should define this
target: {
- host: {
- cflags: [
- "-D__INTRODUCED_IN(n)=",
- "-D__assert(a,b,c)=",
- // We want all the APIs to be available on the host.
- "-D__ANDROID_API__=10000",
- ],
- },
darwin: {
enabled: false,
},
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 5a96b78..ca68b99 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -1674,8 +1674,8 @@
static AssertionResult defaultPostConnect(RpcTransport* serverTransport,
FdTrigger* fdTrigger) {
std::string message(kMessage);
- auto status = serverTransport->interruptableWriteFully(fdTrigger, message.data(),
- message.size(), {});
+ iovec messageIov{message.data(), message.size()};
+ auto status = serverTransport->interruptableWriteFully(fdTrigger, &messageIov, 1, {});
if (status != OK) return AssertionFailure() << statusToString(status);
return AssertionSuccess();
}
@@ -1706,9 +1706,9 @@
AssertionResult readMessage(const std::string& expectedMessage = kMessage) {
LOG_ALWAYS_FATAL_IF(mClientTransport == nullptr, "setUpTransport not called or failed");
std::string readMessage(expectedMessage.size(), '\0');
- status_t readStatus =
- mClientTransport->interruptableReadFully(mFdTrigger.get(), readMessage.data(),
- readMessage.size(), {});
+ iovec readMessageIov{readMessage.data(), readMessage.size()};
+ status_t readStatus = mClientTransport->interruptableReadFully(mFdTrigger.get(),
+ &readMessageIov, 1, {});
if (readStatus != OK) {
return AssertionFailure() << statusToString(readStatus);
}
@@ -1902,8 +1902,8 @@
bool shouldContinueWriting = false;
auto serverPostConnect = [&](RpcTransport* serverTransport, FdTrigger* fdTrigger) {
std::string message(RpcTransportTestUtils::kMessage);
- auto status = serverTransport->interruptableWriteFully(fdTrigger, message.data(),
- message.size(), {});
+ iovec messageIov{message.data(), message.size()};
+ auto status = serverTransport->interruptableWriteFully(fdTrigger, &messageIov, 1, {});
if (status != OK) return AssertionFailure() << statusToString(status);
{
@@ -1913,7 +1913,8 @@
}
}
- status = serverTransport->interruptableWriteFully(fdTrigger, msg2.data(), msg2.size(), {});
+ iovec msg2Iov{msg2.data(), msg2.size()};
+ status = serverTransport->interruptableWriteFully(fdTrigger, &msg2Iov, 1, {});
if (status != DEAD_OBJECT)
return AssertionFailure() << "When FdTrigger is shut down, interruptableWriteFully "
"should return DEAD_OBJECT, but it is "
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index acf3f8f..1446802 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -9,7 +9,6 @@
cc_fuzz {
name: "binder_parcel_fuzzer",
- defaults: ["libbinder_ndk_host_user"],
host_supported: true,
fuzz_config: {
@@ -50,6 +49,9 @@
"libbinder",
],
},
+ darwin: {
+ enabled: false,
+ },
},
// This flag enables verbose output in the fuzz target, and is very useful
// for debugging a failure. If you are trying to diagnose how a crash was
@@ -63,7 +65,7 @@
target: {
darwin: {
enabled: false,
- }
+ },
},
srcs: [
"random_fd.cpp",
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 85a4b67..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,15 +152,13 @@
mBufferItemConsumer->setName(String8(consumerName.c_str()));
mBufferItemConsumer->setFrameAvailableListener(this);
mBufferItemConsumer->setBufferFreedListener(this);
- mBufferItemConsumer->setBlastBufferQueue(this);
ComposerService::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers);
mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers);
mCurrentMaxAcquiredBufferCount = mMaxAcquiredBuffers;
mNumAcquired = 0;
mNumFrameAvailable = 0;
- BQA_LOGV("BLASTBufferQueue created width=%d height=%d format=%d mTransformHint=%d", mSize.width,
- mSize.height, mFormat, mTransformHint);
+ BQA_LOGV("BLASTBufferQueue created");
}
BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface,
@@ -175,21 +168,20 @@
}
BLASTBufferQueue::~BLASTBufferQueue() {
- mBufferItemConsumer->setBlastBufferQueue(nullptr);
if (mPendingTransactions.empty()) {
return;
}
BQA_LOGE("Applying pending transactions on dtor %d",
static_cast<uint32_t>(mPendingTransactions.size()));
SurfaceComposerClient::Transaction t;
- for (auto& [targetFrameNumber, transaction] : mPendingTransactions) {
- t.merge(std::move(transaction));
- }
- t.apply();
+ mergePendingTransactions(&t, std::numeric_limits<uint64_t>::max() /* frameNumber */);
+ t.setApplyToken(mApplyToken).apply();
}
void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height,
int32_t format, SurfaceComposerClient::Transaction* outTransaction) {
+ LOG_ALWAYS_FATAL_IF(surface == nullptr, "BLASTBufferQueue: mSurfaceControl must not be NULL");
+
std::unique_lock _lock{mMutex};
if (mFormat != format) {
mFormat = format;
@@ -197,21 +189,22 @@
}
SurfaceComposerClient::Transaction t;
- const bool setBackpressureFlag = !SurfaceControl::isSameSurface(mSurfaceControl, surface);
+ 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 (mSurfaceControl != nullptr) {
- if (setBackpressureFlag) {
- t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure,
- layer_state_t::eEnableBackpressure);
- applyTransaction = true;
- }
- mTransformHint = mSurfaceControl->getTransformHint();
- mBufferItemConsumer->setTransformHint(mTransformHint);
+ if (surfaceControlChanged) {
+ t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure,
+ layer_state_t::eEnableBackpressure);
+ applyTransaction = true;
}
+ mTransformHint = mSurfaceControl->getTransformHint();
+ mBufferItemConsumer->setTransformHint(mTransformHint);
BQA_LOGV("update width=%d height=%d format=%d mTransformHint=%d", width, height, format,
mTransformHint);
@@ -225,11 +218,9 @@
mSize = mRequestedSize;
SurfaceComposerClient::Transaction* destFrameTransaction =
(outTransaction) ? outTransaction : &t;
- if (mSurfaceControl != nullptr) {
- destFrameTransaction->setDestinationFrame(mSurfaceControl,
- Rect(0, 0, newSize.getWidth(),
- newSize.getHeight()));
- }
+ destFrameTransaction->setDestinationFrame(mSurfaceControl,
+ Rect(0, 0, newSize.getWidth(),
+ newSize.getHeight()));
applyTransaction = true;
}
}
@@ -511,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);
@@ -626,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;
@@ -640,7 +630,7 @@
// add to shadow queue
mNumFrameAvailable++;
- if (mWaitForTransactionCallback && mNumFrameAvailable == 2) {
+ if (mWaitForTransactionCallback && mNumFrameAvailable >= 2) {
acquireAndReleaseBuffer();
}
ATRACE_INT(mQueuedBufferTrace.c_str(),
@@ -717,7 +707,7 @@
// of the buffer, the next acquire may return with NO_BUFFER_AVAILABLE.
bool BLASTBufferQueue::maxBuffersAcquired(bool includeExtraAcquire) const {
int maxAcquiredBuffers = mMaxAcquiredBuffers + (includeExtraAcquire ? 2 : 1);
- return mNumAcquired == maxAcquiredBuffers;
+ return mNumAcquired >= maxAcquiredBuffers;
}
class BBQSurface : public Surface {
@@ -991,4 +981,53 @@
return mLastAcquiredFrameNumber;
}
+void BLASTBufferQueue::abandon() {
+ std::unique_lock _lock{mMutex};
+ // flush out the shadow queue
+ while (mNumFrameAvailable > 0) {
+ acquireAndReleaseBuffer();
+ }
+
+ // Clear submitted buffer states
+ mNumAcquired = 0;
+ mSubmitted.clear();
+ mPendingRelease.clear();
+
+ if (!mPendingTransactions.empty()) {
+ BQA_LOGD("Applying pending transactions on abandon %d",
+ static_cast<uint32_t>(mPendingTransactions.size()));
+ SurfaceComposerClient::Transaction t;
+ mergePendingTransactions(&t, std::numeric_limits<uint64_t>::max() /* frameNumber */);
+ t.setApplyToken(mApplyToken).apply();
+ }
+
+ // Clear sync states
+ if (mWaitForTransactionCallback) {
+ BQA_LOGD("mWaitForTransactionCallback cleared");
+ mWaitForTransactionCallback = false;
+ }
+
+ if (mSyncTransaction != nullptr) {
+ BQA_LOGD("mSyncTransaction cleared mAcquireSingleBuffer=%s",
+ mAcquireSingleBuffer ? "true" : "false");
+ mSyncTransaction = nullptr;
+ mAcquireSingleBuffer = false;
+ }
+
+ // abandon buffer queue
+ if (mBufferItemConsumer != nullptr) {
+ mBufferItemConsumer->abandon();
+ mBufferItemConsumer->setFrameAvailableListener(nullptr);
+ mBufferItemConsumer->setBufferFreedListener(nullptr);
+ }
+ mBufferItemConsumer = nullptr;
+ mConsumer = nullptr;
+ mProducer = nullptr;
+}
+
+bool BLASTBufferQueue::isSameSurfaceControl(const sp<SurfaceControl>& surfaceControl) const {
+ std::unique_lock _lock{mMutex};
+ return SurfaceControl::isSameSurface(mSurfaceControl, surfaceControl);
+}
+
} // namespace android
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 7f73013..a931709 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -1134,6 +1134,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;
@@ -2016,6 +2044,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..acd9ac5 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -677,6 +677,10 @@
return NO_ERROR;
}
+ReleaseCallbackId BufferData::generateReleaseCallbackId() const {
+ return {buffer->getId(), frameNumber};
+}
+
status_t BufferData::write(Parcel& output) const {
SAFE_PARCEL(output.writeInt32, flags.get());
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index cf04ec8..b10c384 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -736,10 +736,10 @@
// 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);
}
}
@@ -1335,7 +1335,7 @@
BufferData bufferData = s->bufferData;
TransactionCompletedListener::getInstance()->removeReleaseBufferCallback(
- bufferData.releaseCallbackId);
+ bufferData.generateReleaseCallbackId());
BufferData emptyBufferData;
s->what &= ~layer_state_t::eBufferChanged;
s->bufferData = emptyBufferData;
@@ -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;
@@ -1371,7 +1371,7 @@
if (mIsAutoTimestamp) {
mDesiredPresentTime = systemTime();
}
- setReleaseBufferCallback(&bufferData, id, callback);
+ setReleaseBufferCallback(&bufferData, callback);
s->what |= layer_state_t::eBufferChanged;
s->bufferData = bufferData;
registerSurfaceControlForCallback(sc);
@@ -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(
@@ -2218,6 +2216,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 8a2f392..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
@@ -82,6 +81,7 @@
return mProducer;
}
sp<Surface> getSurface(bool includeSurfaceControlHandle);
+ bool isSameSurfaceControl(const sp<SurfaceControl>& surfaceControl) const;
void onBufferFreed(const wp<GraphicBuffer>&/* graphicBuffer*/) override { /* TODO */ }
void onFrameReplaced(const BufferItem& item) override;
@@ -109,6 +109,7 @@
uint32_t getLastTransformHint() const;
uint64_t getLastAcquiredFrameNum();
+ void abandon();
virtual ~BLASTBufferQueue();
@@ -145,15 +146,15 @@
std::string mQueuedBufferTrace;
sp<SurfaceControl> mSurfaceControl;
- std::mutex mMutex;
+ mutable std::mutex mMutex;
std::condition_variable mCallbackCV;
// BufferQueue internally allows 1 more than
// the max to be acquired
int32_t mMaxAcquiredBuffers = 1;
- int32_t mNumFrameAvailable GUARDED_BY(mMutex);
- int32_t mNumAcquired GUARDED_BY(mMutex);
+ int32_t mNumFrameAvailable GUARDED_BY(mMutex) = 0;
+ int32_t mNumAcquired GUARDED_BY(mMutex) = 0;
// Keep a reference to the submitted buffers so we can release when surfaceflinger drops the
// buffer or the buffer has been presented and a new buffer is ready to be presented.
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 2546e4c..69dce9d 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -508,6 +508,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 +644,7 @@
ADD_WINDOW_INFOS_LISTENER,
REMOVE_WINDOW_INFOS_LISTENER,
GET_PRIMARY_PHYSICAL_DISPLAY_ID,
+ GET_DISPLAY_DECORATION_SUPPORT,
// 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..e48f52d 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -77,12 +77,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,6 +86,9 @@
client_cache_t cachedBuffer;
+ // 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 write(Parcel& output) const;
status_t read(const Parcel& input);
};
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 17b4846..b739b3c 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -272,6 +272,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 +426,7 @@
void cacheBuffers();
void registerSurfaceControlForCallback(const sp<SurfaceControl>& sc);
- void setReleaseBufferCallback(BufferData*, const ReleaseCallbackId&, ReleaseBufferCallback);
+ void setReleaseBufferCallback(BufferData*, ReleaseBufferCallback);
public:
Transaction();
@@ -490,7 +500,6 @@
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);
Transaction& setDataspace(const sp<SurfaceControl>& sc, ui::Dataspace dataspace);
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 48b8621..42a32f3 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -1069,6 +1069,94 @@
checkScreenCapture(255, 0, 0, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
}
+// This test will currently fail because the old surfacecontrol will steal the last presented buffer
+// until the old surface control is destroyed. This is not necessarily a bug but to document a
+// limitation with the update API and to test any changes to make the api more robust. The current
+// approach for the client is to recreate the blastbufferqueue when the surfacecontrol updates.
+TEST_F(BLASTBufferQueueTest, DISABLED_DisconnectProducerTest) {
+ BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+ std::vector<sp<SurfaceControl>> surfaceControls;
+ sp<IGraphicBufferProducer> igbProducer;
+ for (int i = 0; i < 10; i++) {
+ sp<SurfaceControl> sc =
+ mClient->createSurface(String8("TestSurface"), mDisplayWidth, mDisplayHeight,
+ PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceBufferState,
+ /*parent*/ nullptr);
+ Transaction()
+ .setLayerStack(mSurfaceControl, ui::DEFAULT_LAYER_STACK)
+ .setLayer(mSurfaceControl, std::numeric_limits<int32_t>::max())
+ .show(mSurfaceControl)
+ .setDataspace(mSurfaceControl, ui::Dataspace::V0_SRGB)
+ .apply(true);
+ surfaceControls.push_back(sc);
+ adapter.update(sc, mDisplayWidth, mDisplayHeight);
+
+ setUpProducer(adapter, igbProducer);
+ Transaction next;
+ queueBuffer(igbProducer, 0, 255, 0, 0);
+ queueBuffer(igbProducer, 0, 0, 255, 0);
+ adapter.setSyncTransaction(&next, false);
+ queueBuffer(igbProducer, 255, 0, 0, 0);
+
+ CallbackHelper transactionCallback;
+ next.addTransactionCompletedCallback(transactionCallback.function,
+ transactionCallback.getContext())
+ .apply();
+
+ CallbackData callbackData;
+ transactionCallback.getCallbackData(&callbackData);
+ // capture screen and verify that it is red
+ ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_NO_FATAL_FAILURE(
+ checkScreenCapture(255, 0, 0,
+ {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
+ igbProducer->disconnect(NATIVE_WINDOW_API_CPU);
+ }
+}
+
+// See DISABLED_DisconnectProducerTest
+TEST_F(BLASTBufferQueueTest, DISABLED_UpdateSurfaceControlTest) {
+ BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+ std::vector<sp<SurfaceControl>> surfaceControls;
+ sp<IGraphicBufferProducer> igbProducer;
+ for (int i = 0; i < 10; i++) {
+ sp<SurfaceControl> sc =
+ mClient->createSurface(String8("TestSurface"), mDisplayWidth, mDisplayHeight,
+ PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceBufferState,
+ /*parent*/ nullptr);
+ Transaction()
+ .setLayerStack(mSurfaceControl, ui::DEFAULT_LAYER_STACK)
+ .setLayer(mSurfaceControl, std::numeric_limits<int32_t>::max())
+ .show(mSurfaceControl)
+ .setDataspace(mSurfaceControl, ui::Dataspace::V0_SRGB)
+ .apply(true);
+ surfaceControls.push_back(sc);
+ adapter.update(sc, mDisplayWidth, mDisplayHeight);
+ setUpProducer(adapter, igbProducer);
+
+ Transaction next;
+ queueBuffer(igbProducer, 0, 255, 0, 0);
+ queueBuffer(igbProducer, 0, 0, 255, 0);
+ adapter.setSyncTransaction(&next, false);
+ queueBuffer(igbProducer, 255, 0, 0, 0);
+
+ CallbackHelper transactionCallback;
+ next.addTransactionCompletedCallback(transactionCallback.function,
+ transactionCallback.getContext())
+ .apply();
+
+ CallbackData callbackData;
+ transactionCallback.getCallbackData(&callbackData);
+ // capture screen and verify that it is red
+ ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_NO_FATAL_FAILURE(
+ checkScreenCapture(255, 0, 0,
+ {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
+ }
+}
+
class TestProducerListener : public BnProducerListener {
public:
sp<IGraphicBufferProducer> mIgbp;
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index f960e07..6f1263b 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -46,6 +46,8 @@
#include <ui/Rect.h>
#include <ui/Region.h>
+#include <private/android_filesystem_config.h>
+
using android::os::IInputFlinger;
using android::hardware::graphics::common::V1_1::BufferUsage;
@@ -179,6 +181,25 @@
EXPECT_EQ(flags, mev->getFlags() & flags);
}
+ void expectTapInDisplayCoordinates(int displayX, int displayY) {
+ InputEvent *ev = consumeEvent();
+ ASSERT_NE(ev, nullptr);
+ ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, ev->getType());
+ MotionEvent *mev = static_cast<MotionEvent *>(ev);
+ EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, mev->getAction());
+ const PointerCoords &coords = *mev->getRawPointerCoords(0 /*pointerIndex*/);
+ EXPECT_EQ(displayX, coords.getX());
+ EXPECT_EQ(displayY, coords.getY());
+ EXPECT_EQ(0, mev->getFlags() & VERIFIED_MOTION_EVENT_FLAGS);
+
+ ev = consumeEvent();
+ ASSERT_NE(ev, nullptr);
+ ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, ev->getType());
+ mev = static_cast<MotionEvent *>(ev);
+ EXPECT_EQ(AMOTION_EVENT_ACTION_UP, mev->getAction());
+ EXPECT_EQ(0, mev->getFlags() & VERIFIED_MOTION_EVENT_FLAGS);
+ }
+
void expectKey(uint32_t keycode) {
InputEvent *ev = consumeEvent();
ASSERT_NE(ev, nullptr);
@@ -969,31 +990,96 @@
class MultiDisplayTests : public InputSurfacesTest {
public:
MultiDisplayTests() : InputSurfacesTest() { ProcessState::self()->startThreadPool(); }
- void TearDown() {
- if (mVirtualDisplay) {
- SurfaceComposerClient::destroyDisplay(mVirtualDisplay);
+ void TearDown() override {
+ for (auto &token : mVirtualDisplays) {
+ SurfaceComposerClient::destroyDisplay(token);
}
InputSurfacesTest::TearDown();
}
- void createDisplay(int32_t width, int32_t height, bool isSecure, ui::LayerStack layerStack) {
+ void createDisplay(int32_t width, int32_t height, bool isSecure, ui::LayerStack layerStack,
+ bool receivesInput = true, int32_t offsetX = 0, int32_t offsetY = 0) {
sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&mProducer, &consumer);
+ sp<IGraphicBufferProducer> producer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
consumer->setConsumerName(String8("Virtual disp consumer"));
consumer->setDefaultBufferSize(width, height);
+ mProducers.push_back(producer);
- mVirtualDisplay = SurfaceComposerClient::createDisplay(String8("VirtualDisplay"), isSecure);
+ std::string name = "VirtualDisplay";
+ name += std::to_string(mVirtualDisplays.size());
+ sp<IBinder> token = SurfaceComposerClient::createDisplay(String8(name.c_str()), isSecure);
SurfaceComposerClient::Transaction t;
- t.setDisplaySurface(mVirtualDisplay, mProducer);
- t.setDisplayFlags(mVirtualDisplay, 0x01 /* DisplayDevice::eReceivesInput */);
- t.setDisplayLayerStack(mVirtualDisplay, layerStack);
+ t.setDisplaySurface(token, producer);
+ t.setDisplayFlags(token, receivesInput ? 0x01 /* DisplayDevice::eReceivesInput */ : 0);
+ t.setDisplayLayerStack(token, layerStack);
+ t.setDisplayProjection(token, ui::ROTATION_0, {0, 0, width, height},
+ {offsetX, offsetY, offsetX + width, offsetY + height});
t.apply(true);
+
+ mVirtualDisplays.push_back(token);
}
- sp<IBinder> mVirtualDisplay;
- sp<IGraphicBufferProducer> mProducer;
+ std::vector<sp<IBinder>> mVirtualDisplays;
+ std::vector<sp<IGraphicBufferProducer>> mProducers;
};
+TEST_F(MultiDisplayTests, drop_input_if_layer_on_invalid_display) {
+ ui::LayerStack layerStack = ui::LayerStack::fromValue(42);
+ // Do not create a display associated with the LayerStack.
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ surface->doTransaction([&](auto &t, auto &sc) { t.setLayerStack(sc, layerStack); });
+ surface->showAt(100, 100);
+
+ injectTapOnDisplay(101, 101, layerStack.id);
+ surface->requestFocus(layerStack.id);
+ injectKeyOnDisplay(AKEYCODE_V, layerStack.id);
+
+ EXPECT_EQ(surface->consumeEvent(100), nullptr);
+}
+
+TEST_F(MultiDisplayTests, virtual_display_receives_input) {
+ ui::LayerStack layerStack = ui::LayerStack::fromValue(42);
+ createDisplay(1000, 1000, false /*isSecure*/, layerStack);
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ surface->doTransaction([&](auto &t, auto &sc) { t.setLayerStack(sc, layerStack); });
+ surface->showAt(100, 100);
+
+ injectTapOnDisplay(101, 101, layerStack.id);
+ surface->expectTap(1, 1);
+
+ surface->requestFocus(layerStack.id);
+ surface->assertFocusChange(true);
+ injectKeyOnDisplay(AKEYCODE_V, layerStack.id);
+ surface->expectKey(AKEYCODE_V);
+}
+
+/**
+ * When multiple DisplayDevices are mapped to the same layerStack, use the configuration for the
+ * display that can receive input.
+ */
+TEST_F(MultiDisplayTests, many_to_one_display_mapping) {
+ ui::LayerStack layerStack = ui::LayerStack::fromValue(42);
+ createDisplay(1000, 1000, false /*isSecure*/, layerStack, false /*receivesInput*/,
+ 100 /*offsetX*/, 100 /*offsetY*/);
+ createDisplay(1000, 1000, false /*isSecure*/, layerStack, true /*receivesInput*/,
+ 200 /*offsetX*/, 200 /*offsetY*/);
+ createDisplay(1000, 1000, false /*isSecure*/, layerStack, false /*receivesInput*/,
+ 300 /*offsetX*/, 300 /*offsetY*/);
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ surface->doTransaction([&](auto &t, auto &sc) { t.setLayerStack(sc, layerStack); });
+ surface->showAt(10, 10);
+
+ // Input injection happens in logical display coordinates.
+ injectTapOnDisplay(11, 11, layerStack.id);
+ // Expect that the display transform for the display that receives input was used.
+ surface->expectTapInDisplayCoordinates(211, 211);
+
+ surface->requestFocus(layerStack.id);
+ surface->assertFocusChange(true);
+ injectKeyOnDisplay(AKEYCODE_V, layerStack.id);
+}
+
TEST_F(MultiDisplayTests, drop_input_for_secure_layer_on_nonsecure_display) {
ui::LayerStack layerStack = ui::LayerStack::fromValue(42);
createDisplay(1000, 1000, false /*isSecure*/, layerStack);
@@ -1004,7 +1090,7 @@
});
surface->showAt(100, 100);
- injectTap(101, 101);
+ injectTapOnDisplay(101, 101, layerStack.id);
EXPECT_EQ(surface->consumeEvent(100), nullptr);
@@ -1016,7 +1102,13 @@
TEST_F(MultiDisplayTests, dont_drop_input_for_secure_layer_on_secure_display) {
ui::LayerStack layerStack = ui::LayerStack::fromValue(42);
+
+ // Create the secure display as system, because only certain users can create secure displays.
+ seteuid(AID_SYSTEM);
createDisplay(1000, 1000, true /*isSecure*/, layerStack);
+ // Change the uid back to root.
+ seteuid(AID_ROOT);
+
std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
surface->doTransaction([&](auto &t, auto &sc) {
t.setFlags(sc, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index d6ac3f9..d5e089a 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -882,6 +882,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/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/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index b9cc648..d646756 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -189,6 +189,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) {}
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/ui/Android.bp b/libs/ui/Android.bp
index 006c478..980fc8b 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -29,6 +29,11 @@
],
}
+cc_library_headers {
+ name: "libui_fuzzableDataspaces_headers",
+ export_include_dirs: ["include/ui/fuzzer/"],
+}
+
cc_defaults {
name: "libui-defaults",
clang: true,
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/libs/ui/include/ui/fuzzer/FuzzableDataspaces.h b/libs/ui/include/ui/fuzzer/FuzzableDataspaces.h
new file mode 100644
index 0000000..4200d6a
--- /dev/null
+++ b/libs/ui/include/ui/fuzzer/FuzzableDataspaces.h
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+#include <ui/GraphicTypes.h>
+using namespace android;
+
+constexpr ui::Dataspace kDataspaces[] = {
+ ui::Dataspace::UNKNOWN,
+ ui::Dataspace::ARBITRARY,
+ ui::Dataspace::STANDARD_UNSPECIFIED,
+ ui::Dataspace::STANDARD_BT709,
+ ui::Dataspace::STANDARD_BT601_625,
+ ui::Dataspace::STANDARD_BT601_625_UNADJUSTED,
+ ui::Dataspace::STANDARD_BT601_525,
+ ui::Dataspace::STANDARD_BT601_525_UNADJUSTED,
+ ui::Dataspace::STANDARD_BT2020,
+ ui::Dataspace::STANDARD_BT2020_CONSTANT_LUMINANCE,
+ ui::Dataspace::STANDARD_BT470M,
+ ui::Dataspace::STANDARD_FILM,
+ ui::Dataspace::STANDARD_DCI_P3,
+ ui::Dataspace::STANDARD_ADOBE_RGB,
+ ui::Dataspace::TRANSFER_UNSPECIFIED,
+ ui::Dataspace::TRANSFER_LINEAR,
+ ui::Dataspace::TRANSFER_SRGB,
+ ui::Dataspace::TRANSFER_SMPTE_170M,
+ ui::Dataspace::TRANSFER_GAMMA2_2,
+ ui::Dataspace::TRANSFER_GAMMA2_6,
+ ui::Dataspace::TRANSFER_GAMMA2_8,
+ ui::Dataspace::TRANSFER_ST2084,
+ ui::Dataspace::TRANSFER_HLG,
+ ui::Dataspace::RANGE_UNSPECIFIED,
+ ui::Dataspace::RANGE_FULL,
+ ui::Dataspace::RANGE_LIMITED,
+ ui::Dataspace::RANGE_EXTENDED,
+ ui::Dataspace::SRGB_LINEAR,
+ ui::Dataspace::V0_SRGB_LINEAR,
+ ui::Dataspace::V0_SCRGB_LINEAR,
+ ui::Dataspace::SRGB,
+ ui::Dataspace::V0_SRGB,
+ ui::Dataspace::V0_SCRGB,
+ ui::Dataspace::JFIF,
+ ui::Dataspace::V0_JFIF,
+ ui::Dataspace::BT601_625,
+ ui::Dataspace::V0_BT601_625,
+ ui::Dataspace::BT601_525,
+ ui::Dataspace::V0_BT601_525,
+ ui::Dataspace::BT709,
+ ui::Dataspace::V0_BT709,
+ ui::Dataspace::DCI_P3_LINEAR,
+ ui::Dataspace::DCI_P3,
+ ui::Dataspace::DISPLAY_P3_LINEAR,
+ ui::Dataspace::DISPLAY_P3,
+ ui::Dataspace::ADOBE_RGB,
+ ui::Dataspace::BT2020_LINEAR,
+ ui::Dataspace::BT2020,
+ ui::Dataspace::BT2020_PQ,
+ ui::Dataspace::DEPTH,
+ ui::Dataspace::SENSOR,
+ ui::Dataspace::BT2020_ITU,
+ ui::Dataspace::BT2020_ITU_PQ,
+ ui::Dataspace::BT2020_ITU_HLG,
+ ui::Dataspace::BT2020_HLG,
+ ui::Dataspace::DISPLAY_BT2020,
+ ui::Dataspace::DYNAMIC_DEPTH,
+ ui::Dataspace::JPEG_APP_SEGMENTS,
+ ui::Dataspace::HEIF,
+};
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 8cdb706..ec58325 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -24,6 +24,7 @@
cc_defaults {
name: "inputflinger_defaults",
+ cpp_std: "c++20",
cflags: [
"-Wall",
"-Wextra",
@@ -71,7 +72,6 @@
"libstatssocket",
"libutils",
"libui",
- "lib-platform-compat-native-api",
"server_configurable_flags",
],
static_libs: [
diff --git a/services/inputflinger/BlockingQueue.h b/services/inputflinger/BlockingQueue.h
index b612ca7..8300e8a 100644
--- a/services/inputflinger/BlockingQueue.h
+++ b/services/inputflinger/BlockingQueue.h
@@ -71,8 +71,7 @@
void erase(const std::function<bool(const T&)>& lambda) {
std::scoped_lock lock(mLock);
- mQueue.erase(std::remove_if(mQueue.begin(), mQueue.end(),
- [&lambda](const T& t) { return lambda(t); }), mQueue.end());
+ std::erase_if(mQueue, [&lambda](const auto& t) { return lambda(t); });
}
/**
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 ff2e4a0..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 {
@@ -91,7 +88,6 @@
constexpr bool DEBUG_TOUCH_MODE = false;
// Log debug messages about touch occlusion
-// STOPSHIP(b/169067926): Set to false
constexpr bool DEBUG_TOUCH_OCCLUSION = true;
// Log debug messages about the app switch latency optimization.
@@ -412,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,
@@ -571,8 +558,7 @@
mFocusedDisplayId(ADISPLAY_ID_DEFAULT),
mWindowTokenWithPointerCapture(nullptr),
mLatencyAggregator(),
- mLatencyTracker(&mLatencyAggregator),
- mCompatService(getCompatService()) {
+ mLatencyTracker(&mLatencyAggregator) {
mLooper = new Looper(false);
mReporter = createInputReporter();
@@ -4813,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/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp
index d624e99..08c7826 100644
--- a/services/inputflinger/dispatcher/TouchState.cpp
+++ b/services/inputflinger/dispatcher/TouchState.cpp
@@ -106,10 +106,8 @@
}
void TouchState::filterWindowsExcept(const sp<IBinder>& token) {
- auto it = std::remove_if(windows.begin(), windows.end(), [&token](const TouchedWindow& w) {
- return w.windowHandle->getToken() != token;
- });
- windows.erase(it, windows.end());
+ std::erase_if(windows,
+ [&token](const TouchedWindow& w) { return w.windowHandle->getToken() != token; });
}
sp<WindowInfoHandle> TouchState::getFirstForegroundWindowHandle() const {
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index d10f8b6..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) {
@@ -2344,13 +2343,10 @@
return;
}
}
- mUnattachedVideoDevices
- .erase(std::remove_if(mUnattachedVideoDevices.begin(), mUnattachedVideoDevices.end(),
- [&devicePath](
- const std::unique_ptr<TouchVideoDevice>& videoDevice) {
- return videoDevice->getPath() == devicePath;
- }),
- mUnattachedVideoDevices.end());
+ std::erase_if(mUnattachedVideoDevices,
+ [&devicePath](const std::unique_ptr<TouchVideoDevice>& videoDevice) {
+ return videoDevice->getPath() == devicePath;
+ });
}
void EventHub::closeAllDevicesLocked() {
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 7704a84..564db56 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -237,9 +237,7 @@
auto mapIt = mDeviceToEventHubIdsMap.find(device);
if (mapIt != mDeviceToEventHubIdsMap.end()) {
std::vector<int32_t>& eventHubIds = mapIt->second;
- eventHubIds.erase(std::remove_if(eventHubIds.begin(), eventHubIds.end(),
- [eventHubId](int32_t eId) { return eId == eventHubId; }),
- eventHubIds.end());
+ std::erase_if(eventHubIds, [eventHubId](int32_t eId) { return eId == eventHubId; });
if (eventHubIds.size() == 0) {
mDeviceToEventHubIdsMap.erase(mapIt);
}
diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h
index f1c0e5a..d83d74d 100644
--- a/services/inputflinger/reader/mapper/InputMapper.h
+++ b/services/inputflinger/reader/mapper/InputMapper.h
@@ -45,7 +45,7 @@
inline int32_t getDeviceId() { return mDeviceContext.getId(); }
inline InputDeviceContext& getDeviceContext() { return mDeviceContext; }
- inline const std::string getDeviceName() { return mDeviceContext.getName(); }
+ inline const std::string getDeviceName() const { return mDeviceContext.getName(); }
inline InputReaderContext* getContext() { return mDeviceContext.getContext(); }
inline InputReaderPolicyInterface* getPolicy() { return getContext()->getPolicy(); }
inline InputListenerInterface& getListener() { return getContext()->getListener(); }
diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
index 6bdb121..ad11b05 100644
--- a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
@@ -32,8 +32,7 @@
void JoystickInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
InputMapper::populateDeviceInfo(info);
- for (std::pair<const int32_t, Axis>& pair : mAxes) {
- const Axis& axis = pair.second;
+ for (const auto& [_, axis] : mAxes) {
addMotionRange(axis.axisInfo.axis, axis, info);
if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 6f49f31..0a5de27 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -609,6 +609,270 @@
return std::make_optional(newViewport);
}
+int32_t TouchInputMapper::clampResolution(const char* axisName, int32_t resolution) const {
+ if (resolution < 0) {
+ ALOGE("Invalid %s resolution %" PRId32 " for device %s", axisName, resolution,
+ getDeviceName().c_str());
+ return 0;
+ }
+ return resolution;
+}
+
+void TouchInputMapper::initializeSizeRanges() {
+ if (mCalibration.sizeCalibration == Calibration::SizeCalibration::NONE) {
+ mSizeScale = 0.0f;
+ return;
+ }
+
+ // Size of diagonal axis.
+ const float diagonalSize = hypotf(mDisplayWidth, mDisplayHeight);
+
+ // Size factors.
+ if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.touchMajor.maxValue != 0) {
+ mSizeScale = 1.0f / mRawPointerAxes.touchMajor.maxValue;
+ } else if (mRawPointerAxes.toolMajor.valid && mRawPointerAxes.toolMajor.maxValue != 0) {
+ mSizeScale = 1.0f / mRawPointerAxes.toolMajor.maxValue;
+ } else {
+ mSizeScale = 0.0f;
+ }
+
+ mOrientedRanges.haveTouchSize = true;
+ mOrientedRanges.haveToolSize = true;
+ mOrientedRanges.haveSize = true;
+
+ mOrientedRanges.touchMajor.axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR;
+ mOrientedRanges.touchMajor.source = mSource;
+ mOrientedRanges.touchMajor.min = 0;
+ mOrientedRanges.touchMajor.max = diagonalSize;
+ mOrientedRanges.touchMajor.flat = 0;
+ mOrientedRanges.touchMajor.fuzz = 0;
+ mOrientedRanges.touchMajor.resolution = 0;
+ if (mRawPointerAxes.touchMajor.valid) {
+ mRawPointerAxes.touchMajor.resolution =
+ clampResolution("touchMajor", mRawPointerAxes.touchMajor.resolution);
+ mOrientedRanges.touchMajor.resolution = mRawPointerAxes.touchMajor.resolution;
+ }
+
+ mOrientedRanges.touchMinor = mOrientedRanges.touchMajor;
+ mOrientedRanges.touchMinor.axis = AMOTION_EVENT_AXIS_TOUCH_MINOR;
+ if (mRawPointerAxes.touchMinor.valid) {
+ mRawPointerAxes.touchMinor.resolution =
+ clampResolution("touchMinor", mRawPointerAxes.touchMinor.resolution);
+ mOrientedRanges.touchMinor.resolution = mRawPointerAxes.touchMinor.resolution;
+ }
+
+ mOrientedRanges.toolMajor.axis = AMOTION_EVENT_AXIS_TOOL_MAJOR;
+ mOrientedRanges.toolMajor.source = mSource;
+ mOrientedRanges.toolMajor.min = 0;
+ mOrientedRanges.toolMajor.max = diagonalSize;
+ mOrientedRanges.toolMajor.flat = 0;
+ mOrientedRanges.toolMajor.fuzz = 0;
+ mOrientedRanges.toolMajor.resolution = 0;
+ if (mRawPointerAxes.toolMajor.valid) {
+ mRawPointerAxes.toolMajor.resolution =
+ clampResolution("toolMajor", mRawPointerAxes.toolMajor.resolution);
+ mOrientedRanges.toolMajor.resolution = mRawPointerAxes.toolMajor.resolution;
+ }
+
+ mOrientedRanges.toolMinor = mOrientedRanges.toolMajor;
+ mOrientedRanges.toolMinor.axis = AMOTION_EVENT_AXIS_TOOL_MINOR;
+ if (mRawPointerAxes.toolMinor.valid) {
+ mRawPointerAxes.toolMinor.resolution =
+ clampResolution("toolMinor", mRawPointerAxes.toolMinor.resolution);
+ mOrientedRanges.toolMinor.resolution = mRawPointerAxes.toolMinor.resolution;
+ }
+
+ if (mCalibration.sizeCalibration == Calibration::SizeCalibration::GEOMETRIC) {
+ mOrientedRanges.touchMajor.resolution *= mGeometricScale;
+ mOrientedRanges.touchMinor.resolution *= mGeometricScale;
+ mOrientedRanges.toolMajor.resolution *= mGeometricScale;
+ mOrientedRanges.toolMinor.resolution *= mGeometricScale;
+ } else {
+ // Support for other calibrations can be added here.
+ ALOGW("%s calibration is not supported for size ranges at the moment. "
+ "Using raw resolution instead",
+ ftl::enum_string(mCalibration.sizeCalibration).c_str());
+ }
+
+ mOrientedRanges.size.axis = AMOTION_EVENT_AXIS_SIZE;
+ mOrientedRanges.size.source = mSource;
+ mOrientedRanges.size.min = 0;
+ mOrientedRanges.size.max = 1.0;
+ mOrientedRanges.size.flat = 0;
+ mOrientedRanges.size.fuzz = 0;
+ mOrientedRanges.size.resolution = 0;
+}
+
+void TouchInputMapper::initializeOrientedRanges() {
+ // Configure X and Y factors.
+ mXScale = float(mDisplayWidth) / mRawPointerAxes.getRawWidth();
+ mYScale = float(mDisplayHeight) / mRawPointerAxes.getRawHeight();
+ mXPrecision = 1.0f / mXScale;
+ mYPrecision = 1.0f / mYScale;
+
+ mOrientedRanges.x.axis = AMOTION_EVENT_AXIS_X;
+ mOrientedRanges.x.source = mSource;
+ mOrientedRanges.y.axis = AMOTION_EVENT_AXIS_Y;
+ mOrientedRanges.y.source = mSource;
+
+ // Scale factor for terms that are not oriented in a particular axis.
+ // If the pixels are square then xScale == yScale otherwise we fake it
+ // by choosing an average.
+ mGeometricScale = avg(mXScale, mYScale);
+
+ initializeSizeRanges();
+
+ // Pressure factors.
+ mPressureScale = 0;
+ float pressureMax = 1.0;
+ if (mCalibration.pressureCalibration == Calibration::PressureCalibration::PHYSICAL ||
+ mCalibration.pressureCalibration == Calibration::PressureCalibration::AMPLITUDE) {
+ if (mCalibration.havePressureScale) {
+ mPressureScale = mCalibration.pressureScale;
+ pressureMax = mPressureScale * mRawPointerAxes.pressure.maxValue;
+ } else if (mRawPointerAxes.pressure.valid && mRawPointerAxes.pressure.maxValue != 0) {
+ mPressureScale = 1.0f / mRawPointerAxes.pressure.maxValue;
+ }
+ }
+
+ mOrientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE;
+ mOrientedRanges.pressure.source = mSource;
+ mOrientedRanges.pressure.min = 0;
+ mOrientedRanges.pressure.max = pressureMax;
+ mOrientedRanges.pressure.flat = 0;
+ mOrientedRanges.pressure.fuzz = 0;
+ mOrientedRanges.pressure.resolution = 0;
+
+ // Tilt
+ mTiltXCenter = 0;
+ mTiltXScale = 0;
+ mTiltYCenter = 0;
+ mTiltYScale = 0;
+ mHaveTilt = mRawPointerAxes.tiltX.valid && mRawPointerAxes.tiltY.valid;
+ if (mHaveTilt) {
+ mTiltXCenter = avg(mRawPointerAxes.tiltX.minValue, mRawPointerAxes.tiltX.maxValue);
+ mTiltYCenter = avg(mRawPointerAxes.tiltY.minValue, mRawPointerAxes.tiltY.maxValue);
+ mTiltXScale = M_PI / 180;
+ mTiltYScale = M_PI / 180;
+
+ if (mRawPointerAxes.tiltX.resolution) {
+ mTiltXScale = 1.0 / mRawPointerAxes.tiltX.resolution;
+ }
+ if (mRawPointerAxes.tiltY.resolution) {
+ mTiltYScale = 1.0 / mRawPointerAxes.tiltY.resolution;
+ }
+
+ mOrientedRanges.haveTilt = true;
+
+ mOrientedRanges.tilt.axis = AMOTION_EVENT_AXIS_TILT;
+ mOrientedRanges.tilt.source = mSource;
+ mOrientedRanges.tilt.min = 0;
+ mOrientedRanges.tilt.max = M_PI_2;
+ mOrientedRanges.tilt.flat = 0;
+ mOrientedRanges.tilt.fuzz = 0;
+ mOrientedRanges.tilt.resolution = 0;
+ }
+
+ // Orientation
+ mOrientationScale = 0;
+ if (mHaveTilt) {
+ mOrientedRanges.haveOrientation = true;
+
+ mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION;
+ mOrientedRanges.orientation.source = mSource;
+ mOrientedRanges.orientation.min = -M_PI;
+ mOrientedRanges.orientation.max = M_PI;
+ mOrientedRanges.orientation.flat = 0;
+ mOrientedRanges.orientation.fuzz = 0;
+ mOrientedRanges.orientation.resolution = 0;
+ } else if (mCalibration.orientationCalibration != Calibration::OrientationCalibration::NONE) {
+ if (mCalibration.orientationCalibration ==
+ Calibration::OrientationCalibration::INTERPOLATED) {
+ if (mRawPointerAxes.orientation.valid) {
+ if (mRawPointerAxes.orientation.maxValue > 0) {
+ mOrientationScale = M_PI_2 / mRawPointerAxes.orientation.maxValue;
+ } else if (mRawPointerAxes.orientation.minValue < 0) {
+ mOrientationScale = -M_PI_2 / mRawPointerAxes.orientation.minValue;
+ } else {
+ mOrientationScale = 0;
+ }
+ }
+ }
+
+ mOrientedRanges.haveOrientation = true;
+
+ mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION;
+ mOrientedRanges.orientation.source = mSource;
+ mOrientedRanges.orientation.min = -M_PI_2;
+ mOrientedRanges.orientation.max = M_PI_2;
+ mOrientedRanges.orientation.flat = 0;
+ mOrientedRanges.orientation.fuzz = 0;
+ mOrientedRanges.orientation.resolution = 0;
+ }
+
+ // Distance
+ mDistanceScale = 0;
+ if (mCalibration.distanceCalibration != Calibration::DistanceCalibration::NONE) {
+ if (mCalibration.distanceCalibration == Calibration::DistanceCalibration::SCALED) {
+ if (mCalibration.haveDistanceScale) {
+ mDistanceScale = mCalibration.distanceScale;
+ } else {
+ mDistanceScale = 1.0f;
+ }
+ }
+
+ mOrientedRanges.haveDistance = true;
+
+ mOrientedRanges.distance.axis = AMOTION_EVENT_AXIS_DISTANCE;
+ mOrientedRanges.distance.source = mSource;
+ mOrientedRanges.distance.min = mRawPointerAxes.distance.minValue * mDistanceScale;
+ mOrientedRanges.distance.max = mRawPointerAxes.distance.maxValue * mDistanceScale;
+ mOrientedRanges.distance.flat = 0;
+ mOrientedRanges.distance.fuzz = mRawPointerAxes.distance.fuzz * mDistanceScale;
+ mOrientedRanges.distance.resolution = 0;
+ }
+
+ // Compute oriented precision, scales and ranges.
+ // Note that the maximum value reported is an inclusive maximum value so it is one
+ // unit less than the total width or height of the display.
+ switch (mInputDeviceOrientation) {
+ case DISPLAY_ORIENTATION_90:
+ case DISPLAY_ORIENTATION_270:
+ mOrientedXPrecision = mYPrecision;
+ mOrientedYPrecision = mXPrecision;
+
+ mOrientedRanges.x.min = 0;
+ mOrientedRanges.x.max = mDisplayHeight - 1;
+ mOrientedRanges.x.flat = 0;
+ mOrientedRanges.x.fuzz = 0;
+ mOrientedRanges.x.resolution = mRawPointerAxes.y.resolution * mYScale;
+
+ mOrientedRanges.y.min = 0;
+ mOrientedRanges.y.max = mDisplayWidth - 1;
+ mOrientedRanges.y.flat = 0;
+ mOrientedRanges.y.fuzz = 0;
+ mOrientedRanges.y.resolution = mRawPointerAxes.x.resolution * mXScale;
+ break;
+
+ default:
+ mOrientedXPrecision = mXPrecision;
+ mOrientedYPrecision = mYPrecision;
+
+ mOrientedRanges.x.min = 0;
+ mOrientedRanges.x.max = mDisplayWidth - 1;
+ mOrientedRanges.x.flat = 0;
+ mOrientedRanges.x.fuzz = 0;
+ mOrientedRanges.x.resolution = mRawPointerAxes.x.resolution * mXScale;
+
+ mOrientedRanges.y.min = 0;
+ mOrientedRanges.y.max = mDisplayHeight - 1;
+ mOrientedRanges.y.flat = 0;
+ mOrientedRanges.y.fuzz = 0;
+ mOrientedRanges.y.resolution = mRawPointerAxes.y.resolution * mYScale;
+ break;
+ }
+}
+
void TouchInputMapper::configureInputDevice(nsecs_t when, bool* outResetNeeded) {
DeviceMode oldDeviceMode = mDeviceMode;
@@ -795,224 +1059,9 @@
getDeviceId(), getDeviceName().c_str(), mDisplayWidth, mDisplayHeight,
mInputDeviceOrientation, mDeviceMode, mViewport.displayId);
- // Configure X and Y factors.
- mXScale = float(mDisplayWidth) / rawWidth;
- mYScale = float(mDisplayHeight) / rawHeight;
- mXPrecision = 1.0f / mXScale;
- mYPrecision = 1.0f / mYScale;
-
- mOrientedRanges.x.axis = AMOTION_EVENT_AXIS_X;
- mOrientedRanges.x.source = mSource;
- mOrientedRanges.y.axis = AMOTION_EVENT_AXIS_Y;
- mOrientedRanges.y.source = mSource;
-
configureVirtualKeys();
- // Scale factor for terms that are not oriented in a particular axis.
- // If the pixels are square then xScale == yScale otherwise we fake it
- // by choosing an average.
- mGeometricScale = avg(mXScale, mYScale);
-
- // Size of diagonal axis.
- float diagonalSize = hypotf(mDisplayWidth, mDisplayHeight);
-
- // Size factors.
- if (mCalibration.sizeCalibration != Calibration::SizeCalibration::NONE) {
- if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.touchMajor.maxValue != 0) {
- mSizeScale = 1.0f / mRawPointerAxes.touchMajor.maxValue;
- } else if (mRawPointerAxes.toolMajor.valid && mRawPointerAxes.toolMajor.maxValue != 0) {
- mSizeScale = 1.0f / mRawPointerAxes.toolMajor.maxValue;
- } else {
- mSizeScale = 0.0f;
- }
-
- mOrientedRanges.haveTouchSize = true;
- mOrientedRanges.haveToolSize = true;
- mOrientedRanges.haveSize = true;
-
- mOrientedRanges.touchMajor.axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR;
- mOrientedRanges.touchMajor.source = mSource;
- mOrientedRanges.touchMajor.min = 0;
- mOrientedRanges.touchMajor.max = diagonalSize;
- mOrientedRanges.touchMajor.flat = 0;
- mOrientedRanges.touchMajor.fuzz = 0;
- mOrientedRanges.touchMajor.resolution = 0;
-
- mOrientedRanges.touchMinor = mOrientedRanges.touchMajor;
- mOrientedRanges.touchMinor.axis = AMOTION_EVENT_AXIS_TOUCH_MINOR;
-
- mOrientedRanges.toolMajor.axis = AMOTION_EVENT_AXIS_TOOL_MAJOR;
- mOrientedRanges.toolMajor.source = mSource;
- mOrientedRanges.toolMajor.min = 0;
- mOrientedRanges.toolMajor.max = diagonalSize;
- mOrientedRanges.toolMajor.flat = 0;
- mOrientedRanges.toolMajor.fuzz = 0;
- mOrientedRanges.toolMajor.resolution = 0;
-
- mOrientedRanges.toolMinor = mOrientedRanges.toolMajor;
- mOrientedRanges.toolMinor.axis = AMOTION_EVENT_AXIS_TOOL_MINOR;
-
- mOrientedRanges.size.axis = AMOTION_EVENT_AXIS_SIZE;
- mOrientedRanges.size.source = mSource;
- mOrientedRanges.size.min = 0;
- mOrientedRanges.size.max = 1.0;
- mOrientedRanges.size.flat = 0;
- mOrientedRanges.size.fuzz = 0;
- mOrientedRanges.size.resolution = 0;
- } else {
- mSizeScale = 0.0f;
- }
-
- // Pressure factors.
- mPressureScale = 0;
- float pressureMax = 1.0;
- if (mCalibration.pressureCalibration == Calibration::PressureCalibration::PHYSICAL ||
- mCalibration.pressureCalibration == Calibration::PressureCalibration::AMPLITUDE) {
- if (mCalibration.havePressureScale) {
- mPressureScale = mCalibration.pressureScale;
- pressureMax = mPressureScale * mRawPointerAxes.pressure.maxValue;
- } else if (mRawPointerAxes.pressure.valid && mRawPointerAxes.pressure.maxValue != 0) {
- mPressureScale = 1.0f / mRawPointerAxes.pressure.maxValue;
- }
- }
-
- mOrientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE;
- mOrientedRanges.pressure.source = mSource;
- mOrientedRanges.pressure.min = 0;
- mOrientedRanges.pressure.max = pressureMax;
- mOrientedRanges.pressure.flat = 0;
- mOrientedRanges.pressure.fuzz = 0;
- mOrientedRanges.pressure.resolution = 0;
-
- // Tilt
- mTiltXCenter = 0;
- mTiltXScale = 0;
- mTiltYCenter = 0;
- mTiltYScale = 0;
- mHaveTilt = mRawPointerAxes.tiltX.valid && mRawPointerAxes.tiltY.valid;
- if (mHaveTilt) {
- mTiltXCenter = avg(mRawPointerAxes.tiltX.minValue, mRawPointerAxes.tiltX.maxValue);
- mTiltYCenter = avg(mRawPointerAxes.tiltY.minValue, mRawPointerAxes.tiltY.maxValue);
- mTiltXScale = M_PI / 180;
- mTiltYScale = M_PI / 180;
-
- if (mRawPointerAxes.tiltX.resolution) {
- mTiltXScale = 1.0 / mRawPointerAxes.tiltX.resolution;
- }
- if (mRawPointerAxes.tiltY.resolution) {
- mTiltYScale = 1.0 / mRawPointerAxes.tiltY.resolution;
- }
-
- mOrientedRanges.haveTilt = true;
-
- mOrientedRanges.tilt.axis = AMOTION_EVENT_AXIS_TILT;
- mOrientedRanges.tilt.source = mSource;
- mOrientedRanges.tilt.min = 0;
- mOrientedRanges.tilt.max = M_PI_2;
- mOrientedRanges.tilt.flat = 0;
- mOrientedRanges.tilt.fuzz = 0;
- mOrientedRanges.tilt.resolution = 0;
- }
-
- // Orientation
- mOrientationScale = 0;
- if (mHaveTilt) {
- mOrientedRanges.haveOrientation = true;
-
- mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION;
- mOrientedRanges.orientation.source = mSource;
- mOrientedRanges.orientation.min = -M_PI;
- mOrientedRanges.orientation.max = M_PI;
- mOrientedRanges.orientation.flat = 0;
- mOrientedRanges.orientation.fuzz = 0;
- mOrientedRanges.orientation.resolution = 0;
- } else if (mCalibration.orientationCalibration !=
- Calibration::OrientationCalibration::NONE) {
- if (mCalibration.orientationCalibration ==
- Calibration::OrientationCalibration::INTERPOLATED) {
- if (mRawPointerAxes.orientation.valid) {
- if (mRawPointerAxes.orientation.maxValue > 0) {
- mOrientationScale = M_PI_2 / mRawPointerAxes.orientation.maxValue;
- } else if (mRawPointerAxes.orientation.minValue < 0) {
- mOrientationScale = -M_PI_2 / mRawPointerAxes.orientation.minValue;
- } else {
- mOrientationScale = 0;
- }
- }
- }
-
- mOrientedRanges.haveOrientation = true;
-
- mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION;
- mOrientedRanges.orientation.source = mSource;
- mOrientedRanges.orientation.min = -M_PI_2;
- mOrientedRanges.orientation.max = M_PI_2;
- mOrientedRanges.orientation.flat = 0;
- mOrientedRanges.orientation.fuzz = 0;
- mOrientedRanges.orientation.resolution = 0;
- }
-
- // Distance
- mDistanceScale = 0;
- if (mCalibration.distanceCalibration != Calibration::DistanceCalibration::NONE) {
- if (mCalibration.distanceCalibration == Calibration::DistanceCalibration::SCALED) {
- if (mCalibration.haveDistanceScale) {
- mDistanceScale = mCalibration.distanceScale;
- } else {
- mDistanceScale = 1.0f;
- }
- }
-
- mOrientedRanges.haveDistance = true;
-
- mOrientedRanges.distance.axis = AMOTION_EVENT_AXIS_DISTANCE;
- mOrientedRanges.distance.source = mSource;
- mOrientedRanges.distance.min = mRawPointerAxes.distance.minValue * mDistanceScale;
- mOrientedRanges.distance.max = mRawPointerAxes.distance.maxValue * mDistanceScale;
- mOrientedRanges.distance.flat = 0;
- mOrientedRanges.distance.fuzz = mRawPointerAxes.distance.fuzz * mDistanceScale;
- mOrientedRanges.distance.resolution = 0;
- }
-
- // Compute oriented precision, scales and ranges.
- // Note that the maximum value reported is an inclusive maximum value so it is one
- // unit less than the total width or height of the display.
- switch (mInputDeviceOrientation) {
- case DISPLAY_ORIENTATION_90:
- case DISPLAY_ORIENTATION_270:
- mOrientedXPrecision = mYPrecision;
- mOrientedYPrecision = mXPrecision;
-
- mOrientedRanges.x.min = 0;
- mOrientedRanges.x.max = mDisplayHeight - 1;
- mOrientedRanges.x.flat = 0;
- mOrientedRanges.x.fuzz = 0;
- mOrientedRanges.x.resolution = mRawPointerAxes.y.resolution * mYScale;
-
- mOrientedRanges.y.min = 0;
- mOrientedRanges.y.max = mDisplayWidth - 1;
- mOrientedRanges.y.flat = 0;
- mOrientedRanges.y.fuzz = 0;
- mOrientedRanges.y.resolution = mRawPointerAxes.x.resolution * mXScale;
- break;
-
- default:
- mOrientedXPrecision = mXPrecision;
- mOrientedYPrecision = mYPrecision;
-
- mOrientedRanges.x.min = 0;
- mOrientedRanges.x.max = mDisplayWidth - 1;
- mOrientedRanges.x.flat = 0;
- mOrientedRanges.x.fuzz = 0;
- mOrientedRanges.x.resolution = mRawPointerAxes.x.resolution * mXScale;
-
- mOrientedRanges.y.min = 0;
- mOrientedRanges.y.max = mDisplayHeight - 1;
- mOrientedRanges.y.flat = 0;
- mOrientedRanges.y.fuzz = 0;
- mOrientedRanges.y.resolution = mRawPointerAxes.y.resolution * mYScale;
- break;
- }
+ initializeOrientedRanges();
// Location
updateAffineTransformation();
@@ -1267,26 +1316,8 @@
void TouchInputMapper::dumpCalibration(std::string& dump) {
dump += INDENT3 "Calibration:\n";
- // Size
- switch (mCalibration.sizeCalibration) {
- case Calibration::SizeCalibration::NONE:
- dump += INDENT4 "touch.size.calibration: none\n";
- break;
- case Calibration::SizeCalibration::GEOMETRIC:
- dump += INDENT4 "touch.size.calibration: geometric\n";
- break;
- case Calibration::SizeCalibration::DIAMETER:
- dump += INDENT4 "touch.size.calibration: diameter\n";
- break;
- case Calibration::SizeCalibration::BOX:
- dump += INDENT4 "touch.size.calibration: box\n";
- break;
- case Calibration::SizeCalibration::AREA:
- dump += INDENT4 "touch.size.calibration: area\n";
- break;
- default:
- ALOG_ASSERT(false);
- }
+ dump += INDENT4 "touch.size.calibration: ";
+ dump += ftl::enum_string(mCalibration.sizeCalibration) + "\n";
if (mCalibration.haveSizeScale) {
dump += StringPrintf(INDENT4 "touch.size.scale: %0.3f\n", mCalibration.sizeScale);
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index 9b020a6..9fd30e4 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -243,6 +243,7 @@
DIAMETER,
BOX,
AREA,
+ ftl_last = AREA
};
SizeCalibration sizeCalibration;
@@ -732,6 +733,10 @@
void resetExternalStylus();
void clearStylusDataPendingFlags();
+ int32_t clampResolution(const char* axisName, int32_t resolution) const;
+ void initializeOrientedRanges();
+ void initializeSizeRanges();
+
void sync(nsecs_t when, nsecs_t readTime);
bool consumeRawTouches(nsecs_t when, nsecs_t readTime, uint32_t policyFlags);
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 336afc6..2c5b321 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -78,6 +78,15 @@
static constexpr int32_t LIGHT_COLOR = 0x7F448866;
static constexpr int32_t LIGHT_PLAYER_ID = 2;
+static constexpr int32_t ACTION_POINTER_0_DOWN =
+ AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+static constexpr int32_t ACTION_POINTER_0_UP =
+ AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+static constexpr int32_t ACTION_POINTER_1_DOWN =
+ AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+static constexpr int32_t ACTION_POINTER_1_UP =
+ AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+
// Error tolerance for floating point assertions.
static const float EPSILON = 0.001f;
@@ -106,6 +115,24 @@
}
}
+static void assertAxisResolution(MultiTouchInputMapper& mapper, int axis, float resolution) {
+ InputDeviceInfo info;
+ mapper.populateDeviceInfo(&info);
+
+ const InputDeviceInfo::MotionRange* motionRange =
+ info.getMotionRange(axis, AINPUT_SOURCE_TOUCHSCREEN);
+ ASSERT_NEAR(motionRange->resolution, resolution, EPSILON);
+}
+
+static void assertAxisNotPresent(MultiTouchInputMapper& mapper, int axis) {
+ InputDeviceInfo info;
+ mapper.populateDeviceInfo(&info);
+
+ const InputDeviceInfo::MotionRange* motionRange =
+ info.getMotionRange(axis, AINPUT_SOURCE_TOUCHSCREEN);
+ ASSERT_EQ(nullptr, motionRange);
+}
+
// --- FakePointerController ---
class FakePointerController : public PointerControllerInterface {
@@ -2303,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;
};
@@ -2313,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);
}
@@ -2335,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);
@@ -2342,29 +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(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- args.action);
+ 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(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- args.action);
+ 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();
@@ -2373,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);
@@ -2381,12 +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(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- args.action);
+ 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);
@@ -2394,19 +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(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- args.action);
+ 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);
@@ -6488,7 +6634,7 @@
mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MAJOR, RAW_TOOL_MIN, RAW_TOOL_MAX,
0, 0);
if (axes & MINOR) {
- mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MINOR, RAW_TOOL_MAX,
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MINOR, RAW_TOOL_MIN,
RAW_TOOL_MAX, 0, 0);
}
}
@@ -6622,8 +6768,7 @@
ASSERT_EQ(DEVICE_ID, motionArgs.deviceId);
ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source);
ASSERT_EQ(uint32_t(0), motionArgs.policyFlags);
- ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- motionArgs.action);
+ ASSERT_EQ(ACTION_POINTER_1_DOWN, motionArgs.action);
ASSERT_EQ(0, motionArgs.flags);
ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState);
ASSERT_EQ(0, motionArgs.buttonState);
@@ -6683,8 +6828,7 @@
ASSERT_EQ(DEVICE_ID, motionArgs.deviceId);
ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source);
ASSERT_EQ(uint32_t(0), motionArgs.policyFlags);
- ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- motionArgs.action);
+ ASSERT_EQ(ACTION_POINTER_0_UP, motionArgs.action);
ASSERT_EQ(0, motionArgs.flags);
ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState);
ASSERT_EQ(0, motionArgs.buttonState);
@@ -6759,8 +6903,7 @@
ASSERT_EQ(DEVICE_ID, motionArgs.deviceId);
ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source);
ASSERT_EQ(uint32_t(0), motionArgs.policyFlags);
- ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- motionArgs.action);
+ ASSERT_EQ(ACTION_POINTER_0_DOWN, motionArgs.action);
ASSERT_EQ(0, motionArgs.flags);
ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState);
ASSERT_EQ(0, motionArgs.buttonState);
@@ -6789,8 +6932,7 @@
ASSERT_EQ(DEVICE_ID, motionArgs.deviceId);
ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source);
ASSERT_EQ(uint32_t(0), motionArgs.policyFlags);
- ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- motionArgs.action);
+ ASSERT_EQ(ACTION_POINTER_1_UP, motionArgs.action);
ASSERT_EQ(0, motionArgs.flags);
ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState);
ASSERT_EQ(0, motionArgs.buttonState);
@@ -6855,6 +6997,57 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
}
+TEST_F(MultiTouchInputMapperTest, AxisResolution_IsPopulated) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX, /*flat*/ 0,
+ /*fuzz*/ 0, /*resolution*/ 10);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, RAW_Y_MIN, RAW_Y_MAX, /*flat*/ 0,
+ /*fuzz*/ 0, /*resolution*/ 11);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOUCH_MAJOR, RAW_TOUCH_MIN, RAW_TOUCH_MAX,
+ /*flat*/ 0, /*fuzz*/ 0, /*resolution*/ 12);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOUCH_MINOR, RAW_TOUCH_MIN, RAW_TOUCH_MAX,
+ /*flat*/ 0, /*fuzz*/ 0, /*resolution*/ 13);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MAJOR, RAW_TOOL_MIN, RAW_TOOL_MAX,
+ /*flat*/ 0, /*flat*/ 0, /*resolution*/ 14);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MINOR, RAW_TOOL_MIN, RAW_TOOL_MAX,
+ /*flat*/ 0, /*flat*/ 0, /*resolution*/ 15);
+
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+ // X and Y axes
+ assertAxisResolution(mapper, AMOTION_EVENT_AXIS_X, 10 / X_PRECISION);
+ assertAxisResolution(mapper, AMOTION_EVENT_AXIS_Y, 11 / Y_PRECISION);
+ // Touch major and minor
+ assertAxisResolution(mapper, AMOTION_EVENT_AXIS_TOUCH_MAJOR, 12 * GEOMETRIC_SCALE);
+ assertAxisResolution(mapper, AMOTION_EVENT_AXIS_TOUCH_MINOR, 13 * GEOMETRIC_SCALE);
+ // Tool major and minor
+ assertAxisResolution(mapper, AMOTION_EVENT_AXIS_TOOL_MAJOR, 14 * GEOMETRIC_SCALE);
+ assertAxisResolution(mapper, AMOTION_EVENT_AXIS_TOOL_MINOR, 15 * GEOMETRIC_SCALE);
+}
+
+TEST_F(MultiTouchInputMapperTest, TouchMajorAndMinorAxes_DoNotAppearIfNotSupported) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX, /*flat*/ 0,
+ /*fuzz*/ 0, /*resolution*/ 10);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, RAW_Y_MIN, RAW_Y_MAX, /*flat*/ 0,
+ /*fuzz*/ 0, /*resolution*/ 11);
+
+ // We do not add ABS_MT_TOUCH_MAJOR / MINOR or ABS_MT_WIDTH_MAJOR / MINOR axes
+
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+ // Touch major and minor
+ assertAxisNotPresent(mapper, AMOTION_EVENT_AXIS_TOUCH_MAJOR);
+ assertAxisNotPresent(mapper, AMOTION_EVENT_AXIS_TOUCH_MINOR);
+ // Tool major and minor
+ assertAxisNotPresent(mapper, AMOTION_EVENT_AXIS_TOOL_MAJOR);
+ assertAxisNotPresent(mapper, AMOTION_EVENT_AXIS_TOOL_MINOR);
+}
+
TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingIds) {
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
@@ -6885,8 +7078,7 @@
toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0));
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
- ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- motionArgs.action);
+ ASSERT_EQ(ACTION_POINTER_1_DOWN, motionArgs.action);
ASSERT_EQ(size_t(2), motionArgs.pointerCount);
ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
@@ -6927,8 +7119,7 @@
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
- ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- motionArgs.action);
+ ASSERT_EQ(ACTION_POINTER_0_UP, motionArgs.action);
ASSERT_EQ(size_t(2), motionArgs.pointerCount);
ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
@@ -6973,8 +7164,7 @@
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
- ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- motionArgs.action);
+ ASSERT_EQ(ACTION_POINTER_0_DOWN, motionArgs.action);
ASSERT_EQ(size_t(2), motionArgs.pointerCount);
ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
@@ -6993,8 +7183,7 @@
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
- ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- motionArgs.action);
+ ASSERT_EQ(ACTION_POINTER_1_UP, motionArgs.action);
ASSERT_EQ(size_t(2), motionArgs.pointerCount);
ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
@@ -7059,8 +7248,7 @@
toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0));
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
- ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- motionArgs.action);
+ ASSERT_EQ(ACTION_POINTER_1_DOWN, motionArgs.action);
ASSERT_EQ(size_t(2), motionArgs.pointerCount);
ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
@@ -7100,8 +7288,7 @@
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
- ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- motionArgs.action);
+ ASSERT_EQ(ACTION_POINTER_0_UP, motionArgs.action);
ASSERT_EQ(size_t(2), motionArgs.pointerCount);
ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
@@ -7142,8 +7329,7 @@
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
- ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- motionArgs.action);
+ ASSERT_EQ(ACTION_POINTER_0_DOWN, motionArgs.action);
ASSERT_EQ(size_t(2), motionArgs.pointerCount);
ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
@@ -7163,8 +7349,7 @@
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
- ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- motionArgs.action);
+ ASSERT_EQ(ACTION_POINTER_1_UP, motionArgs.action);
ASSERT_EQ(size_t(2), motionArgs.pointerCount);
ASSERT_EQ(0, motionArgs.pointerProperties[0].id);
ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
@@ -7329,8 +7514,7 @@
ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
- ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- args.action);
+ ASSERT_EQ(ACTION_POINTER_1_DOWN, args.action);
ASSERT_EQ(size_t(2), args.pointerCount);
ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
x, y, 1.0f, size, touch, touch, tool, tool, 0, 0));
@@ -8460,8 +8644,7 @@
processPosition(mapper, x2, y2);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
- ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- motionArgs.action);
+ ASSERT_EQ(ACTION_POINTER_1_DOWN, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType);
// If the tool type of the first finger changes to MT_TOOL_PALM,
@@ -8471,8 +8654,7 @@
processToolType(mapper, MT_TOOL_PALM);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
- ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- motionArgs.action);
+ ASSERT_EQ(ACTION_POINTER_0_UP, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags);
// The following MOVE events of second finger should be processed.
@@ -8537,8 +8719,7 @@
processPosition(mapper, x2, y2);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
- ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- motionArgs.action);
+ ASSERT_EQ(ACTION_POINTER_1_DOWN, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
// If the tool type of the first finger changes to MT_TOOL_PALM,
@@ -8548,8 +8729,7 @@
processToolType(mapper, MT_TOOL_PALM);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
- ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- motionArgs.action);
+ ASSERT_EQ(ACTION_POINTER_0_UP, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags);
// Second finger keeps moving.
@@ -8637,8 +8817,7 @@
processPosition(mapper, x2, y2);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
- ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- motionArgs.action);
+ ASSERT_EQ(ACTION_POINTER_1_DOWN, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
// If the tool type of the second finger changes to MT_TOOL_PALM,
@@ -8647,8 +8826,7 @@
processToolType(mapper, MT_TOOL_PALM);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
- ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- motionArgs.action);
+ ASSERT_EQ(ACTION_POINTER_1_UP, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags);
// The following MOVE event should be processed.
@@ -8722,8 +8900,7 @@
processPressure(mapper, RAW_PRESSURE_MAX);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
- ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- motionArgs.action);
+ ASSERT_EQ(ACTION_POINTER_1_DOWN, motionArgs.action);
ASSERT_EQ(uint32_t(2), motionArgs.pointerCount);
// second finger up with some unexpected data.
@@ -8732,8 +8909,7 @@
processPosition(mapper, x2, y2);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
- ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- motionArgs.action);
+ ASSERT_EQ(ACTION_POINTER_1_UP, motionArgs.action);
ASSERT_EQ(uint32_t(2), motionArgs.pointerCount);
// first finger up with some unexpected data.
@@ -8845,8 +9021,7 @@
// expect coord[0] to contain previous location, coord[1] to contain new touch 1 location
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
- ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- args.action);
+ ASSERT_EQ(ACTION_POINTER_1_DOWN, args.action);
ASSERT_EQ(2U, args.pointerCount);
ASSERT_EQ(0, args.pointerProperties[0].id);
ASSERT_EQ(1, args.pointerProperties[1].id);
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
new file mode 100644
index 0000000..049d06a
--- /dev/null
+++ b/services/sensorservice/AidlSensorHalWrapper.cpp
@@ -0,0 +1,673 @@
+/*
+ * 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.
+ */
+
+#include "AidlSensorHalWrapper.h"
+#include "ISensorsWrapper.h"
+#include "SensorDeviceUtils.h"
+#include "android/hardware/sensors/2.0/types.h"
+
+#include <aidl/android/hardware/sensors/BnSensorsCallback.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+
+using ::aidl::android::hardware::sensors::AdditionalInfo;
+using ::aidl::android::hardware::sensors::DynamicSensorInfo;
+using ::aidl::android::hardware::sensors::Event;
+using ::aidl::android::hardware::sensors::ISensors;
+using ::aidl::android::hardware::sensors::SensorInfo;
+using ::aidl::android::hardware::sensors::SensorStatus;
+using ::aidl::android::hardware::sensors::SensorType;
+using ::android::AidlMessageQueue;
+using ::android::hardware::EventFlag;
+using ::android::hardware::sensors::V2_1::implementation::MAX_RECEIVE_BUFFER_EVENT_COUNT;
+
+namespace android {
+
+namespace {
+
+status_t convertToStatus(ndk::ScopedAStatus status) {
+ if (status.isOk()) {
+ return OK;
+ } else {
+ switch (status.getExceptionCode()) {
+ case EX_ILLEGAL_ARGUMENT: {
+ return BAD_VALUE;
+ }
+ case EX_SECURITY: {
+ return PERMISSION_DENIED;
+ }
+ case EX_UNSUPPORTED_OPERATION: {
+ return INVALID_OPERATION;
+ }
+ case EX_SERVICE_SPECIFIC: {
+ switch (status.getServiceSpecificError()) {
+ case ISensors::ERROR_BAD_VALUE: {
+ return BAD_VALUE;
+ }
+ case ISensors::ERROR_NO_MEMORY: {
+ return NO_MEMORY;
+ }
+ default: {
+ return UNKNOWN_ERROR;
+ }
+ }
+ }
+ default: {
+ return UNKNOWN_ERROR;
+ }
+ }
+ }
+}
+
+void convertToSensor(const SensorInfo &src, sensor_t *dst) {
+ dst->name = strdup(src.name.c_str());
+ dst->vendor = strdup(src.vendor.c_str());
+ dst->version = src.version;
+ dst->handle = src.sensorHandle;
+ dst->type = (int)src.type;
+ dst->maxRange = src.maxRange;
+ dst->resolution = src.resolution;
+ dst->power = src.power;
+ dst->minDelay = src.minDelayUs;
+ dst->fifoReservedEventCount = src.fifoReservedEventCount;
+ dst->fifoMaxEventCount = src.fifoMaxEventCount;
+ dst->stringType = strdup(src.typeAsString.c_str());
+ dst->requiredPermission = strdup(src.requiredPermission.c_str());
+ dst->maxDelay = src.maxDelayUs;
+ dst->flags = src.flags;
+ dst->reserved[0] = dst->reserved[1] = 0;
+}
+
+void convertToSensorEvent(const Event &src, sensors_event_t *dst) {
+ *dst = {.version = sizeof(sensors_event_t),
+ .sensor = src.sensorHandle,
+ .type = (int32_t)src.sensorType,
+ .reserved0 = 0,
+ .timestamp = src.timestamp};
+
+ switch (src.sensorType) {
+ case SensorType::META_DATA: {
+ // Legacy HALs expect the handle reference in the meta data field.
+ // Copy it over from the handle of the event.
+ dst->meta_data.what = (int32_t)src.payload.get<Event::EventPayload::meta>().what;
+ dst->meta_data.sensor = src.sensorHandle;
+ // Set the sensor handle to 0 to maintain compatibility.
+ dst->sensor = 0;
+ break;
+ }
+
+ case SensorType::ACCELEROMETER:
+ case SensorType::MAGNETIC_FIELD:
+ case SensorType::ORIENTATION:
+ case SensorType::GYROSCOPE:
+ case SensorType::GRAVITY:
+ case SensorType::LINEAR_ACCELERATION: {
+ dst->acceleration.x = src.payload.get<Event::EventPayload::vec3>().x;
+ dst->acceleration.y = src.payload.get<Event::EventPayload::vec3>().y;
+ dst->acceleration.z = src.payload.get<Event::EventPayload::vec3>().z;
+ dst->acceleration.status = (int32_t)src.payload.get<Event::EventPayload::vec3>().status;
+ break;
+ }
+
+ case SensorType::GAME_ROTATION_VECTOR: {
+ dst->data[0] = src.payload.get<Event::EventPayload::vec4>().x;
+ dst->data[1] = src.payload.get<Event::EventPayload::vec4>().y;
+ dst->data[2] = src.payload.get<Event::EventPayload::vec4>().z;
+ dst->data[3] = src.payload.get<Event::EventPayload::vec4>().w;
+ break;
+ }
+
+ case SensorType::ROTATION_VECTOR:
+ case SensorType::GEOMAGNETIC_ROTATION_VECTOR: {
+ dst->data[0] = src.payload.get<Event::EventPayload::data>().values[0];
+ dst->data[1] = src.payload.get<Event::EventPayload::data>().values[1];
+ dst->data[2] = src.payload.get<Event::EventPayload::data>().values[2];
+ dst->data[3] = src.payload.get<Event::EventPayload::data>().values[3];
+ dst->data[4] = src.payload.get<Event::EventPayload::data>().values[4];
+ break;
+ }
+
+ case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
+ case SensorType::GYROSCOPE_UNCALIBRATED:
+ case SensorType::ACCELEROMETER_UNCALIBRATED: {
+ dst->uncalibrated_gyro.x_uncalib = src.payload.get<Event::EventPayload::uncal>().x;
+ dst->uncalibrated_gyro.y_uncalib = src.payload.get<Event::EventPayload::uncal>().y;
+ dst->uncalibrated_gyro.z_uncalib = src.payload.get<Event::EventPayload::uncal>().z;
+ dst->uncalibrated_gyro.x_bias = src.payload.get<Event::EventPayload::uncal>().xBias;
+ dst->uncalibrated_gyro.y_bias = src.payload.get<Event::EventPayload::uncal>().yBias;
+ dst->uncalibrated_gyro.z_bias = src.payload.get<Event::EventPayload::uncal>().zBias;
+ break;
+ }
+
+ case SensorType::HINGE_ANGLE:
+ case SensorType::DEVICE_ORIENTATION:
+ case SensorType::LIGHT:
+ case SensorType::PRESSURE:
+ case SensorType::PROXIMITY:
+ case SensorType::RELATIVE_HUMIDITY:
+ case SensorType::AMBIENT_TEMPERATURE:
+ case SensorType::SIGNIFICANT_MOTION:
+ case SensorType::STEP_DETECTOR:
+ case SensorType::TILT_DETECTOR:
+ case SensorType::WAKE_GESTURE:
+ case SensorType::GLANCE_GESTURE:
+ case SensorType::PICK_UP_GESTURE:
+ case SensorType::WRIST_TILT_GESTURE:
+ case SensorType::STATIONARY_DETECT:
+ case SensorType::MOTION_DETECT:
+ case SensorType::HEART_BEAT:
+ case SensorType::LOW_LATENCY_OFFBODY_DETECT: {
+ dst->data[0] = src.payload.get<Event::EventPayload::scalar>();
+ break;
+ }
+
+ case SensorType::STEP_COUNTER: {
+ dst->u64.step_counter = src.payload.get<Event::EventPayload::stepCount>();
+ break;
+ }
+
+ case SensorType::HEART_RATE: {
+ dst->heart_rate.bpm = src.payload.get<Event::EventPayload::heartRate>().bpm;
+ dst->heart_rate.status =
+ (int8_t)src.payload.get<Event::EventPayload::heartRate>().status;
+ break;
+ }
+
+ case SensorType::POSE_6DOF: { // 15 floats
+ for (size_t i = 0; i < 15; ++i) {
+ dst->data[i] = src.payload.get<Event::EventPayload::pose6DOF>().values[i];
+ }
+ break;
+ }
+
+ case SensorType::DYNAMIC_SENSOR_META: {
+ dst->dynamic_sensor_meta.connected =
+ src.payload.get<Event::EventPayload::dynamic>().connected;
+ dst->dynamic_sensor_meta.handle =
+ src.payload.get<Event::EventPayload::dynamic>().sensorHandle;
+ dst->dynamic_sensor_meta.sensor = NULL; // to be filled in later
+
+ memcpy(dst->dynamic_sensor_meta.uuid,
+ src.payload.get<Event::EventPayload::dynamic>().uuid.values.data(), 16);
+
+ break;
+ }
+
+ case SensorType::ADDITIONAL_INFO: {
+ const AdditionalInfo &srcInfo = src.payload.get<Event::EventPayload::additional>();
+
+ additional_info_event_t *dstInfo = &dst->additional_info;
+ dstInfo->type = (int32_t)srcInfo.type;
+ dstInfo->serial = srcInfo.serial;
+
+ 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;
+ }
+
+ default: {
+ CHECK_GE((int32_t)src.sensorType, (int32_t)SensorType::DEVICE_PRIVATE_BASE);
+
+ memcpy(dst->data, src.payload.get<Event::EventPayload::data>().values.data(),
+ 16 * sizeof(float));
+ break;
+ }
+ }
+}
+
+void convertFromSensorEvent(const sensors_event_t &src, Event *dst) {
+ *dst = {
+ .timestamp = src.timestamp,
+ .sensorHandle = src.sensor,
+ .sensorType = (SensorType) src.type,
+ };
+
+ switch (dst->sensorType) {
+ case SensorType::META_DATA: {
+ Event::EventPayload::MetaData meta;
+ meta.what = (Event::EventPayload::MetaData::MetaDataEventType)src.meta_data.what;
+ // Legacy HALs contain the handle reference in the meta data field.
+ // Copy that over to the handle of the event. In legacy HALs this
+ // field was expected to be 0.
+ dst->sensorHandle = src.meta_data.sensor;
+ dst->payload.set<Event::EventPayload::Tag::meta>(meta);
+ break;
+ }
+
+ case SensorType::ACCELEROMETER:
+ case SensorType::MAGNETIC_FIELD:
+ case SensorType::ORIENTATION:
+ case SensorType::GYROSCOPE:
+ case SensorType::GRAVITY:
+ case SensorType::LINEAR_ACCELERATION: {
+ Event::EventPayload::Vec3 vec3;
+ vec3.x = src.acceleration.x;
+ vec3.y = src.acceleration.y;
+ vec3.z = src.acceleration.z;
+ vec3.status = (SensorStatus)src.acceleration.status;
+ dst->payload.set<Event::EventPayload::Tag::vec3>(vec3);
+ break;
+ }
+
+ case SensorType::GAME_ROTATION_VECTOR: {
+ Event::EventPayload::Vec4 vec4;
+ vec4.x = src.data[0];
+ vec4.y = src.data[1];
+ vec4.z = src.data[2];
+ vec4.w = src.data[3];
+ dst->payload.set<Event::EventPayload::Tag::vec4>(vec4);
+ break;
+ }
+
+ case SensorType::ROTATION_VECTOR:
+ case SensorType::GEOMAGNETIC_ROTATION_VECTOR: {
+ Event::EventPayload::Data data;
+ memcpy(data.values.data(), src.data, 5 * sizeof(float));
+ dst->payload.set<Event::EventPayload::Tag::data>(data);
+ break;
+ }
+
+ case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
+ case SensorType::GYROSCOPE_UNCALIBRATED:
+ case SensorType::ACCELEROMETER_UNCALIBRATED: {
+ Event::EventPayload::Uncal uncal;
+ uncal.x = src.uncalibrated_gyro.x_uncalib;
+ uncal.y = src.uncalibrated_gyro.y_uncalib;
+ uncal.z = src.uncalibrated_gyro.z_uncalib;
+ uncal.xBias = src.uncalibrated_gyro.x_bias;
+ uncal.yBias = src.uncalibrated_gyro.y_bias;
+ uncal.zBias = src.uncalibrated_gyro.z_bias;
+ dst->payload.set<Event::EventPayload::Tag::uncal>(uncal);
+ break;
+ }
+
+ case SensorType::DEVICE_ORIENTATION:
+ case SensorType::LIGHT:
+ case SensorType::PRESSURE:
+ case SensorType::PROXIMITY:
+ case SensorType::RELATIVE_HUMIDITY:
+ case SensorType::AMBIENT_TEMPERATURE:
+ case SensorType::SIGNIFICANT_MOTION:
+ case SensorType::STEP_DETECTOR:
+ case SensorType::TILT_DETECTOR:
+ case SensorType::WAKE_GESTURE:
+ case SensorType::GLANCE_GESTURE:
+ case SensorType::PICK_UP_GESTURE:
+ case SensorType::WRIST_TILT_GESTURE:
+ case SensorType::STATIONARY_DETECT:
+ case SensorType::MOTION_DETECT:
+ case SensorType::HEART_BEAT:
+ case SensorType::LOW_LATENCY_OFFBODY_DETECT:
+ case SensorType::HINGE_ANGLE: {
+ dst->payload.set<Event::EventPayload::Tag::scalar>((float)src.data[0]);
+ break;
+ }
+
+ case SensorType::STEP_COUNTER: {
+ dst->payload.set<Event::EventPayload::Tag::stepCount>(src.u64.step_counter);
+ break;
+ }
+
+ case SensorType::HEART_RATE: {
+ Event::EventPayload::HeartRate heartRate;
+ heartRate.bpm = src.heart_rate.bpm;
+ heartRate.status = (SensorStatus)src.heart_rate.status;
+ dst->payload.set<Event::EventPayload::Tag::heartRate>(heartRate);
+ break;
+ }
+
+ case SensorType::POSE_6DOF: { // 15 floats
+ Event::EventPayload::Pose6Dof pose6DOF;
+ for (size_t i = 0; i < 15; ++i) {
+ pose6DOF.values[i] = src.data[i];
+ }
+ dst->payload.set<Event::EventPayload::Tag::pose6DOF>(pose6DOF);
+ break;
+ }
+
+ case SensorType::DYNAMIC_SENSOR_META: {
+ DynamicSensorInfo dynamic;
+ dynamic.connected = src.dynamic_sensor_meta.connected;
+ dynamic.sensorHandle = src.dynamic_sensor_meta.handle;
+
+ memcpy(dynamic.uuid.values.data(), src.dynamic_sensor_meta.uuid, 16);
+ dst->payload.set<Event::EventPayload::Tag::dynamic>(dynamic);
+ break;
+ }
+
+ case SensorType::ADDITIONAL_INFO: {
+ AdditionalInfo info;
+ const additional_info_event_t &srcInfo = src.additional_info;
+ info.type = (AdditionalInfo::AdditionalInfoType)srcInfo.type;
+ info.serial = srcInfo.serial;
+
+ 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;
+ }
+
+ default: {
+ CHECK_GE((int32_t)dst->sensorType, (int32_t)SensorType::DEVICE_PRIVATE_BASE);
+
+ Event::EventPayload::Data data;
+ memcpy(data.values.data(), src.data, 16 * sizeof(float));
+ dst->payload.set<Event::EventPayload::Tag::data>(data);
+ break;
+ }
+ }
+}
+
+void serviceDied(void *cookie) {
+ ALOGW("Sensors HAL died, attempting to reconnect.");
+ ((AidlSensorHalWrapper *)cookie)->prepareForReconnect();
+}
+
+template <typename EnumType>
+constexpr typename std::underlying_type<EnumType>::type asBaseType(EnumType value) {
+ return static_cast<typename std::underlying_type<EnumType>::type>(value);
+}
+
+enum EventQueueFlagBitsInternal : uint32_t {
+ INTERNAL_WAKE = 1 << 16,
+};
+
+} // anonymous namespace
+
+class AidlSensorsCallback : public ::aidl::android::hardware::sensors::BnSensorsCallback {
+public:
+ AidlSensorsCallback(AidlSensorHalWrapper::SensorDeviceCallback *sensorDeviceCallback)
+ : mSensorDeviceCallback(sensorDeviceCallback) {}
+
+ ::ndk::ScopedAStatus onDynamicSensorsConnected(
+ const std::vector<SensorInfo> &sensorInfos) override {
+ std::vector<sensor_t> sensors;
+ for (const SensorInfo &sensorInfo : sensorInfos) {
+ sensor_t sensor;
+ convertToSensor(sensorInfo, &sensor);
+ sensors.push_back(sensor);
+ }
+
+ mSensorDeviceCallback->onDynamicSensorsConnected(sensors);
+ return ::ndk::ScopedAStatus::ok();
+ }
+
+ ::ndk::ScopedAStatus onDynamicSensorsDisconnected(
+ const std::vector<int32_t> &sensorHandles) override {
+ mSensorDeviceCallback->onDynamicSensorsDisconnected(sensorHandles);
+ return ::ndk::ScopedAStatus::ok();
+ }
+
+private:
+ ISensorHalWrapper::SensorDeviceCallback *mSensorDeviceCallback;
+};
+
+AidlSensorHalWrapper::AidlSensorHalWrapper()
+ : mEventQueueFlag(nullptr),
+ mWakeLockQueueFlag(nullptr),
+ mDeathRecipient(AIBinder_DeathRecipient_new(serviceDied)) {}
+
+bool AidlSensorHalWrapper::supportsPolling() {
+ return false;
+}
+
+bool AidlSensorHalWrapper::supportsMessageQueues() {
+ return true;
+}
+
+bool AidlSensorHalWrapper::connect(SensorDeviceCallback *callback) {
+ mSensorDeviceCallback = callback;
+ mSensors = nullptr;
+
+ auto aidlServiceName = std::string() + ISensors::descriptor + "/default";
+ if (AServiceManager_isDeclared(aidlServiceName.c_str())) {
+ if (mSensors != nullptr) {
+ AIBinder_unlinkToDeath(mSensors->asBinder().get(), mDeathRecipient.get(), this);
+ }
+
+ 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,
+ /*configureEventFlagWord=*/true);
+
+ mWakeLockQueue = std::make_unique<AidlMessageQueue<
+ int32_t, SynchronizedReadWrite>>(MAX_RECEIVE_BUFFER_EVENT_COUNT,
+ /*configureEventFlagWord=*/true);
+ if (mEventQueueFlag != nullptr) {
+ EventFlag::deleteEventFlag(&mEventQueueFlag);
+ }
+ EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag);
+ if (mWakeLockQueueFlag != nullptr) {
+ EventFlag::deleteEventFlag(&mWakeLockQueueFlag);
+ }
+ EventFlag::createEventFlag(mWakeLockQueue->getEventFlagWord(), &mWakeLockQueueFlag);
+
+ CHECK(mEventQueue != nullptr && mEventQueueFlag != nullptr &&
+ mWakeLockQueue != nullptr && mWakeLockQueueFlag != nullptr);
+
+ mCallback = ndk::SharedRefBase::make<AidlSensorsCallback>(mSensorDeviceCallback);
+ mSensors->initialize(mEventQueue->dupeDesc(), mWakeLockQueue->dupeDesc(), mCallback);
+
+ AIBinder_linkToDeath(mSensors->asBinder().get(), mDeathRecipient.get(), this);
+ } else {
+ ALOGE("Could not connect to declared sensors AIDL HAL");
+ }
+ }
+
+ return mSensors != nullptr;
+}
+
+void AidlSensorHalWrapper::prepareForReconnect() {
+ mReconnecting = true;
+ if (mEventQueueFlag != nullptr) {
+ mEventQueueFlag->wake(asBaseType(INTERNAL_WAKE));
+ }
+}
+
+ssize_t AidlSensorHalWrapper::poll(sensors_event_t * /* buffer */, size_t /* count */) {
+ return 0;
+}
+
+ssize_t AidlSensorHalWrapper::pollFmq(sensors_event_t *buffer, size_t maxNumEventsToRead) {
+ ssize_t eventsRead = 0;
+ size_t availableEvents = mEventQueue->availableToRead();
+
+ if (availableEvents == 0) {
+ uint32_t eventFlagState = 0;
+
+ // Wait for events to become available. This is necessary so that the Event FMQ's read() is
+ // able to be called with the correct number of events to read. If the specified number of
+ // events is not available, then read() would return no events, possibly introducing
+ // additional latency in delivering events to applications.
+ if (mEventQueueFlag != nullptr) {
+ mEventQueueFlag->wait(asBaseType(ISensors::EVENT_QUEUE_FLAG_BITS_READ_AND_PROCESS) |
+ asBaseType(INTERNAL_WAKE),
+ &eventFlagState);
+ }
+ availableEvents = mEventQueue->availableToRead();
+
+ if ((eventFlagState & asBaseType(INTERNAL_WAKE)) && mReconnecting) {
+ ALOGD("Event FMQ internal wake, returning from poll with no events");
+ return DEAD_OBJECT;
+ }
+ }
+
+ size_t eventsToRead = std::min({availableEvents, maxNumEventsToRead, mEventBuffer.size()});
+ if (eventsToRead > 0) {
+ if (mEventQueue->read(mEventBuffer.data(), eventsToRead)) {
+ // Notify the Sensors HAL that sensor events have been read. This is required to support
+ // the use of writeBlocking by the Sensors HAL.
+ if (mEventQueueFlag != nullptr) {
+ mEventQueueFlag->wake(asBaseType(ISensors::EVENT_QUEUE_FLAG_BITS_EVENTS_READ));
+ }
+
+ for (size_t i = 0; i < eventsToRead; i++) {
+ convertToSensorEvent(mEventBuffer[i], &buffer[i]);
+ }
+ eventsRead = eventsToRead;
+ } else {
+ ALOGW("Failed to read %zu events, currently %zu events available", eventsToRead,
+ availableEvents);
+ }
+ }
+
+ return eventsRead;
+}
+
+std::vector<sensor_t> AidlSensorHalWrapper::getSensorsList() {
+ std::vector<sensor_t> sensorsFound;
+
+ if (mSensors != nullptr) {
+ std::vector<SensorInfo> list;
+ mSensors->getSensorsList(&list);
+ for (size_t i = 0; i < list.size(); i++) {
+ sensor_t sensor;
+ convertToSensor(list[i], &sensor);
+ sensorsFound.push_back(sensor);
+ }
+ }
+
+ return sensorsFound;
+}
+
+status_t AidlSensorHalWrapper::setOperationMode(SensorService::Mode mode) {
+ if (mSensors == nullptr) return NO_INIT;
+ return convertToStatus(mSensors->setOperationMode(static_cast<ISensors::OperationMode>(mode)));
+}
+
+status_t AidlSensorHalWrapper::activate(int32_t sensorHandle, bool enabled) {
+ if (mSensors == nullptr) return NO_INIT;
+ return convertToStatus(mSensors->activate(sensorHandle, enabled));
+}
+
+status_t AidlSensorHalWrapper::batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+ int64_t maxReportLatencyNs) {
+ if (mSensors == nullptr) return NO_INIT;
+ return convertToStatus(mSensors->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs));
+}
+
+status_t AidlSensorHalWrapper::flush(int32_t sensorHandle) {
+ if (mSensors == nullptr) return NO_INIT;
+ return convertToStatus(mSensors->flush(sensorHandle));
+}
+
+status_t AidlSensorHalWrapper::injectSensorData(const sensors_event_t *event) {
+ if (mSensors == nullptr) return NO_INIT;
+
+ Event ev;
+ convertFromSensorEvent(*event, &ev);
+ return convertToStatus(mSensors->injectSensorData(ev));
+}
+
+status_t AidlSensorHalWrapper::registerDirectChannel(const sensors_direct_mem_t *memory,
+ int32_t *channelHandle) {
+ if (mSensors == nullptr) return NO_INIT;
+
+ ISensors::SharedMemInfo::SharedMemType type;
+ switch (memory->type) {
+ case SENSOR_DIRECT_MEM_TYPE_ASHMEM:
+ type = ISensors::SharedMemInfo::SharedMemType::ASHMEM;
+ break;
+ case SENSOR_DIRECT_MEM_TYPE_GRALLOC:
+ type = ISensors::SharedMemInfo::SharedMemType::GRALLOC;
+ break;
+ default:
+ return BAD_VALUE;
+ }
+
+ if (memory->format != SENSOR_DIRECT_FMT_SENSORS_EVENT) {
+ return BAD_VALUE;
+ }
+ ISensors::SharedMemInfo::SharedMemFormat format =
+ ISensors::SharedMemInfo::SharedMemFormat::SENSORS_EVENT;
+
+ ISensors::SharedMemInfo mem = {
+ .type = type,
+ .format = format,
+ .size = static_cast<int32_t>(memory->size),
+ .memoryHandle = makeToAidl(memory->handle),
+ };
+
+ return convertToStatus(mSensors->registerDirectChannel(mem, channelHandle));
+}
+
+status_t AidlSensorHalWrapper::unregisterDirectChannel(int32_t channelHandle) {
+ if (mSensors == nullptr) return NO_INIT;
+ return convertToStatus(mSensors->unregisterDirectChannel(channelHandle));
+}
+
+status_t AidlSensorHalWrapper::configureDirectChannel(int32_t sensorHandle, int32_t channelHandle,
+ const struct sensors_direct_cfg_t *config) {
+ if (mSensors == nullptr) return NO_INIT;
+
+ ISensors::RateLevel rate;
+ switch (config->rate_level) {
+ case SENSOR_DIRECT_RATE_STOP:
+ rate = ISensors::RateLevel::STOP;
+ break;
+ case SENSOR_DIRECT_RATE_NORMAL:
+ rate = ISensors::RateLevel::NORMAL;
+ break;
+ case SENSOR_DIRECT_RATE_FAST:
+ rate = ISensors::RateLevel::FAST;
+ break;
+ case SENSOR_DIRECT_RATE_VERY_FAST:
+ rate = ISensors::RateLevel::VERY_FAST;
+ break;
+ default:
+ return BAD_VALUE;
+ }
+
+ int32_t token;
+ mSensors->configDirectReport(sensorHandle, channelHandle, rate, &token);
+ return token;
+}
+
+void AidlSensorHalWrapper::writeWakeLockHandled(uint32_t count) {
+ int signedCount = (int)count;
+ if (mWakeLockQueue->write(&signedCount)) {
+ mWakeLockQueueFlag->wake(asBaseType(ISensors::WAKE_LOCK_QUEUE_FLAG_BITS_DATA_WRITTEN));
+ } else {
+ ALOGW("Failed to write wake lock handled");
+ }
+}
+
+} // namespace android
diff --git a/services/sensorservice/AidlSensorHalWrapper.h b/services/sensorservice/AidlSensorHalWrapper.h
new file mode 100644
index 0000000..9f61993
--- /dev/null
+++ b/services/sensorservice/AidlSensorHalWrapper.h
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_AIDL_SENSOR_HAL_WRAPPER_H
+#define ANDROID_AIDL_SENSOR_HAL_WRAPPER_H
+
+#include "ISensorHalWrapper.h"
+
+#include <aidl/android/hardware/sensors/ISensors.h>
+#include <fmq/AidlMessageQueue.h>
+#include <sensor/SensorEventQueue.h>
+
+namespace android {
+
+class AidlSensorHalWrapper : public ISensorHalWrapper {
+public:
+ AidlSensorHalWrapper();
+
+ ~AidlSensorHalWrapper() override {
+ if (mEventQueueFlag != nullptr) {
+ ::android::hardware::EventFlag::deleteEventFlag(&mEventQueueFlag);
+ mEventQueueFlag = nullptr;
+ }
+ if (mWakeLockQueueFlag != nullptr) {
+ ::android::hardware::EventFlag::deleteEventFlag(&mWakeLockQueueFlag);
+ mWakeLockQueueFlag = nullptr;
+ }
+ }
+
+ virtual bool connect(SensorDeviceCallback *callback) override;
+
+ virtual void prepareForReconnect() override;
+
+ virtual bool supportsPolling() override;
+
+ virtual bool supportsMessageQueues() override;
+
+ virtual ssize_t poll(sensors_event_t *buffer, size_t count) override;
+
+ virtual ssize_t pollFmq(sensors_event_t *buffer, size_t count) override;
+
+ virtual std::vector<sensor_t> getSensorsList() override;
+
+ virtual status_t setOperationMode(SensorService::Mode mode) override;
+
+ virtual status_t activate(int32_t sensorHandle, bool enabled) override;
+
+ virtual status_t batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+ int64_t maxReportLatencyNs) override;
+
+ virtual status_t flush(int32_t sensorHandle) override;
+
+ virtual status_t injectSensorData(const sensors_event_t *event) override;
+
+ virtual status_t registerDirectChannel(const sensors_direct_mem_t *memory,
+ int32_t *channelHandle) override;
+
+ virtual status_t unregisterDirectChannel(int32_t channelHandle) override;
+
+ virtual status_t configureDirectChannel(int32_t sensorHandle, int32_t channelHandle,
+ const struct sensors_direct_cfg_t *config) override;
+
+ virtual void writeWakeLockHandled(uint32_t count) override;
+
+private:
+ std::shared_ptr<aidl::android::hardware::sensors::ISensors> mSensors;
+ std::shared_ptr<::aidl::android::hardware::sensors::ISensorsCallback> mCallback;
+ std::unique_ptr<::android::AidlMessageQueue<::aidl::android::hardware::sensors::Event,
+ SynchronizedReadWrite>>
+ mEventQueue;
+ std::unique_ptr<::android::AidlMessageQueue<int, SynchronizedReadWrite>> mWakeLockQueue;
+ ::android::hardware::EventFlag *mEventQueueFlag;
+ ::android::hardware::EventFlag *mWakeLockQueueFlag;
+ SensorDeviceCallback *mSensorDeviceCallback;
+ std::array<::aidl::android::hardware::sensors::Event,
+ ::android::SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT>
+ mEventBuffer;
+
+ ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+};
+
+} // namespace android
+
+#endif // ANDROID_AIDL_SENSOR_HAL_WRAPPER_H
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index f8d9dc2..d5b629d 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -11,6 +11,7 @@
name: "libsensorservice",
srcs: [
+ "AidlSensorHalWrapper.cpp",
"BatteryService.cpp",
"CorrectedGyroSensor.cpp",
"Fusion.cpp",
@@ -61,14 +62,19 @@
"libbase",
"libhidlbase",
"libfmq",
+ "libbinder_ndk",
"packagemanager_aidl-cpp",
"android.hardware.sensors@1.0",
"android.hardware.sensors@2.0",
"android.hardware.sensors@2.1",
+ "android.hardware.common-V2-ndk",
+ "android.hardware.common.fmq-V1-ndk",
],
static_libs: [
+ "libaidlcommonsupport",
"android.hardware.sensors@1.0-convert",
+ "android.hardware.sensors-V1-ndk",
],
generated_headers: ["framework-cppstream-protos"],
diff --git a/services/sensorservice/HidlSensorHalWrapper.cpp b/services/sensorservice/HidlSensorHalWrapper.cpp
index dbb3da1..4c64e59 100644
--- a/services/sensorservice/HidlSensorHalWrapper.cpp
+++ b/services/sensorservice/HidlSensorHalWrapper.cpp
@@ -76,11 +76,11 @@
mHidlSensorHalWrapper->prepareForReconnect();
}
-struct SensorsCallback : public ISensorsCallback {
+struct HidlSensorsCallback : public ISensorsCallback {
using Result = ::android::hardware::sensors::V1_0::Result;
using SensorInfo = ::android::hardware::sensors::V2_1::SensorInfo;
- SensorsCallback(ISensorHalWrapper::SensorDeviceCallback* sensorDeviceCallback) {
+ HidlSensorsCallback(ISensorHalWrapper::SensorDeviceCallback* sensorDeviceCallback) {
mSensorDeviceCallback = sensorDeviceCallback;
}
@@ -143,18 +143,19 @@
bool hidlTransportError = false;
do {
- auto ret = mSensors->poll(
- count, [&](auto result, const auto& events, const auto& dynamicSensorsAdded) {
- if (result == Result::OK) {
- convertToSensorEventsAndQuantize(convertToNewEvents(events),
- convertToNewSensorInfos(
- dynamicSensorsAdded),
- buffer);
- err = (ssize_t)events.size();
- } else {
- err = statusFromResult(result);
- }
- });
+ auto ret = mSensors->poll(count,
+ [&](auto result, const auto& events,
+ const auto& dynamicSensorsAdded) {
+ if (result == Result::OK) {
+ convertToSensorEvents(convertToNewEvents(events),
+ convertToNewSensorInfos(
+ dynamicSensorsAdded),
+ buffer);
+ err = (ssize_t)events.size();
+ } else {
+ err = statusFromResult(result);
+ }
+ });
if (ret.isOk()) {
hidlTransportError = false;
@@ -216,9 +217,6 @@
for (size_t i = 0; i < eventsToRead; i++) {
convertToSensorEvent(mEventBuffer[i], &buffer[i]);
- android::SensorDeviceUtils::quantizeSensorEventValues(&buffer[i],
- getResolutionForSensor(
- buffer[i].sensor));
}
eventsRead = eventsToRead;
} else {
@@ -482,7 +480,7 @@
CHECK(mSensors != nullptr && mWakeLockQueue != nullptr && mEventQueueFlag != nullptr &&
mWakeLockQueueFlag != nullptr);
- mCallback = new SensorsCallback(mSensorDeviceCallback);
+ mCallback = sp<HidlSensorsCallback>::make(mSensorDeviceCallback);
status_t status =
checkReturnAndGetStatus(mSensors->initialize(*mWakeLockQueue->getDesc(), mCallback));
@@ -500,63 +498,18 @@
void HidlSensorHalWrapper::convertToSensorEvent(const Event& src, sensors_event_t* dst) {
android::hardware::sensors::V2_1::implementation::convertToSensorEvent(src, dst);
-
- if (src.sensorType == android::hardware::sensors::V2_1::SensorType::DYNAMIC_SENSOR_META) {
- const hardware::sensors::V1_0::DynamicSensorInfo& dyn = src.u.dynamic;
-
- dst->dynamic_sensor_meta.connected = dyn.connected;
- dst->dynamic_sensor_meta.handle = dyn.sensorHandle;
- if (dyn.connected) {
- std::unique_lock<std::mutex> lock(mDynamicSensorsMutex);
- // Give MAX_DYN_SENSOR_WAIT_SEC for onDynamicSensorsConnected to be invoked since it
- // can be received out of order from this event due to a bug in the HIDL spec that
- // marks it as oneway.
- auto it = mConnectedDynamicSensors.find(dyn.sensorHandle);
- if (it == mConnectedDynamicSensors.end()) {
- mDynamicSensorsCv.wait_for(lock, MAX_DYN_SENSOR_WAIT, [&, dyn] {
- return mConnectedDynamicSensors.find(dyn.sensorHandle) !=
- mConnectedDynamicSensors.end();
- });
- it = mConnectedDynamicSensors.find(dyn.sensorHandle);
- CHECK(it != mConnectedDynamicSensors.end());
- }
-
- dst->dynamic_sensor_meta.sensor = &it->second;
-
- memcpy(dst->dynamic_sensor_meta.uuid, dyn.uuid.data(),
- sizeof(dst->dynamic_sensor_meta.uuid));
- }
- }
}
-void HidlSensorHalWrapper::convertToSensorEventsAndQuantize(
- const hidl_vec<Event>& src, const hidl_vec<SensorInfo>& dynamicSensorsAdded,
- sensors_event_t* dst) {
+void HidlSensorHalWrapper::convertToSensorEvents(const hidl_vec<Event>& src,
+ const hidl_vec<SensorInfo>& dynamicSensorsAdded,
+ sensors_event_t* dst) {
if (dynamicSensorsAdded.size() > 0 && mCallback != nullptr) {
mCallback->onDynamicSensorsConnected_2_1(dynamicSensorsAdded);
}
for (size_t i = 0; i < src.size(); ++i) {
- android::hardware::sensors::V2_1::implementation::convertToSensorEvent(src[i], &dst[i]);
- android::SensorDeviceUtils::quantizeSensorEventValues(&dst[i],
- getResolutionForSensor(
- dst[i].sensor));
+ convertToSensorEvent(src[i], &dst[i]);
}
}
-float HidlSensorHalWrapper::getResolutionForSensor(int sensorHandle) {
- for (size_t i = 0; i < mSensorList.size(); i++) {
- if (sensorHandle == mSensorList[i].handle) {
- return mSensorList[i].resolution;
- }
- }
-
- auto it = mConnectedDynamicSensors.find(sensorHandle);
- if (it != mConnectedDynamicSensors.end()) {
- return it->second.resolution;
- }
-
- return 0;
-}
-
} // namespace android
diff --git a/services/sensorservice/HidlSensorHalWrapper.h b/services/sensorservice/HidlSensorHalWrapper.h
index 030247f..71c3512 100644
--- a/services/sensorservice/HidlSensorHalWrapper.h
+++ b/services/sensorservice/HidlSensorHalWrapper.h
@@ -124,12 +124,6 @@
private:
sp<::android::hardware::sensors::V2_1::implementation::ISensorsWrapperBase> mSensors;
sp<::android::hardware::sensors::V2_1::ISensorsCallback> mCallback;
- std::vector<sensor_t> mSensorList;
- std::unordered_map<int32_t, sensor_t> mConnectedDynamicSensors;
-
- std::mutex mDynamicSensorsMutex;
- std::condition_variable mDynamicSensorsCv;
- static constexpr std::chrono::seconds MAX_DYN_SENSOR_WAIT{5};
// Keep track of any hidl transport failures
SensorServiceUtil::RingBuffer<HidlTransportErrorLog> mHidlTransportErrors;
@@ -153,9 +147,9 @@
void convertToSensorEvent(const Event& src, sensors_event_t* dst);
- void convertToSensorEventsAndQuantize(const hardware::hidl_vec<Event>& src,
- const hardware::hidl_vec<SensorInfo>& dynamicSensorsAdded,
- sensors_event_t* dst);
+ void convertToSensorEvents(const hardware::hidl_vec<Event>& src,
+ const hardware::hidl_vec<SensorInfo>& dynamicSensorsAdded,
+ sensors_event_t* dst);
bool connectHidlService();
@@ -167,8 +161,6 @@
typedef hardware::MessageQueue<uint32_t, hardware::kSynchronizedReadWrite> WakeLockQueue;
std::unique_ptr<WakeLockQueue> mWakeLockQueue;
- float getResolutionForSensor(int sensorHandle);
-
hardware::EventFlag* mEventQueueFlag;
hardware::EventFlag* mWakeLockQueueFlag;
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 84a1076..a0e30ac 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -20,10 +20,15 @@
#include "android/hardware/sensors/2.1/types.h"
#include "convertV2_1.h"
+#include "AidlSensorHalWrapper.h"
+#include "HidlSensorHalWrapper.h"
+
#include <android-base/logging.h>
#include <android/util/ProtoOutputStream.h>
#include <cutils/atomic.h>
#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
+#include <hardware/sensors-base.h>
+#include <hardware/sensors.h>
#include <sensors/convert.h>
#include <utils/Errors.h>
#include <utils/Singleton.h>
@@ -132,11 +137,18 @@
SensorDevice::~SensorDevice() {}
bool SensorDevice::connectHalService() {
+ std::unique_ptr<ISensorHalWrapper> aidl_wrapper = std::make_unique<AidlSensorHalWrapper>();
+ if (aidl_wrapper->connect(this)) {
+ mHalWrapper = std::move(aidl_wrapper);
+ return true;
+ }
+
std::unique_ptr<ISensorHalWrapper> hidl_wrapper = std::make_unique<HidlSensorHalWrapper>();
if (hidl_wrapper->connect(this)) {
mHalWrapper = std::move(hidl_wrapper);
return true;
}
+
// TODO: check aidl connection;
return false;
}
@@ -349,6 +361,35 @@
ALOGE("Must support polling or FMQ");
eventsRead = -1;
}
+
+ if (eventsRead > 0) {
+ for (ssize_t i = 0; i < eventsRead; i++) {
+ float resolution = getResolutionForSensor(buffer[i].sensor);
+ android::SensorDeviceUtils::quantizeSensorEventValues(&buffer[i], resolution);
+
+ if (buffer[i].type == SENSOR_TYPE_DYNAMIC_SENSOR_META) {
+ struct dynamic_sensor_meta_event& dyn = buffer[i].dynamic_sensor_meta;
+ if (dyn.connected) {
+ std::unique_lock<std::mutex> lock(mDynamicSensorsMutex);
+ // Give MAX_DYN_SENSOR_WAIT_SEC for onDynamicSensorsConnected to be invoked
+ // since it can be received out of order from this event due to a bug in the
+ // HIDL spec that marks it as oneway.
+ auto it = mConnectedDynamicSensors.find(dyn.handle);
+ if (it == mConnectedDynamicSensors.end()) {
+ mDynamicSensorsCv.wait_for(lock, MAX_DYN_SENSOR_WAIT, [&, dyn] {
+ return mConnectedDynamicSensors.find(dyn.handle) !=
+ mConnectedDynamicSensors.end();
+ });
+ it = mConnectedDynamicSensors.find(dyn.handle);
+ CHECK(it != mConnectedDynamicSensors.end());
+ }
+
+ dyn.sensor = &it->second;
+ }
+ }
+ }
+ }
+
return eventsRead;
}
@@ -572,6 +613,7 @@
}
status_t SensorDevice::flush(void* /*ident*/, int handle) {
+ if (mHalWrapper == nullptr) return NO_INIT;
return mHalWrapper->flush(handle);
}
@@ -711,6 +753,7 @@
}
status_t SensorDevice::injectSensorData(const sensors_event_t* injected_sensor_event) {
+ if (mHalWrapper == nullptr) return NO_INIT;
return mHalWrapper->injectSensorData(injected_sensor_event);
}
@@ -720,6 +763,7 @@
}
int32_t SensorDevice::registerDirectChannel(const sensors_direct_mem_t* memory) {
+ if (mHalWrapper == nullptr) return NO_INIT;
Mutex::Autolock _l(mLock);
return mHalWrapper->registerDirectChannel(memory, nullptr);
@@ -731,6 +775,7 @@
int32_t SensorDevice::configureDirectChannel(int32_t sensorHandle, int32_t channelHandle,
const struct sensors_direct_cfg_t* config) {
+ if (mHalWrapper == nullptr) return NO_INIT;
Mutex::Autolock _l(mLock);
return mHalWrapper->configureDirectChannel(sensorHandle, channelHandle, config);
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 80e77d9..747a6b0 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -119,6 +119,7 @@
// HAL implementations.
std::mutex mDynamicSensorsMutex;
std::condition_variable mDynamicSensorsCv;
+ static constexpr std::chrono::seconds MAX_DYN_SENSOR_WAIT{5};
static const nsecs_t MINIMUM_EVENTS_PERIOD = 1000000; // 1000 Hz
mutable Mutex mLock; // protect mActivationCount[].batchParams
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 5560ed7..3e6d49f 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,
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/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 715d9fd..22479d8 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -583,6 +583,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 {
@@ -673,15 +688,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);
}
@@ -869,16 +876,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);
}
diff --git a/services/surfaceflinger/DisplayHardware/Hal.h b/services/surfaceflinger/DisplayHardware/Hal.h
index e33dc0f..ee06e03 100644
--- a/services/surfaceflinger/DisplayHardware/Hal.h
+++ b/services/surfaceflinger/DisplayHardware/Hal.h
@@ -136,6 +136,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/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 5c2390e..930ddea 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,11 +294,10 @@
mHasDisplayUpdateImminent = false;
}
- // This just gives a number not a binder status, so no .isOk()
- mSupportsPowerHints = mPowerHal->getInterfaceVersion() >= 2;
+ mSupportsPowerHint = checkPowerHintSessionSupported();
- if (mSupportsPowerHints) {
- mPowerHintQueue.reserve(MAX_QUEUE_SIZE);
+ if (mSupportsPowerHint) {
+ mPowerHintQueue.reserve(kMaxQueueSize);
}
}
@@ -356,7 +342,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 +375,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()) {
@@ -426,23 +424,27 @@
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) {
+ if (!mLastActualDurationSent.has_value() || mPowerHintQueue.size() >= kMaxQueueSize) {
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 +452,31 @@
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");
auto ret = mPowerHintSession->reportActualWorkDuration(mPowerHintQueue);
if (!ret.isOk()) {
ALOGW("Failed to report actual work durations with error: %s",
@@ -464,7 +484,8 @@
mShouldReconnectHal = true;
}
mPowerHintQueue.clear();
- mLastMessageReported = duration;
+ // we save the non-normalized value here to detect % changes
+ mLastActualDurationSent = actualDurationNanos;
}
}
@@ -472,32 +493,48 @@
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;
+ 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;
+ int64_t mLastTargetDurationSent = kDefaultTarget;
+ // 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 number of messages allowed in mPowerHintQueue before reporting is forced
+ static constexpr int32_t kMaxQueueSize = 15;
+ // 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 int64_t kDefaultTarget = 50000000;
};
+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/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ad9bede..63fbe78 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -717,7 +717,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();
@@ -747,7 +746,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)) {
@@ -1772,6 +1782,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(
@@ -1946,6 +1973,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.
@@ -1959,6 +1993,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;
@@ -2021,7 +2059,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) {
@@ -2086,10 +2127,9 @@
{
Mutex::Autolock _l(mStateLock);
mScheduler->chooseRefreshRateForContent();
+ setActiveModeInHwcIfNeeded();
}
- ON_MAIN_THREAD(setActiveModeInHwcIfNeeded());
-
updateCursorAsync();
updateInputFlinger();
@@ -2100,6 +2140,10 @@
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);
@@ -2153,6 +2197,11 @@
const auto presentTime = systemTime();
mCompositionEngine->present(refreshArgs);
+
+ if (mPowerHintSessionData.sessionEnabled) {
+ mPowerHintSessionData.presentEnd = systemTime();
+ }
+
mTimeStats->recordFrameDuration(frameTime, systemTime());
mScheduler->onPostComposition(presentTime);
@@ -2200,6 +2249,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() {
@@ -3157,41 +3213,61 @@
void SurfaceFlinger::buildWindowInfos(std::vector<WindowInfo>& outWindowInfos,
std::vector<DisplayInfo>& outDisplayInfos) {
- std::unordered_map<uint32_t /*layerStackId*/,
- std::pair<bool /* isSecure */, const ui::Transform>>
- inputDisplayDetails;
+ struct Details {
+ Details(bool receivesInput, bool isSecure, const ui::Transform& transform,
+ const DisplayInfo& info)
+ : receivesInput(receivesInput),
+ isSecure(isSecure),
+ transform(std::move(transform)),
+ info(std::move(info)) {}
+ bool receivesInput;
+ bool isSecure;
+ ui::Transform transform;
+ DisplayInfo info;
+ };
+ std::unordered_map<uint32_t /*layerStackId*/, Details> inputDisplayDetails;
for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
- if (!display->receivesInput()) {
- continue;
- }
const uint32_t layerStackId = display->getLayerStack().id;
const auto& [info, transform] = display->getInputInfo();
const auto& [it, emplaced] =
- inputDisplayDetails.try_emplace(layerStackId, display->isSecure(), transform);
- if (!emplaced) {
- ALOGE("Multiple displays claim to accept input for the same layer stack: %u",
- layerStackId);
+ inputDisplayDetails.try_emplace(layerStackId, display->receivesInput(),
+ display->isSecure(), transform, info);
+ if (emplaced) {
continue;
}
- outDisplayInfos.emplace_back(info);
+
+ // There is more than one display for the layerStack. In this case, the display that is
+ // configured to receive input takes precedence.
+ auto& details = it->second;
+ if (!display->receivesInput()) {
+ continue;
+ }
+ ALOGE_IF(details.receivesInput,
+ "Multiple displays claim to accept input for the same layer stack: %u",
+ layerStackId);
+ details.receivesInput = display->receivesInput();
+ details.isSecure = display->isSecure();
+ details.transform = std::move(transform);
+ details.info = std::move(info);
}
mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
if (!layer->needsInputInfo()) return;
- bool isSecure = true;
- ui::Transform displayTransform = ui::Transform();
-
const uint32_t layerStackId = layer->getLayerStack().id;
const auto it = inputDisplayDetails.find(layerStackId);
- if (it != inputDisplayDetails.end()) {
- const auto& [secure, transform] = it->second;
- isSecure = secure;
- displayTransform = transform;
+ if (it == inputDisplayDetails.end()) {
+ // Do not create WindowInfos for windows on displays that cannot receive input.
+ return;
}
- outWindowInfos.push_back(layer->fillInputInfo(displayTransform, isSecure));
+ const auto& details = it->second;
+ outWindowInfos.push_back(layer->fillInputInfo(details.transform, details.isSecure));
});
+
+ for (const auto& [_, details] : inputDisplayDetails) {
+ outDisplayInfos.push_back(std::move(details.info));
+ }
}
void SurfaceFlinger::updateCursorAsync() {
@@ -5393,6 +5469,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:
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index d9147bb..61cfb4e 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -590,6 +590,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;
@@ -1357,6 +1359,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/fuzzer/Android.bp b/services/surfaceflinger/fuzzer/Android.bp
new file mode 100644
index 0000000..0ead163
--- /dev/null
+++ b/services/surfaceflinger/fuzzer/Android.bp
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ *
+ */
+
+cc_defaults {
+ name: "surfaceflinger_fuzz_defaults",
+ include_dirs: [
+ "frameworks/native/services/surfaceflinger/tests/unittests",
+ ],
+ static_libs: [
+ "android.hardware.graphics.composer@2.1-resources",
+ "libgmock",
+ "libgui_mocks",
+ "libgmock_ndk",
+ "libgmock_main",
+ "libgtest_ndk_c++",
+ "libgmock_main_ndk",
+ "librenderengine_mocks",
+ "perfetto_trace_protos",
+ "libcompositionengine_mocks",
+ "perfetto_trace_protos",
+ ],
+ shared_libs: [
+ "libprotoutil",
+ "libstatssocket",
+ "libstatspull",
+ "libtimestats",
+ "libtimestats_proto",
+ "libprotobuf-cpp-full",
+ "android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
+ ],
+ srcs: [
+ ":libsurfaceflinger_sources",
+ ":libsurfaceflinger_mock_sources",
+ ],
+ defaults: [
+ "libsurfaceflinger_defaults",
+ ],
+ header_libs: [
+ "libui_fuzzableDataspaces_headers",
+ "libsurfaceflinger_headers",
+ "libui_headers",
+ ],
+ cflags: [
+ "-Wno-unused-result",
+ "-Wno-conversion",
+ "-Wno-sign-compare",
+ ],
+ fuzz_config: {
+ cc: [
+ "android-media-fuzzing-reports@google.com",
+ ],
+ componentid: 155276,
+ },
+}
+
+cc_fuzz {
+ name: "surfaceflinger_fuzzer",
+ defaults: [
+ "surfaceflinger_fuzz_defaults",
+ ],
+ srcs: [
+ "surfaceflinger_fuzzer.cpp",
+ ],
+}
+
+cc_fuzz {
+ name: "surfaceflinger_displayhardware_fuzzer",
+ defaults: [
+ "surfaceflinger_fuzz_defaults",
+ ],
+ srcs: [
+ "surfaceflinger_displayhardware_fuzzer.cpp",
+ ],
+ header_libs: [
+ "android.hardware.graphics.composer@2.4-command-buffer",
+ "android.hardware.graphics.composer@2.4-hal",
+ ],
+}
diff --git a/services/surfaceflinger/fuzzer/README.md b/services/surfaceflinger/fuzzer/README.md
new file mode 100644
index 0000000..4ecf770
--- /dev/null
+++ b/services/surfaceflinger/fuzzer/README.md
@@ -0,0 +1,53 @@
+# Fuzzers for SurfaceFlinger
+## Table of contents
++ [SurfaceFlinger](#SurfaceFlinger)
++ [DisplayHardware](#DisplayHardware)
+
+# <a name="SurfaceFlinger"></a> Fuzzer for SurfaceFlinger
+
+SurfaceFlinger supports the following data sources:
+1. Pixel Formats (parameter name: `defaultCompositionPixelFormat`)
+2. Data Spaces (parameter name: `defaultCompositionDataspace`)
+3. Rotations (parameter name: `internalDisplayOrientation`)
+3. Surface composer tags (parameter name: `onTransact`)
+
+You can find the possible values in the fuzzer's source code.
+
+#### Steps to run
+1. Build the fuzzer
+```
+ $ mm -j$(nproc) surfaceflinger_fuzzer
+```
+2. To run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/surfaceflinger_fuzzer/surfaceflinger_fuzzer
+```
+
+# <a name="DisplayHardware"></a> Fuzzer for DisplayHardware
+
+DisplayHardware supports the following parameters:
+1. Hal Capability (parameter name: `hasCapability`)
+2. Hal BlendMode (parameter name: `setBlendMode`)
+3. Hal Composition (parameter name: `setCompositionType`)
+4. Hal Display Capability (parameter name: `hasDisplayCapability`)
+5. Composition Types (parameter name: `prepareFrame`)
+6. Color Modes (parameter name: `setActiveColorMode`)
+7. Render Intents (parameter name: `setActiveColorMode`)
+8. Power Modes (parameter name: `setPowerMode`)
+9. Content Types (parameter name: `setContentType`)
+10. Data Space (parameter name: `setDataspace`)
+11. Transforms (parameter name: `setLayerTransform`)
+
+You can find the possible values in the fuzzer's source code.
+
+#### Steps to run
+1. Build the fuzzer
+```
+ $ mm -j$(nproc) surfaceflinger_displayhardware_fuzzer
+```
+2. Run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/surfaceflinger_displayhardware_fuzzer/surfaceflinger_displayhardware_fuzzer
+```
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
new file mode 100644
index 0000000..a18a28a
--- /dev/null
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
@@ -0,0 +1,662 @@
+/*
+ * 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 <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <compositionengine/impl/OutputCompositionState.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <gui/BLASTBufferQueue.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/IProducerListener.h>
+#include <gui/LayerDebugInfo.h>
+#include <gui/SurfaceComposerClient.h>
+#include <hidl/ServiceManagement.h>
+#include <hwbinder/ProcessState.h>
+
+#include "DisplayHardware/AidlComposerHal.h"
+#include "DisplayHardware/DisplayIdentification.h"
+#include "DisplayHardware/DisplayMode.h"
+#include "DisplayHardware/FramebufferSurface.h"
+#include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware/Hash.h"
+#include "DisplayHardware/PowerAdvisor.h"
+#include "DisplayHardware/VirtualDisplaySurface.h"
+#include "SurfaceFlinger.h"
+#include "surfaceflinger_displayhardware_fuzzer_utils.h"
+
+#include <FuzzableDataspaces.h>
+
+namespace android::fuzz {
+
+using namespace android::hardware::graphics::common;
+using namespace android::hardware::graphics::composer;
+namespace hal = android::hardware::graphics::composer::hal;
+using Config = hal::V2_1::Config;
+using Display = hal::V2_1::Display;
+using RenderIntent = V1_1::RenderIntent;
+using IComposerClient = hal::V2_4::IComposerClient;
+using VsyncPeriodChangeTimeline = hal::V2_4::VsyncPeriodChangeTimeline;
+using PerFrameMetadata = IComposerClient::PerFrameMetadata;
+using PerFrameMetadataBlob = IComposerClient::PerFrameMetadataBlob;
+using Vsync = IComposerClient::Vsync;
+
+static constexpr hal::Transform kTransforms[] = {hal::Transform::FLIP_H, hal::Transform::FLIP_V,
+ hal::Transform::ROT_90, hal::Transform::ROT_180,
+ hal::Transform::ROT_270};
+
+static constexpr hal::Capability kCapability[] = {hal::Capability::INVALID,
+ hal::Capability::SIDEBAND_STREAM,
+ hal::Capability::SKIP_CLIENT_COLOR_TRANSFORM,
+ hal::Capability::PRESENT_FENCE_IS_NOT_RELIABLE};
+
+static constexpr hal::BlendMode kBlendModes[] = {hal::BlendMode::INVALID, hal::BlendMode::NONE,
+ hal::BlendMode::PREMULTIPLIED,
+ hal::BlendMode::COVERAGE};
+
+static constexpr Composition kCompositions[] = {Composition::INVALID, Composition::CLIENT,
+ Composition::DEVICE, Composition::SOLID_COLOR,
+ Composition::CURSOR, Composition::SIDEBAND};
+
+static constexpr DisplayCapability kDisplayCapability[] =
+ {DisplayCapability::INVALID,
+ DisplayCapability::SKIP_CLIENT_COLOR_TRANSFORM,
+ DisplayCapability::DOZE,
+ DisplayCapability::BRIGHTNESS,
+ DisplayCapability::PROTECTED_CONTENTS,
+ DisplayCapability::AUTO_LOW_LATENCY_MODE};
+
+static constexpr VirtualDisplaySurface::CompositionType kCompositionTypes[] =
+ {VirtualDisplaySurface::CompositionType::Unknown,
+ VirtualDisplaySurface::CompositionType::Gpu, VirtualDisplaySurface::CompositionType::Hwc,
+ VirtualDisplaySurface::CompositionType::Mixed};
+
+static constexpr ui::RenderIntent kRenderIntents[] = {ui::RenderIntent::COLORIMETRIC,
+ ui::RenderIntent::ENHANCE,
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC,
+ ui::RenderIntent::TONE_MAP_ENHANCE};
+
+static constexpr hal::PowerMode kPowerModes[] = {hal::PowerMode::OFF, hal::PowerMode::DOZE,
+ hal::PowerMode::DOZE_SUSPEND, hal::PowerMode::ON,
+ hal::PowerMode::ON_SUSPEND};
+
+static constexpr hal::ContentType kContentTypes[] = {hal::ContentType::NONE,
+ hal::ContentType::GRAPHICS,
+ hal::ContentType::PHOTO,
+ hal::ContentType::CINEMA,
+ hal::ContentType::GAME};
+
+const unsigned char kInternalEdid[] =
+ "\x00\xff\xff\xff\xff\xff\xff\x00\x4c\xa3\x42\x31\x00\x00\x00\x00"
+ "\x00\x15\x01\x03\x80\x1a\x10\x78\x0a\xd3\xe5\x95\x5c\x60\x90\x27"
+ "\x19\x50\x54\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
+ "\x01\x01\x01\x01\x01\x01\x9e\x1b\x00\xa0\x50\x20\x12\x30\x10\x30"
+ "\x13\x00\x05\xa3\x10\x00\x00\x19\x00\x00\x00\x0f\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x23\x87\x02\x64\x00\x00\x00\x00\xfe\x00\x53"
+ "\x41\x4d\x53\x55\x4e\x47\x0a\x20\x20\x20\x20\x20\x00\x00\x00\xfe"
+ "\x00\x31\x32\x31\x41\x54\x31\x31\x2d\x38\x30\x31\x0a\x20\x00\x45";
+
+static constexpr hal::HWConfigId kActiveConfig = 0;
+
+class DisplayHardwareFuzzer {
+public:
+ DisplayHardwareFuzzer(const uint8_t* data, size_t size) : mFdp(data, size) {
+ mPhysicalDisplayId = SurfaceComposerClient::getInternalDisplayId().value();
+ };
+ void process();
+
+private:
+ void invokeComposer();
+ void invokeDisplayIdentification();
+ void invokeLayer(HWC2::Layer* layer);
+ void setSidebandStream(HWC2::Layer* layer);
+ void setCursorPosition(HWC2::Layer* layer);
+ void setBuffer(HWC2::Layer* layer);
+ void setSurfaceDamage(HWC2::Layer* layer);
+ void setDisplayFrame(HWC2::Layer* layer);
+ void setVisibleRegion(HWC2::Layer* layer);
+ void setLayerGenericMetadata(HWC2::Layer* layer);
+ void invokeFrameBufferSurface();
+ void invokeVirtualDisplaySurface();
+ void invokeAidlComposer();
+ Display createVirtualDisplay(Hwc2::AidlComposer*);
+ void validateDisplay(Hwc2::AidlComposer*, Display);
+ void presentOrValidateDisplay(Hwc2::AidlComposer*, Display);
+ void setOutputBuffer(Hwc2::AidlComposer*, Display);
+ void setLayerSidebandStream(Hwc2::AidlComposer*, Display, Hwc2::V2_4::hal::Layer);
+ void invokeComposerHal2_2(Hwc2::AidlComposer*, Display, Hwc2::V2_4::hal::Layer);
+ void invokeComposerHal2_3(Hwc2::AidlComposer*, Display, Hwc2::V2_4::hal::Layer);
+ void invokeComposerHal2_4(Hwc2::AidlComposer*, Display, Hwc2::V2_4::hal::Layer);
+ void getDisplayVsyncPeriod();
+ void setActiveModeWithConstraints();
+ void getDisplayIdentificationData();
+ void dumpHwc();
+ void getDisplayedContentSamplingAttributes(HalDisplayId);
+ void getDeviceCompositionChanges(HalDisplayId);
+ void getHdrCapabilities(HalDisplayId);
+ void getDisplayedContentSample(HalDisplayId);
+ void getSupportedContentTypes();
+ ui::Size getFuzzedSize();
+ mat4 getFuzzedMatrix();
+
+ DisplayIdGenerator<HalVirtualDisplayId> mGenerator;
+ FuzzedDataProvider mFdp;
+ PhysicalDisplayId mPhysicalDisplayId;
+ android::impl::HWComposer mHwc{std::make_unique<Hwc2::mock::Composer>()};
+};
+
+void DisplayHardwareFuzzer::validateDisplay(Hwc2::AidlComposer* composer, Display display) {
+ uint32_t outNumTypes, outNumRequests;
+ composer->validateDisplay(display, mFdp.ConsumeIntegral<nsecs_t>(), &outNumTypes,
+ &outNumRequests);
+}
+
+void DisplayHardwareFuzzer::presentOrValidateDisplay(Hwc2::AidlComposer* composer,
+ Display display) {
+ int32_t outPresentFence;
+ uint32_t outNumTypes, outNumRequests, state;
+ composer->presentOrValidateDisplay(display, mFdp.ConsumeIntegral<nsecs_t>(), &outNumTypes,
+ &outNumRequests, &outPresentFence, &state);
+}
+
+void DisplayHardwareFuzzer::setOutputBuffer(Hwc2::AidlComposer* composer, Display display) {
+ const native_handle_t buffer{};
+ composer->setOutputBuffer(display, &buffer, mFdp.ConsumeIntegral<int32_t>() /*releaseFence*/);
+}
+
+void DisplayHardwareFuzzer::setLayerSidebandStream(Hwc2::AidlComposer* composer, Display display,
+ Hwc2::V2_4::hal::Layer outLayer) {
+ const native_handle_t stream{};
+ composer->setLayerSidebandStream(display, outLayer, &stream);
+}
+
+Display DisplayHardwareFuzzer::createVirtualDisplay(Hwc2::AidlComposer* composer) {
+ namespace types = hardware::graphics::common;
+ using types::V1_2::PixelFormat;
+ PixelFormat format{};
+ Display display;
+ composer->createVirtualDisplay(mFdp.ConsumeIntegral<uint32_t>() /*width*/,
+ mFdp.ConsumeIntegral<uint32_t>() /*height*/, &format, &display);
+ return display;
+}
+
+void DisplayHardwareFuzzer::getDisplayVsyncPeriod() {
+ nsecs_t outVsyncPeriod;
+ mHwc.getDisplayVsyncPeriod(mPhysicalDisplayId, &outVsyncPeriod);
+}
+
+void DisplayHardwareFuzzer::setActiveModeWithConstraints() {
+ hal::VsyncPeriodChangeTimeline outTimeline;
+ mHwc.setActiveModeWithConstraints(mPhysicalDisplayId, kActiveConfig, {} /*constraints*/,
+ &outTimeline);
+}
+
+void DisplayHardwareFuzzer::getDisplayIdentificationData() {
+ uint8_t outPort;
+ DisplayIdentificationData outData;
+ mHwc.getDisplayIdentificationData(kHwDisplayId, &outPort, &outData);
+}
+
+void DisplayHardwareFuzzer::dumpHwc() {
+ std::string string = mFdp.ConsumeRandomLengthString().c_str();
+ mHwc.dump(string);
+}
+
+void DisplayHardwareFuzzer::getDeviceCompositionChanges(HalDisplayId halDisplayID) {
+ std::optional<impl::HWComposer::DeviceRequestedChanges> outChanges;
+ mHwc.getDeviceCompositionChanges(halDisplayID,
+ mFdp.ConsumeBool() /*frameUsesClientComposition*/,
+ std::chrono::steady_clock::now(), FenceTime::NO_FENCE,
+ mFdp.ConsumeIntegral<nsecs_t>(), &outChanges);
+}
+
+void DisplayHardwareFuzzer::getDisplayedContentSamplingAttributes(HalDisplayId halDisplayID) {
+ uint8_t outComponentMask;
+ ui::Dataspace dataSpace;
+ ui::PixelFormat pixelFormat;
+ mHwc.getDisplayedContentSamplingAttributes(halDisplayID, &pixelFormat, &dataSpace,
+ &outComponentMask);
+}
+
+void DisplayHardwareFuzzer::getHdrCapabilities(HalDisplayId halDisplayID) {
+ HdrCapabilities outCapabilities;
+ mHwc.getHdrCapabilities(halDisplayID, &outCapabilities);
+}
+
+void DisplayHardwareFuzzer::getDisplayedContentSample(HalDisplayId halDisplayID) {
+ DisplayedFrameStats outStats;
+ mHwc.getDisplayedContentSample(halDisplayID, mFdp.ConsumeIntegral<uint64_t>() /* maxFrames*/,
+ mFdp.ConsumeIntegral<uint64_t>() /*timestamps*/, &outStats);
+}
+
+void DisplayHardwareFuzzer::getSupportedContentTypes() {
+ std::vector<hal::ContentType> contentType{};
+ mHwc.getSupportedContentTypes(mPhysicalDisplayId, &contentType);
+}
+
+void DisplayHardwareFuzzer::invokeAidlComposer() {
+ hardware::ProcessState::self()->startThreadPool();
+ ProcessState::self()->startThreadPool();
+
+ if (!Hwc2::AidlComposer::isDeclared("default")) {
+ return;
+ }
+
+ Hwc2::AidlComposer composer("default");
+
+ android::hardware::graphics::composer::hal::TestHWC2ComposerCallback composerCallback{};
+ composer.registerCallback(
+ sp<android::hardware::graphics::composer::hal::ComposerCallbackBridge>::
+ make(&composerCallback,
+ composer.isSupported(
+ Hwc2::Composer::OptionalFeature::RefreshRateSwitching)));
+
+ Display display = createVirtualDisplay(&composer);
+
+ composer.acceptDisplayChanges(display);
+
+ Hwc2::V2_4::hal::Layer outLayer;
+ composer.createLayer(display, &outLayer);
+
+ int32_t outPresentFence;
+ composer.presentDisplay(display, &outPresentFence);
+
+ composer.setActiveConfig(display, Config{});
+
+ composer.setClientTarget(display, mFdp.ConsumeIntegral<uint32_t>(), sp<GraphicBuffer>(),
+ mFdp.ConsumeIntegral<int32_t>(), mFdp.PickValueInArray(kDataspaces),
+ {});
+
+ composer.setColorMode(display, mFdp.PickValueInArray(kColormodes),
+ mFdp.PickValueInArray(kRenderIntents));
+
+ setOutputBuffer(&composer, display);
+
+ composer.setPowerMode(display, mFdp.PickValueInArray(kPowerModes));
+ composer.setVsyncEnabled(display, mFdp.ConsumeBool() ? Vsync::ENABLE : Vsync::DISABLE);
+
+ composer.setClientTargetSlotCount(display);
+
+ validateDisplay(&composer, display);
+
+ presentOrValidateDisplay(&composer, display);
+
+ composer.setCursorPosition(display, outLayer, mFdp.ConsumeIntegral<uint8_t>() /*x*/,
+ mFdp.ConsumeIntegral<uint8_t>() /*y*/);
+
+ composer.setLayerBuffer(display, outLayer, mFdp.ConsumeIntegral<uint32_t>() /*slot*/,
+ sp<GraphicBuffer>(), mFdp.ConsumeIntegral<int32_t>() /*acquireFence*/);
+
+ composer.setLayerSurfaceDamage(display, outLayer, {} /*damage*/);
+
+ composer.setLayerBlendMode(display, outLayer, mFdp.PickValueInArray(kBlendModes));
+
+ composer.setLayerColor(display, outLayer,
+ {mFdp.ConsumeIntegral<uint8_t>() /*red*/,
+ mFdp.ConsumeIntegral<uint8_t>() /*green*/,
+ mFdp.ConsumeIntegral<uint8_t>() /*blue*/,
+ mFdp.ConsumeIntegral<uint8_t>() /*alpha*/});
+ composer.setLayerCompositionType(display, outLayer, mFdp.PickValueInArray(kCompositions));
+ composer.setLayerDataspace(display, outLayer, mFdp.PickValueInArray(kDataspaces));
+ composer.setLayerDisplayFrame(display, outLayer, {} /*frame*/);
+ composer.setLayerPlaneAlpha(display, outLayer, mFdp.ConsumeFloatingPoint<float>());
+
+ setLayerSidebandStream(&composer, display, outLayer);
+
+ composer.setLayerSourceCrop(display, outLayer, {} /*crop*/);
+
+ composer.setLayerTransform(display, outLayer, mFdp.PickValueInArray(kTransforms));
+
+ composer.setLayerVisibleRegion(display, outLayer, std::vector<IComposerClient::Rect>{});
+ composer.setLayerZOrder(display, outLayer, mFdp.ConsumeIntegral<uint32_t>());
+
+ invokeComposerHal2_2(&composer, display, outLayer);
+ invokeComposerHal2_3(&composer, display, outLayer);
+ invokeComposerHal2_4(&composer, display, outLayer);
+
+ composer.executeCommands();
+ composer.resetCommands();
+
+ composer.destroyLayer(display, outLayer);
+ composer.destroyVirtualDisplay(display);
+}
+
+void DisplayHardwareFuzzer::invokeComposerHal2_2(Hwc2::AidlComposer* composer, Display display,
+ Hwc2::V2_4::hal::Layer outLayer) {
+ const std::vector<PerFrameMetadata> perFrameMetadatas;
+ composer->setLayerPerFrameMetadata(display, outLayer, perFrameMetadatas);
+
+ composer->getPerFrameMetadataKeys(display);
+ std::vector<RenderIntent> outRenderIntents;
+
+ composer->getRenderIntents(display, mFdp.PickValueInArray(kColormodes), &outRenderIntents);
+ mat4 outMatrix;
+ composer->getDataspaceSaturationMatrix(mFdp.PickValueInArray(kDataspaces), &outMatrix);
+}
+
+void DisplayHardwareFuzzer::invokeComposerHal2_3(Hwc2::AidlComposer* composer, Display display,
+ Hwc2::V2_4::hal::Layer outLayer) {
+ composer->setDisplayContentSamplingEnabled(display, mFdp.ConsumeBool() /*enabled*/,
+ mFdp.ConsumeIntegral<uint8_t>() /*componentMask*/,
+ mFdp.ConsumeIntegral<uint64_t>() /*maxFrames*/);
+
+ DisplayedFrameStats outStats;
+ composer->getDisplayedContentSample(display, mFdp.ConsumeIntegral<uint64_t>() /*maxFrames*/,
+ mFdp.ConsumeIntegral<uint64_t>() /*timestamp*/, &outStats);
+
+ composer->setLayerPerFrameMetadataBlobs(display, outLayer, std::vector<PerFrameMetadataBlob>{});
+
+ composer->setDisplayBrightness(display, mFdp.ConsumeFloatingPoint<float>());
+}
+
+void DisplayHardwareFuzzer::invokeComposerHal2_4(Hwc2::AidlComposer* composer, Display display,
+ Hwc2::V2_4::hal::Layer outLayer) {
+ VsyncPeriodChangeTimeline outTimeline;
+ composer->setActiveConfigWithConstraints(display, Config{},
+ IComposerClient::VsyncPeriodChangeConstraints{},
+ &outTimeline);
+
+ composer->setAutoLowLatencyMode(display, mFdp.ConsumeBool());
+
+ composer->setContentType(display, mFdp.PickValueInArray(kContentTypes));
+
+ std::vector<uint8_t> value;
+ value.push_back(mFdp.ConsumeIntegral<uint8_t>());
+ composer->setLayerGenericMetadata(display, outLayer, mFdp.ConsumeRandomLengthString() /*key*/,
+ mFdp.ConsumeBool() /*mandatory*/, value);
+}
+
+ui::Size DisplayHardwareFuzzer::getFuzzedSize() {
+ ui::Size size{mFdp.ConsumeIntegral<int32_t>() /*width*/,
+ mFdp.ConsumeIntegral<int32_t>() /*height*/};
+ return size;
+}
+
+mat4 DisplayHardwareFuzzer::getFuzzedMatrix() {
+ mat4 matrix{mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>(),
+ mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>(),
+ mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>(),
+ mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>(),
+ mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>(),
+ mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>(),
+ mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>(),
+ mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>()};
+ return matrix;
+}
+
+void DisplayHardwareFuzzer::setCursorPosition(HWC2::Layer* layer) {
+ layer->setCursorPosition(mFdp.ConsumeIntegral<int32_t>() /*x*/,
+ mFdp.ConsumeIntegral<int32_t>() /*y*/);
+}
+
+void DisplayHardwareFuzzer::setBuffer(HWC2::Layer* layer) {
+ layer->setBuffer(mFdp.ConsumeIntegral<uint32_t>() /*slot*/, sp<GraphicBuffer>(),
+ sp<Fence>::make());
+}
+
+void DisplayHardwareFuzzer::setSurfaceDamage(HWC2::Layer* layer) {
+ Rect rhs{mFdp.ConsumeIntegral<uint32_t>() /*width*/,
+ mFdp.ConsumeIntegral<uint32_t>() /*height*/};
+ const Region damage{rhs};
+ layer->setSurfaceDamage(damage);
+}
+
+void DisplayHardwareFuzzer::setVisibleRegion(HWC2::Layer* layer) {
+ uint32_t width = mFdp.ConsumeIntegral<uint32_t>();
+ uint32_t height = mFdp.ConsumeIntegral<uint32_t>();
+ Rect rect{width, height};
+ const Region region{rect};
+ layer->setVisibleRegion(region);
+}
+
+void DisplayHardwareFuzzer::setDisplayFrame(HWC2::Layer* layer) {
+ uint32_t width = mFdp.ConsumeIntegral<uint32_t>();
+ uint32_t height = mFdp.ConsumeIntegral<uint32_t>();
+ const Rect frame{width, height};
+ layer->setDisplayFrame(frame);
+}
+
+void DisplayHardwareFuzzer::setLayerGenericMetadata(HWC2::Layer* layer) {
+ std::vector<uint8_t> value;
+ value.push_back(mFdp.ConsumeIntegral<uint8_t>());
+ layer->setLayerGenericMetadata(mFdp.ConsumeRandomLengthString().c_str() /*name*/,
+ mFdp.ConsumeBool() /*mandatory*/, value);
+}
+
+void DisplayHardwareFuzzer::setSidebandStream(HWC2::Layer* layer) {
+ const native_handle_t stream{};
+ layer->setSidebandStream(&stream);
+}
+
+void DisplayHardwareFuzzer::invokeLayer(HWC2::Layer* layer) {
+ setCursorPosition(layer);
+ setBuffer(layer);
+ setSurfaceDamage(layer);
+
+ layer->setBlendMode(mFdp.PickValueInArray(kBlendModes));
+ layer->setColor(
+ {mFdp.ConsumeIntegral<uint8_t>() /*red*/, mFdp.ConsumeIntegral<uint8_t>() /*green*/,
+ mFdp.ConsumeIntegral<uint8_t>() /*blue*/, mFdp.ConsumeIntegral<uint8_t>() /*alpha*/});
+ layer->setCompositionType(mFdp.PickValueInArray(kCompositions));
+ layer->setDataspace(mFdp.PickValueInArray(kDataspaces));
+
+ layer->setPerFrameMetadata(mFdp.ConsumeIntegral<int32_t>(), getFuzzedHdrMetadata(&mFdp));
+ setDisplayFrame(layer);
+
+ layer->setPlaneAlpha(mFdp.ConsumeFloatingPoint<float>());
+
+ setSidebandStream(layer);
+
+ layer->setSourceCrop(getFuzzedFloatRect(&mFdp));
+ layer->setTransform(mFdp.PickValueInArray(kTransforms));
+
+ setVisibleRegion(layer);
+
+ layer->setZOrder(mFdp.ConsumeIntegral<uint32_t>());
+
+ layer->setColorTransform(getFuzzedMatrix());
+
+ setLayerGenericMetadata(layer);
+}
+
+void DisplayHardwareFuzzer::invokeFrameBufferSurface() {
+ sp<IGraphicBufferProducer> bqProducer = sp<mock::GraphicBufferProducer>::make();
+ sp<IGraphicBufferConsumer> bqConsumer;
+ BufferQueue::createBufferQueue(&bqProducer, &bqConsumer);
+
+ sp<FramebufferSurface> surface =
+ new FramebufferSurface(mHwc, mPhysicalDisplayId, bqConsumer, getFuzzedSize() /*size*/,
+ getFuzzedSize() /*maxSize*/);
+ surface->beginFrame(mFdp.ConsumeBool());
+
+ surface->prepareFrame(mFdp.PickValueInArray(kCompositionTypes));
+ surface->advanceFrame();
+ surface->onFrameCommitted();
+ String8 result = String8(mFdp.ConsumeRandomLengthString().c_str());
+ surface->dumpAsString(result);
+ surface->resizeBuffers(getFuzzedSize());
+ surface->getClientTargetAcquireFence();
+}
+
+void DisplayHardwareFuzzer::invokeVirtualDisplaySurface() {
+ DisplayIdGenerator<HalVirtualDisplayId> mGenerator;
+ VirtualDisplayId VirtualDisplayId = mGenerator.generateId().value();
+
+ sp<SurfaceComposerClient> mClient = new SurfaceComposerClient();
+ sp<SurfaceControl> mSurfaceControl =
+ mClient->createSurface(String8("TestSurface"), 100, 100, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceBufferState,
+ /*parent*/ nullptr);
+
+ sp<BLASTBufferQueue> mBlastBufferQueueAdapter =
+ new BLASTBufferQueue("TestBLASTBufferQueue", mSurfaceControl, 100, 100,
+ PIXEL_FORMAT_RGBA_8888);
+
+ sp<IGraphicBufferProducer> sink = mBlastBufferQueueAdapter->getIGraphicBufferProducer();
+ sp<IGraphicBufferProducer> bqProducer = mBlastBufferQueueAdapter->getIGraphicBufferProducer();
+ sp<IGraphicBufferConsumer> bqConsumer;
+ BufferQueue::createBufferQueue(&bqProducer, &bqConsumer);
+ BufferQueue::createBufferQueue(&sink, &bqConsumer);
+
+ sp<VirtualDisplaySurface> surface =
+ new VirtualDisplaySurface(mHwc, VirtualDisplayId, sink, bqProducer, bqConsumer,
+ mFdp.ConsumeRandomLengthString().c_str() /*name*/);
+
+ surface->beginFrame(mFdp.ConsumeBool());
+ surface->prepareFrame(mFdp.PickValueInArray(kCompositionTypes));
+ surface->resizeBuffers(getFuzzedSize());
+ surface->getClientTargetAcquireFence();
+ surface->advanceFrame();
+ surface->onFrameCommitted();
+ String8 result = String8(mFdp.ConsumeRandomLengthString().c_str());
+ surface->dumpAsString(result);
+}
+
+void DisplayHardwareFuzzer::invokeComposer() {
+ HalVirtualDisplayId halVirtualDisplayId = mGenerator.generateId().value();
+ HalDisplayId halDisplayID = HalDisplayId{halVirtualDisplayId};
+
+ android::hardware::graphics::composer::hal::TestHWC2ComposerCallback composerCallback{};
+ mHwc.setCallback(&composerCallback);
+
+ ui::PixelFormat pixelFormat{};
+ if (!mHwc.allocateVirtualDisplay(halVirtualDisplayId, getFuzzedSize(), &pixelFormat)) {
+ return;
+ }
+
+ getDisplayIdentificationData();
+
+ mHwc.hasDisplayCapability(halDisplayID, mFdp.PickValueInArray(kDisplayCapability));
+
+ mHwc.allocatePhysicalDisplay(kHwDisplayId, mPhysicalDisplayId);
+
+ static auto hwcLayer = mHwc.createLayer(halDisplayID);
+ HWC2::Layer* layer = hwcLayer.get();
+ invokeLayer(layer);
+
+ getDeviceCompositionChanges(halDisplayID);
+
+ mHwc.setClientTarget(halDisplayID, mFdp.ConsumeIntegral<uint32_t>(), Fence::NO_FENCE,
+ sp<GraphicBuffer>::make(), mFdp.PickValueInArray(kDataspaces));
+
+ mHwc.presentAndGetReleaseFences(halDisplayID, std::chrono::steady_clock::now(),
+ FenceTime::NO_FENCE);
+
+ mHwc.setPowerMode(mPhysicalDisplayId, mFdp.PickValueInArray(kPowerModes));
+
+ mHwc.setColorTransform(halDisplayID, getFuzzedMatrix());
+
+ mHwc.getPresentFence(halDisplayID);
+
+ mHwc.getLayerReleaseFence(halDisplayID, layer);
+
+ mHwc.setOutputBuffer(halVirtualDisplayId, sp<Fence>::make().get(), sp<GraphicBuffer>::make());
+
+ mHwc.clearReleaseFences(halDisplayID);
+
+ getHdrCapabilities(halDisplayID);
+
+ mHwc.getSupportedPerFrameMetadata(halDisplayID);
+
+ mHwc.getRenderIntents(halDisplayID, ui::ColorMode());
+
+ mHwc.getDataspaceSaturationMatrix(halDisplayID, ui::Dataspace());
+
+ getDisplayedContentSamplingAttributes(halDisplayID);
+
+ mHwc.setDisplayContentSamplingEnabled(halDisplayID, mFdp.ConsumeBool() /*enabled*/,
+ mFdp.ConsumeIntegral<uint8_t>() /*componentMask*/,
+ mFdp.ConsumeIntegral<uint64_t>() /*maxFrames*/);
+
+ getDisplayedContentSample(halDisplayID);
+
+ mHwc.setDisplayBrightness(mPhysicalDisplayId, mFdp.ConsumeFloatingPoint<float>());
+
+ mHwc.onHotplug(kHwDisplayId, hal::Connection::CONNECTED);
+ mHwc.updatesDeviceProductInfoOnHotplugReconnect();
+
+ mHwc.onVsync(kHwDisplayId, mFdp.ConsumeIntegral<int64_t>());
+ mHwc.setVsyncEnabled(mPhysicalDisplayId,
+ mFdp.ConsumeBool() ? hal::Vsync::ENABLE : hal::Vsync::DISABLE);
+
+ mHwc.isConnected(mPhysicalDisplayId);
+ mHwc.getModes(mPhysicalDisplayId);
+ mHwc.getActiveMode(mPhysicalDisplayId);
+ mHwc.getColorModes(mPhysicalDisplayId);
+ mHwc.hasCapability(mFdp.PickValueInArray(kCapability));
+
+ mHwc.setActiveColorMode(mPhysicalDisplayId, mFdp.PickValueInArray(kColormodes),
+ mFdp.PickValueInArray(kRenderIntents));
+
+ mHwc.getDisplayConnectionType(mPhysicalDisplayId);
+ mHwc.isVsyncPeriodSwitchSupported(mPhysicalDisplayId);
+
+ getDisplayVsyncPeriod();
+
+ setActiveModeWithConstraints();
+
+ mHwc.setAutoLowLatencyMode(mPhysicalDisplayId, mFdp.ConsumeBool());
+
+ getSupportedContentTypes();
+
+ mHwc.setContentType(mPhysicalDisplayId, mFdp.PickValueInArray(kContentTypes));
+
+ dumpHwc();
+
+ mHwc.toPhysicalDisplayId(kHwDisplayId);
+ mHwc.fromPhysicalDisplayId(mPhysicalDisplayId);
+ mHwc.disconnectDisplay(halDisplayID);
+
+ static hal::HWDisplayId displayId = mFdp.ConsumeIntegral<hal::HWDisplayId>();
+ mHwc.onHotplug(displayId,
+ mFdp.ConsumeBool() ? hal::Connection::DISCONNECTED : hal::Connection::CONNECTED);
+}
+
+template <size_t N>
+DisplayIdentificationData asDisplayIdentificationData(const unsigned char (&bytes)[N]) {
+ return DisplayIdentificationData(bytes, bytes + N - 1);
+}
+
+uint32_t hashStr(const char* str) {
+ return static_cast<uint32_t>(cityHash64Len0To16(str));
+}
+
+void DisplayHardwareFuzzer::invokeDisplayIdentification() {
+ static const DisplayIdentificationData data = asDisplayIdentificationData(kInternalEdid);
+ isEdid(data);
+ parseEdid(data);
+ hashStr(mFdp.ConsumeRandomLengthString().c_str());
+ parseDisplayIdentificationData(mFdp.ConsumeIntegral<uint8_t>(), data);
+ getPnpId(getVirtualDisplayId(mFdp.ConsumeIntegral<uint32_t>()));
+ getPnpId(mFdp.ConsumeIntegral<uint8_t>());
+}
+
+void DisplayHardwareFuzzer::process() {
+ invokeComposer();
+ invokeAidlComposer();
+ invokeDisplayIdentification();
+ invokeFrameBufferSurface();
+ invokeVirtualDisplaySurface();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ DisplayHardwareFuzzer displayHardwareFuzzer(data, size);
+ displayHardwareFuzzer.process();
+ return 0;
+}
+
+} // namespace android::fuzz
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer_utils.h
new file mode 100644
index 0000000..d047270
--- /dev/null
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer_utils.h
@@ -0,0 +1,103 @@
+/*
+ * 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 <utils/Condition.h>
+#include <chrono>
+#include <vector>
+
+#include <android/hardware/graphics/composer/2.4/IComposer.h>
+#include <composer-hal/2.1/ComposerClient.h>
+#include <composer-hal/2.2/ComposerClient.h>
+#include <composer-hal/2.3/ComposerClient.h>
+#include <composer-hal/2.4/ComposerClient.h>
+
+#include "DisplayHardware/HWC2.h"
+#include "surfaceflinger_fuzzers_utils.h"
+
+namespace {
+class LayerImpl;
+class Frame;
+class DelayedEventGenerator;
+} // namespace
+
+namespace android {
+class SurfaceComposerClient;
+} // namespace android
+
+namespace android::hardware::graphics::composer::hal {
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::HWC2::ComposerCallback;
+
+class ComposerCallbackBridge : public IComposerCallback {
+public:
+ ComposerCallbackBridge(ComposerCallback* callback, bool vsyncSwitchingSupported)
+ : mCallback(callback), mVsyncSwitchingSupported(vsyncSwitchingSupported) {}
+
+ Return<void> onHotplug(HWDisplayId display, Connection connection) override {
+ mCallback->onComposerHalHotplug(display, connection);
+ return Void();
+ }
+
+ Return<void> onRefresh(HWDisplayId display) override {
+ mCallback->onComposerHalRefresh(display);
+ return Void();
+ }
+
+ Return<void> onVsync(HWDisplayId display, int64_t timestamp) override {
+ if (!mVsyncSwitchingSupported) {
+ mCallback->onComposerHalVsync(display, timestamp, std::nullopt);
+ }
+ return Void();
+ }
+
+ Return<void> onVsync_2_4(HWDisplayId display, int64_t timestamp,
+ VsyncPeriodNanos vsyncPeriodNanos) override {
+ if (mVsyncSwitchingSupported) {
+ mCallback->onComposerHalVsync(display, timestamp, vsyncPeriodNanos);
+ }
+ return Void();
+ }
+
+ Return<void> onVsyncPeriodTimingChanged(HWDisplayId display,
+ const VsyncPeriodChangeTimeline& timeline) override {
+ mCallback->onComposerHalVsyncPeriodTimingChanged(display, timeline);
+ return Void();
+ }
+
+ Return<void> onSeamlessPossible(HWDisplayId display) override {
+ mCallback->onComposerHalSeamlessPossible(display);
+ return Void();
+ }
+
+private:
+ ComposerCallback* const mCallback;
+ const bool mVsyncSwitchingSupported;
+};
+
+struct TestHWC2ComposerCallback : public HWC2::ComposerCallback {
+ virtual ~TestHWC2ComposerCallback() = default;
+ void onComposerHalHotplug(HWDisplayId, Connection){};
+ void onComposerHalRefresh(HWDisplayId) {}
+ void onComposerHalVsync(HWDisplayId, int64_t, std::optional<VsyncPeriodNanos>) {}
+ void onComposerHalVsyncPeriodTimingChanged(HWDisplayId, const VsyncPeriodChangeTimeline&) {}
+ void onComposerHalSeamlessPossible(HWDisplayId) {}
+};
+
+} // namespace android::hardware::graphics::composer::hal
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
new file mode 100644
index 0000000..ba80414
--- /dev/null
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
@@ -0,0 +1,295 @@
+/*
+ * 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 <FuzzableDataspaces.h>
+#include <binder/IServiceManager.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <ui/DisplayStatInfo.h>
+#include "surfaceflinger_fuzzers_utils.h"
+
+namespace android::fuzz {
+
+static constexpr LatchUnsignaledConfig kLatchUnsignaledConfig[] = {
+ LatchUnsignaledConfig::Always,
+ LatchUnsignaledConfig::Auto,
+ LatchUnsignaledConfig::Disabled,
+};
+
+static constexpr ui::PixelFormat kPixelFormats[] = {ui::PixelFormat::RGBA_8888,
+ ui::PixelFormat::RGBX_8888,
+ ui::PixelFormat::RGB_888,
+ ui::PixelFormat::RGB_565,
+ ui::PixelFormat::BGRA_8888,
+ ui::PixelFormat::YCBCR_422_SP,
+ ui::PixelFormat::YCRCB_420_SP,
+ ui::PixelFormat::YCBCR_422_I,
+ ui::PixelFormat::RGBA_FP16,
+ ui::PixelFormat::RAW16,
+ ui::PixelFormat::BLOB,
+ ui::PixelFormat::IMPLEMENTATION_DEFINED,
+ ui::PixelFormat::YCBCR_420_888,
+ ui::PixelFormat::RAW_OPAQUE,
+ ui::PixelFormat::RAW10,
+ ui::PixelFormat::RAW12,
+ ui::PixelFormat::RGBA_1010102,
+ ui::PixelFormat::Y8,
+ ui::PixelFormat::Y16,
+ ui::PixelFormat::YV12,
+ ui::PixelFormat::DEPTH_16,
+ ui::PixelFormat::DEPTH_24,
+ ui::PixelFormat::DEPTH_24_STENCIL_8,
+ ui::PixelFormat::DEPTH_32F,
+ ui::PixelFormat::DEPTH_32F_STENCIL_8,
+ ui::PixelFormat::STENCIL_8,
+ ui::PixelFormat::YCBCR_P010,
+ ui::PixelFormat::HSV_888};
+
+static constexpr ui::Rotation kRotations[] = {ui::Rotation::Rotation0, ui::Rotation::Rotation90,
+ ui::Rotation::Rotation180, ui::Rotation::Rotation270};
+
+static constexpr BnSurfaceComposer::ISurfaceComposerTag kSurfaceComposerTags[]{
+ BnSurfaceComposer::BOOT_FINISHED,
+ BnSurfaceComposer::CREATE_CONNECTION,
+ BnSurfaceComposer::GET_STATIC_DISPLAY_INFO,
+ BnSurfaceComposer::CREATE_DISPLAY_EVENT_CONNECTION,
+ BnSurfaceComposer::CREATE_DISPLAY,
+ BnSurfaceComposer::DESTROY_DISPLAY,
+ BnSurfaceComposer::GET_PHYSICAL_DISPLAY_TOKEN,
+ BnSurfaceComposer::SET_TRANSACTION_STATE,
+ BnSurfaceComposer::AUTHENTICATE_SURFACE,
+ BnSurfaceComposer::GET_SUPPORTED_FRAME_TIMESTAMPS,
+ BnSurfaceComposer::GET_DISPLAY_MODES,
+ BnSurfaceComposer::GET_ACTIVE_DISPLAY_MODE,
+ BnSurfaceComposer::GET_DISPLAY_STATE,
+ BnSurfaceComposer::CAPTURE_DISPLAY,
+ BnSurfaceComposer::CAPTURE_LAYERS,
+ BnSurfaceComposer::CLEAR_ANIMATION_FRAME_STATS,
+ BnSurfaceComposer::GET_ANIMATION_FRAME_STATS,
+ BnSurfaceComposer::SET_POWER_MODE,
+ BnSurfaceComposer::GET_DISPLAY_STATS,
+ BnSurfaceComposer::GET_HDR_CAPABILITIES,
+ BnSurfaceComposer::GET_DISPLAY_COLOR_MODES,
+ BnSurfaceComposer::GET_ACTIVE_COLOR_MODE,
+ BnSurfaceComposer::SET_ACTIVE_COLOR_MODE,
+ BnSurfaceComposer::ENABLE_VSYNC_INJECTIONS,
+ BnSurfaceComposer::INJECT_VSYNC,
+ BnSurfaceComposer::GET_LAYER_DEBUG_INFO,
+ BnSurfaceComposer::GET_COMPOSITION_PREFERENCE,
+ BnSurfaceComposer::GET_COLOR_MANAGEMENT,
+ BnSurfaceComposer::GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES,
+ BnSurfaceComposer::SET_DISPLAY_CONTENT_SAMPLING_ENABLED,
+ BnSurfaceComposer::GET_DISPLAYED_CONTENT_SAMPLE,
+ BnSurfaceComposer::GET_PROTECTED_CONTENT_SUPPORT,
+ BnSurfaceComposer::IS_WIDE_COLOR_DISPLAY,
+ BnSurfaceComposer::GET_DISPLAY_NATIVE_PRIMARIES,
+ BnSurfaceComposer::GET_PHYSICAL_DISPLAY_IDS,
+ BnSurfaceComposer::ADD_REGION_SAMPLING_LISTENER,
+ BnSurfaceComposer::REMOVE_REGION_SAMPLING_LISTENER,
+ BnSurfaceComposer::SET_DESIRED_DISPLAY_MODE_SPECS,
+ BnSurfaceComposer::GET_DESIRED_DISPLAY_MODE_SPECS,
+ BnSurfaceComposer::GET_DISPLAY_BRIGHTNESS_SUPPORT,
+ BnSurfaceComposer::SET_DISPLAY_BRIGHTNESS,
+ BnSurfaceComposer::CAPTURE_DISPLAY_BY_ID,
+ BnSurfaceComposer::NOTIFY_POWER_BOOST,
+ BnSurfaceComposer::SET_GLOBAL_SHADOW_SETTINGS,
+ BnSurfaceComposer::GET_AUTO_LOW_LATENCY_MODE_SUPPORT,
+ BnSurfaceComposer::SET_AUTO_LOW_LATENCY_MODE,
+ BnSurfaceComposer::GET_GAME_CONTENT_TYPE_SUPPORT,
+ BnSurfaceComposer::SET_GAME_CONTENT_TYPE,
+ BnSurfaceComposer::SET_FRAME_RATE,
+ BnSurfaceComposer::ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN,
+ BnSurfaceComposer::SET_FRAME_TIMELINE_INFO,
+ BnSurfaceComposer::ADD_TRANSACTION_TRACE_LISTENER,
+ BnSurfaceComposer::GET_GPU_CONTEXT_PRIORITY,
+ BnSurfaceComposer::GET_MAX_ACQUIRED_BUFFER_COUNT,
+ BnSurfaceComposer::GET_DYNAMIC_DISPLAY_INFO,
+ BnSurfaceComposer::ADD_FPS_LISTENER,
+ BnSurfaceComposer::REMOVE_FPS_LISTENER,
+ BnSurfaceComposer::OVERRIDE_HDR_TYPES,
+ BnSurfaceComposer::ADD_HDR_LAYER_INFO_LISTENER,
+ BnSurfaceComposer::REMOVE_HDR_LAYER_INFO_LISTENER,
+ BnSurfaceComposer::ON_PULL_ATOM,
+ BnSurfaceComposer::ADD_TUNNEL_MODE_ENABLED_LISTENER,
+ BnSurfaceComposer::REMOVE_TUNNEL_MODE_ENABLED_LISTENER,
+ BnSurfaceComposer::ADD_WINDOW_INFOS_LISTENER,
+ BnSurfaceComposer::REMOVE_WINDOW_INFOS_LISTENER,
+};
+
+static constexpr uint32_t kMinCode = 1000;
+static constexpr uint32_t kMaxCode = 1050;
+
+class SurfaceFlingerFuzzer {
+public:
+ SurfaceFlingerFuzzer(const uint8_t *data, size_t size) : mFdp(data, size) {
+ mFlinger = mTestableFlinger.flinger();
+ };
+ void process(const uint8_t *data, size_t size);
+
+private:
+ void setUp();
+ void invokeFlinger();
+ void setTransactionState();
+ void setInternalDisplayPrimaries();
+ void setDisplayStateLocked();
+ void onTransact(const uint8_t *data, size_t size);
+
+ FuzzedDataProvider mFdp;
+ TestableSurfaceFlinger mTestableFlinger;
+ sp<SurfaceFlinger> mFlinger = nullptr;
+};
+
+void SurfaceFlingerFuzzer::invokeFlinger() {
+ mFlinger->setSchedFifo(mFdp.ConsumeBool());
+ mFlinger->setSchedAttr(mFdp.ConsumeBool());
+ mFlinger->getServiceName();
+ mFlinger->hasSyncFramework = mFdp.ConsumeBool();
+ mFlinger->dispSyncPresentTimeOffset = mFdp.ConsumeIntegral<int64_t>();
+ mFlinger->useHwcForRgbToYuv = mFdp.ConsumeBool();
+ mFlinger->maxFrameBufferAcquiredBuffers = mFdp.ConsumeIntegral<int64_t>();
+ mFlinger->maxGraphicsWidth = mFdp.ConsumeIntegral<uint32_t>();
+ mFlinger->maxGraphicsHeight = mFdp.ConsumeIntegral<uint32_t>();
+ mFlinger->hasWideColorDisplay = mFdp.ConsumeBool();
+ mFlinger->internalDisplayOrientation = mFdp.PickValueInArray(kRotations);
+ mFlinger->useContextPriority = mFdp.ConsumeBool();
+
+ mFlinger->defaultCompositionDataspace = mFdp.PickValueInArray(kDataspaces);
+ mFlinger->defaultCompositionPixelFormat = mFdp.PickValueInArray(kPixelFormats);
+ mFlinger->wideColorGamutCompositionDataspace = mFdp.PickValueInArray(kDataspaces);
+ mFlinger->wideColorGamutCompositionPixelFormat = mFdp.PickValueInArray(kPixelFormats);
+
+ mFlinger->enableSdrDimming = mFdp.ConsumeBool();
+ mFlinger->enableLatchUnsignaledConfig = mFdp.PickValueInArray(kLatchUnsignaledConfig);
+
+ mFlinger->scheduleComposite(mFdp.ConsumeBool()
+ ? scheduler::ISchedulerCallback::FrameHint::kActive
+ : scheduler::ISchedulerCallback::FrameHint::kNone);
+
+ mFlinger->scheduleRepaint();
+ mFlinger->scheduleSample();
+
+ uint32_t texture = mFlinger->getNewTexture();
+ mFlinger->deleteTextureAsync(texture);
+
+ sp<IBinder> handle = defaultServiceManager()->checkService(
+ String16(mFdp.ConsumeRandomLengthString().c_str()));
+ mFlinger->fromHandle(handle);
+ mFlinger->windowInfosReported();
+ mFlinger->disableExpensiveRendering();
+}
+
+void SurfaceFlingerFuzzer::setInternalDisplayPrimaries() {
+ ui::DisplayPrimaries primaries;
+ primaries.red.X = mFdp.ConsumeFloatingPoint<float>();
+ primaries.red.Y = mFdp.ConsumeFloatingPoint<float>();
+ primaries.red.Z = mFdp.ConsumeFloatingPoint<float>();
+ primaries.green.X = mFdp.ConsumeFloatingPoint<float>();
+ primaries.green.Y = mFdp.ConsumeFloatingPoint<float>();
+ primaries.green.Z = mFdp.ConsumeFloatingPoint<float>();
+ primaries.blue.X = mFdp.ConsumeFloatingPoint<float>();
+ primaries.blue.Y = mFdp.ConsumeFloatingPoint<float>();
+ primaries.blue.Z = mFdp.ConsumeFloatingPoint<float>();
+ primaries.white.X = mFdp.ConsumeFloatingPoint<float>();
+ primaries.white.Y = mFdp.ConsumeFloatingPoint<float>();
+ primaries.white.Z = mFdp.ConsumeFloatingPoint<float>();
+ mTestableFlinger.setInternalDisplayPrimaries(primaries);
+}
+
+void SurfaceFlingerFuzzer::setTransactionState() {
+ Vector<ComposerState> states;
+ Vector<DisplayState> displays;
+ ComposerState composerState;
+ composerState.state.what = layer_state_t::eLayerCreated;
+ composerState.state.surface = nullptr;
+ states.add(composerState);
+ uint32_t flags = mFdp.ConsumeIntegral<uint32_t>();
+ const sp<IBinder> applyToken = nullptr;
+ int64_t desiredPresentTime = mFdp.ConsumeIntegral<int64_t>();
+ bool isAutoTimestamp = mFdp.ConsumeBool();
+ bool hasListenerCallbacks = mFdp.ConsumeBool();
+ std::vector<ListenerCallbacks> listenerCallbacks{};
+ uint64_t transactionId = mFdp.ConsumeIntegral<uint64_t>();
+
+ mTestableFlinger.setTransactionState(FrameTimelineInfo{}, states, displays, flags, applyToken,
+ InputWindowCommands{}, desiredPresentTime, isAutoTimestamp,
+ {}, hasListenerCallbacks, listenerCallbacks,
+ transactionId);
+}
+
+void SurfaceFlingerFuzzer::setDisplayStateLocked() {
+ DisplayState state{};
+ mTestableFlinger.setDisplayStateLocked(state);
+}
+
+void SurfaceFlingerFuzzer::onTransact(const uint8_t *data, size_t size) {
+ Parcel fuzzedData, reply;
+ fuzzedData.writeInterfaceToken(String16("android.ui.ISurfaceComposer"));
+ fuzzedData.setData(data, size);
+ fuzzedData.setDataPosition(0);
+ uint32_t code = mFdp.ConsumeBool() ? mFdp.PickValueInArray(kSurfaceComposerTags)
+ : mFdp.ConsumeIntegralInRange<uint32_t>(kMinCode, kMaxCode);
+ mTestableFlinger.onTransact(code, fuzzedData, &reply, 0);
+}
+
+void SurfaceFlingerFuzzer::setUp() {
+ mTestableFlinger.setupScheduler(std::make_unique<android::mock::VsyncController>(),
+ std::make_unique<android::mock::VSyncTracker>(),
+ std::make_unique<android::mock::EventThread>(),
+ std::make_unique<android::mock::EventThread>());
+
+ mTestableFlinger.setupTimeStats(std::make_unique<android::mock::TimeStats>());
+
+ std::unique_ptr<android::renderengine::RenderEngine> renderEngine =
+ std::make_unique<android::renderengine::mock::RenderEngine>();
+ mTestableFlinger.setupRenderEngine(std::move(renderEngine));
+ mTestableFlinger.setupComposer(std::make_unique<android::Hwc2::mock::Composer>());
+}
+
+void SurfaceFlingerFuzzer::process(const uint8_t *data, size_t size) {
+ setUp();
+
+ invokeFlinger();
+
+ mTestableFlinger.fuzzSurfaceFlinger(data, size);
+
+ mTestableFlinger.setCreateBufferQueueFunction(
+ surfaceflinger::test::Factory::CreateBufferQueueFunction());
+ mTestableFlinger.setCreateNativeWindowSurface(
+ surfaceflinger::test::Factory::CreateNativeWindowSurfaceFunction());
+
+ setInternalDisplayPrimaries();
+
+ mTestableFlinger.enableHalVirtualDisplays(mFdp.ConsumeBool());
+
+ mTestableFlinger.commitTransactionsLocked(mFdp.ConsumeIntegral<uint32_t>());
+
+ mTestableFlinger.notifyPowerBoost(mFdp.ConsumeIntegral<int32_t>());
+
+ setDisplayStateLocked();
+
+ setTransactionState();
+ mTestableFlinger.flushTransactionQueues();
+
+ onTransact(data, size);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ android::fuzz::SurfaceFlingerFuzzer surfaceFlingerFuzzer(data, size);
+ surfaceFlingerFuzzer.process(data, size);
+ return 0;
+}
+
+} // namespace android::fuzz
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
new file mode 100644
index 0000000..ceb3e64
--- /dev/null
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -0,0 +1,803 @@
+/*
+ * 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 <compositionengine/Display.h>
+#include <compositionengine/LayerFECompositionState.h>
+#include <compositionengine/OutputLayer.h>
+#include <compositionengine/impl/CompositionEngine.h>
+#include <compositionengine/impl/Display.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
+#include <gui/LayerDebugInfo.h>
+#include <gui/ScreenCaptureResults.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/mock/GraphicBufferProducer.h>
+#include <ui/DisplayStatInfo.h>
+#include <ui/DynamicDisplayInfo.h>
+
+#include "BufferQueueLayer.h"
+#include "BufferStateLayer.h"
+#include "ContainerLayer.h"
+#include "DisplayDevice.h"
+#include "DisplayHardware/ComposerHal.h"
+#include "EffectLayer.h"
+#include "FrameTimeline/FrameTimeline.h"
+#include "FrameTracer/FrameTracer.h"
+#include "Layer.h"
+#include "NativeWindowSurface.h"
+#include "Scheduler/EventThread.h"
+#include "Scheduler/MessageQueue.h"
+#include "Scheduler/RefreshRateConfigs.h"
+#include "Scheduler/TimeKeeper.h"
+#include "Scheduler/VSyncTracker.h"
+#include "Scheduler/VsyncConfiguration.h"
+#include "Scheduler/VsyncController.h"
+#include "Scheduler/VsyncModulator.h"
+#include "StartPropertySetThread.h"
+#include "SurfaceFlinger.h"
+#include "SurfaceFlingerDefaultFactory.h"
+#include "SurfaceInterceptor.h"
+#include "TimeStats/TimeStats.h"
+
+#include "renderengine/mock/RenderEngine.h"
+#include "tests/unittests/mock/DisplayHardware/MockComposer.h"
+#include "tests/unittests/mock/DisplayHardware/MockHWC2.h"
+#include "tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h"
+#include "tests/unittests/mock/MockEventThread.h"
+#include "tests/unittests/mock/MockFrameTimeline.h"
+#include "tests/unittests/mock/MockFrameTracer.h"
+#include "tests/unittests/mock/MockNativeWindowSurface.h"
+#include "tests/unittests/mock/MockSurfaceInterceptor.h"
+#include "tests/unittests/mock/MockTimeStats.h"
+#include "tests/unittests/mock/MockVSyncTracker.h"
+#include "tests/unittests/mock/MockVsyncController.h"
+
+namespace android {
+namespace Hwc2 {
+
+class Composer;
+
+namespace types = hardware::graphics::common;
+
+namespace V2_1 = hardware::graphics::composer::V2_1;
+namespace V2_2 = hardware::graphics::composer::V2_2;
+namespace V2_3 = hardware::graphics::composer::V2_3;
+namespace V2_4 = hardware::graphics::composer::V2_4;
+
+using types::V1_0::ColorTransform;
+using types::V1_0::Transform;
+using types::V1_1::RenderIntent;
+using types::V1_2::ColorMode;
+using types::V1_2::Dataspace;
+using types::V1_2::Hdr;
+using types::V1_2::PixelFormat;
+
+using V2_1::Config;
+using V2_1::Display;
+using V2_1::Error;
+using V2_1::Layer;
+using V2_4::CommandReaderBase;
+using V2_4::CommandWriterBase;
+using V2_4::IComposer;
+using V2_4::IComposerCallback;
+using V2_4::IComposerClient;
+using V2_4::VsyncPeriodChangeTimeline;
+using V2_4::VsyncPeriodNanos;
+using DisplayCapability = IComposerClient::DisplayCapability;
+using PerFrameMetadata = IComposerClient::PerFrameMetadata;
+using PerFrameMetadataKey = IComposerClient::PerFrameMetadataKey;
+using PerFrameMetadataBlob = IComposerClient::PerFrameMetadataBlob;
+}; // namespace Hwc2
+
+static constexpr hal::HWDisplayId kHwDisplayId = 1000;
+
+static constexpr ui::Hdr kHdrTypes[] = {ui::Hdr::DOLBY_VISION, ui::Hdr::HDR10, ui::Hdr::HLG,
+ ui::Hdr::HDR10_PLUS};
+
+static constexpr ui::ColorMode kColormodes[] = {ui::ColorMode::NATIVE,
+ ui::ColorMode::STANDARD_BT601_625,
+ ui::ColorMode::STANDARD_BT601_625_UNADJUSTED,
+ ui::ColorMode::STANDARD_BT601_525,
+ ui::ColorMode::STANDARD_BT601_525_UNADJUSTED,
+ ui::ColorMode::STANDARD_BT709,
+ ui::ColorMode::DCI_P3,
+ ui::ColorMode::SRGB,
+ ui::ColorMode::ADOBE_RGB,
+ ui::ColorMode::DISPLAY_P3,
+ ui::ColorMode::BT2020,
+ ui::ColorMode::BT2100_PQ,
+ ui::ColorMode::BT2100_HLG,
+ ui::ColorMode::DISPLAY_BT2020};
+
+FloatRect getFuzzedFloatRect(FuzzedDataProvider *fdp) {
+ return FloatRect(fdp->ConsumeFloatingPoint<float>() /*left*/,
+ fdp->ConsumeFloatingPoint<float>() /*right*/,
+ fdp->ConsumeFloatingPoint<float>() /*top*/,
+ fdp->ConsumeFloatingPoint<float>() /*bottom*/);
+}
+
+HdrMetadata getFuzzedHdrMetadata(FuzzedDataProvider *fdp) {
+ HdrMetadata hdrMetadata;
+ if (fdp->ConsumeBool()) {
+ hdrMetadata.cta8613.maxContentLightLevel = fdp->ConsumeFloatingPoint<float>();
+ hdrMetadata.cta8613.maxFrameAverageLightLevel = fdp->ConsumeFloatingPoint<float>();
+
+ hdrMetadata.validTypes |= HdrMetadata::CTA861_3;
+ } else {
+ hdrMetadata.smpte2086.displayPrimaryRed.x = fdp->ConsumeFloatingPoint<float>();
+ hdrMetadata.smpte2086.displayPrimaryRed.y = fdp->ConsumeFloatingPoint<float>();
+ hdrMetadata.smpte2086.displayPrimaryGreen.x = fdp->ConsumeFloatingPoint<float>();
+ hdrMetadata.smpte2086.displayPrimaryGreen.y = fdp->ConsumeFloatingPoint<float>();
+ hdrMetadata.smpte2086.displayPrimaryBlue.x = fdp->ConsumeFloatingPoint<float>();
+ hdrMetadata.smpte2086.displayPrimaryBlue.y = fdp->ConsumeFloatingPoint<float>();
+ hdrMetadata.smpte2086.whitePoint.x = fdp->ConsumeFloatingPoint<float>();
+ hdrMetadata.smpte2086.whitePoint.y = fdp->ConsumeFloatingPoint<float>();
+ hdrMetadata.smpte2086.minLuminance = fdp->ConsumeFloatingPoint<float>();
+ hdrMetadata.smpte2086.maxLuminance = fdp->ConsumeFloatingPoint<float>();
+
+ hdrMetadata.validTypes |= HdrMetadata::SMPTE2086;
+ }
+ return hdrMetadata;
+}
+
+class EventThread;
+
+namespace hal = android::hardware::graphics::composer::hal;
+
+struct FakePhaseOffsets : scheduler::VsyncConfiguration {
+ static constexpr nsecs_t FAKE_PHASE_OFFSET_NS = 0;
+ static constexpr auto FAKE_DURATION_OFFSET_NS = std::chrono::nanoseconds(0);
+
+ VsyncConfigSet getConfigsForRefreshRate(Fps) const override { return getCurrentConfigs(); }
+
+ VsyncConfigSet getCurrentConfigs() const override {
+ return {{FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS, FAKE_DURATION_OFFSET_NS,
+ FAKE_DURATION_OFFSET_NS},
+ {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS, FAKE_DURATION_OFFSET_NS,
+ FAKE_DURATION_OFFSET_NS},
+ {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS, FAKE_DURATION_OFFSET_NS,
+ FAKE_DURATION_OFFSET_NS},
+ FAKE_DURATION_OFFSET_NS};
+ }
+
+ void reset() override {}
+ void setRefreshRateFps(Fps) override {}
+ void dump(std::string &) const override {}
+};
+namespace scheduler {
+class TestableScheduler : public Scheduler, private ICompositor {
+public:
+ TestableScheduler(const std::shared_ptr<scheduler::RefreshRateConfigs> &refreshRateConfigs,
+ ISchedulerCallback &callback)
+ : TestableScheduler(std::make_unique<android::mock::VsyncController>(),
+ std::make_unique<android::mock::VSyncTracker>(), refreshRateConfigs,
+ callback) {}
+
+ void scheduleFrame(){};
+ void postMessage(sp<MessageHandler> &&){};
+
+ TestableScheduler(std::unique_ptr<VsyncController> controller,
+ std::unique_ptr<VSyncTracker> tracker,
+ std::shared_ptr<RefreshRateConfigs> configs, ISchedulerCallback &callback)
+ : Scheduler(*this, callback, Feature::kContentDetection) {
+ mVsyncSchedule.emplace(VsyncSchedule(std::move(tracker), nullptr, std::move(controller)));
+ setRefreshRateConfigs(std::move(configs));
+ }
+
+ ConnectionHandle createConnection(std::unique_ptr<EventThread> eventThread) {
+ return Scheduler::createConnection(std::move(eventThread));
+ }
+
+ auto &mutablePrimaryHWVsyncEnabled() { return mPrimaryHWVsyncEnabled; }
+ auto &mutableHWVsyncAvailable() { return mHWVsyncAvailable; }
+
+ auto &mutableLayerHistory() { return mLayerHistory; }
+
+ auto refreshRateConfigs() { return holdRefreshRateConfigs(); }
+
+ void replaceTouchTimer(int64_t millis) {
+ if (mTouchTimer) {
+ mTouchTimer.reset();
+ }
+ mTouchTimer.emplace(
+ "Testable Touch timer", std::chrono::milliseconds(millis),
+ [this] { touchTimerCallback(TimerState::Reset); },
+ [this] { touchTimerCallback(TimerState::Expired); });
+ mTouchTimer->start();
+ }
+
+ bool isTouchActive() {
+ std::lock_guard<std::mutex> lock(mPolicyLock);
+ return mPolicy.touch == Scheduler::TouchState::Active;
+ }
+
+ void dispatchCachedReportedMode() {
+ std::lock_guard<std::mutex> lock(mPolicyLock);
+ return Scheduler::dispatchCachedReportedMode();
+ }
+
+ void clearCachedReportedMode() {
+ std::lock_guard<std::mutex> lock(mPolicyLock);
+ mPolicy.cachedModeChangedParams.reset();
+ }
+
+ void onNonPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) {
+ return Scheduler::onNonPrimaryDisplayModeChanged(handle, mode);
+ }
+
+private:
+ // ICompositor overrides:
+ bool commit(nsecs_t, int64_t, nsecs_t) override { return false; }
+ void composite(nsecs_t) override {}
+ void sample() override {}
+};
+}; // namespace scheduler
+
+namespace surfaceflinger::test {
+
+class Factory final : public surfaceflinger::Factory {
+public:
+ ~Factory() = default;
+
+ std::unique_ptr<HWComposer> createHWComposer(const std::string &) override { return nullptr; }
+
+ std::unique_ptr<MessageQueue> createMessageQueue(ICompositor &compositor) {
+ return std::make_unique<android::impl::MessageQueue>(compositor);
+ }
+
+ std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
+ Fps /*currentRefreshRate*/) override {
+ return std::make_unique<FakePhaseOffsets>();
+ }
+
+ std::unique_ptr<scheduler::Scheduler> createScheduler(
+ const std::shared_ptr<scheduler::RefreshRateConfigs> &,
+ scheduler::ISchedulerCallback &) {
+ return nullptr;
+ }
+
+ sp<SurfaceInterceptor> createSurfaceInterceptor() override {
+ return new android::impl::SurfaceInterceptor();
+ }
+
+ sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override {
+ return new StartPropertySetThread(timestampPropertyValue);
+ }
+
+ sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs &creationArgs) override {
+ return new DisplayDevice(creationArgs);
+ }
+
+ sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format,
+ uint32_t layerCount, uint64_t usage,
+ std::string requestorName) override {
+ return new GraphicBuffer(width, height, format, layerCount, usage, requestorName);
+ }
+
+ void createBufferQueue(sp<IGraphicBufferProducer> *outProducer,
+ sp<IGraphicBufferConsumer> *outConsumer,
+ bool consumerIsSurfaceFlinger) override {
+ if (!mCreateBufferQueue) {
+ BufferQueue::createBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger);
+ return;
+ }
+ mCreateBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger);
+ }
+
+ sp<IGraphicBufferProducer> createMonitoredProducer(const sp<IGraphicBufferProducer> &producer,
+ const sp<SurfaceFlinger> &flinger,
+ const wp<Layer> &layer) override {
+ return new MonitoredProducer(producer, flinger, layer);
+ }
+
+ sp<BufferLayerConsumer> createBufferLayerConsumer(const sp<IGraphicBufferConsumer> &consumer,
+ renderengine::RenderEngine &renderEngine,
+ uint32_t textureName, Layer *layer) override {
+ return new BufferLayerConsumer(consumer, renderEngine, textureName, layer);
+ }
+
+ std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
+ const sp<IGraphicBufferProducer> &producer) override {
+ if (!mCreateNativeWindowSurface) return nullptr;
+ return mCreateNativeWindowSurface(producer);
+ }
+
+ std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() override {
+ return compositionengine::impl::createCompositionEngine();
+ }
+
+ sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs &) override {
+ return nullptr;
+ }
+
+ sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs &) override {
+ return nullptr;
+ }
+
+ sp<EffectLayer> createEffectLayer(const LayerCreationArgs &args) override {
+ return new EffectLayer(args);
+ }
+
+ sp<ContainerLayer> createContainerLayer(const LayerCreationArgs &args) override {
+ return new ContainerLayer(args);
+ }
+
+ std::unique_ptr<FrameTracer> createFrameTracer() override {
+ return std::make_unique<android::mock::FrameTracer>();
+ }
+
+ std::unique_ptr<frametimeline::FrameTimeline> createFrameTimeline(
+ std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid = 0) override {
+ return std::make_unique<android::mock::FrameTimeline>(timeStats, surfaceFlingerPid);
+ }
+
+ using CreateBufferQueueFunction =
+ std::function<void(sp<IGraphicBufferProducer> * /* outProducer */,
+ sp<IGraphicBufferConsumer> * /* outConsumer */,
+ bool /* consumerIsSurfaceFlinger */)>;
+ CreateBufferQueueFunction mCreateBufferQueue;
+
+ using CreateNativeWindowSurfaceFunction =
+ std::function<std::unique_ptr<surfaceflinger::NativeWindowSurface>(
+ const sp<IGraphicBufferProducer> &)>;
+ CreateNativeWindowSurfaceFunction mCreateNativeWindowSurface;
+
+ using CreateCompositionEngineFunction =
+ std::function<std::unique_ptr<compositionengine::CompositionEngine>()>;
+ CreateCompositionEngineFunction mCreateCompositionEngine;
+};
+
+} // namespace surfaceflinger::test
+
+// TODO(b/189053744) : Create a common test/mock library for surfaceflinger
+class TestableSurfaceFlinger final : private scheduler::ISchedulerCallback {
+public:
+ using HotplugEvent = SurfaceFlinger::HotplugEvent;
+
+ SurfaceFlinger *flinger() { return mFlinger.get(); }
+ scheduler::TestableScheduler *scheduler() { return mScheduler; }
+
+ // Allow reading display state without locking, as if called on the SF main thread.
+ auto onInitializeDisplays() NO_THREAD_SAFETY_ANALYSIS {
+ return mFlinger->onInitializeDisplays();
+ }
+
+ void scheduleComposite(FrameHint){};
+
+ void setGlobalShadowSettings(FuzzedDataProvider *fdp) {
+ const half4 ambientColor{fdp->ConsumeFloatingPoint<float>(),
+ fdp->ConsumeFloatingPoint<float>(),
+ fdp->ConsumeFloatingPoint<float>(),
+ fdp->ConsumeFloatingPoint<float>()};
+ const half4 spotColor{fdp->ConsumeFloatingPoint<float>(),
+ fdp->ConsumeFloatingPoint<float>(),
+ fdp->ConsumeFloatingPoint<float>(),
+ fdp->ConsumeFloatingPoint<float>()};
+ float lightPosY = fdp->ConsumeFloatingPoint<float>();
+ float lightPosZ = fdp->ConsumeFloatingPoint<float>();
+ float lightRadius = fdp->ConsumeFloatingPoint<float>();
+ mFlinger->setGlobalShadowSettings(ambientColor, spotColor, lightPosY, lightPosZ,
+ lightRadius);
+ }
+
+ void onPullAtom(FuzzedDataProvider *fdp) {
+ const int32_t atomId = fdp->ConsumeIntegral<uint8_t>();
+ std::string pulledData = fdp->ConsumeRandomLengthString().c_str();
+ bool success = fdp->ConsumeBool();
+ mFlinger->onPullAtom(atomId, &pulledData, &success);
+ }
+
+ void fuzzDumpsysAndDebug(FuzzedDataProvider *fdp) {
+ std::string result = fdp->ConsumeRandomLengthString().c_str();
+ mFlinger->appendSfConfigString(result);
+ result = fdp->ConsumeRandomLengthString().c_str();
+ mFlinger->listLayersLocked(result);
+
+ using DumpArgs = Vector<String16>;
+ DumpArgs dumpArgs;
+ dumpArgs.push_back(String16(fdp->ConsumeRandomLengthString().c_str()));
+ mFlinger->clearStatsLocked(dumpArgs, result);
+
+ mFlinger->dumpTimeStats(dumpArgs, fdp->ConsumeBool(), result);
+ mFlinger->logFrameStats();
+
+ result = fdp->ConsumeRandomLengthString().c_str();
+ mFlinger->dumpFrameTimeline(dumpArgs, result);
+
+ result = fdp->ConsumeRandomLengthString().c_str();
+ mFlinger->dumpStaticScreenStats(result);
+
+ result = fdp->ConsumeRandomLengthString().c_str();
+ mFlinger->dumpFrameEventsLocked(result);
+
+ result = fdp->ConsumeRandomLengthString().c_str();
+ mFlinger->dumpRawDisplayIdentificationData(dumpArgs, result);
+
+ LayersProto layersProto = mFlinger->dumpDrawingStateProto(fdp->ConsumeIntegral<uint32_t>());
+ mFlinger->dumpOffscreenLayersProto(layersProto);
+ LayersTraceProto layersTraceProto{};
+ mFlinger->dumpDisplayProto(layersTraceProto);
+
+ result = fdp->ConsumeRandomLengthString().c_str();
+ mFlinger->dumpHwc(result);
+
+ mFlinger->calculateColorMatrix(fdp->ConsumeFloatingPoint<float>());
+ mFlinger->updateColorMatrixLocked();
+ mFlinger->CheckTransactCodeCredentials(fdp->ConsumeIntegral<uint32_t>());
+
+ const CountDownLatch transactionCommittedSignal(fdp->ConsumeIntegral<uint32_t>());
+ mFlinger->waitForSynchronousTransaction(transactionCommittedSignal);
+ mFlinger->signalSynchronousTransactions(fdp->ConsumeIntegral<uint32_t>());
+ }
+
+ void getCompositionPreference() {
+ ui::Dataspace outDataspace;
+ ui::PixelFormat outPixelFormat;
+ ui::Dataspace outWideColorGamutDataspace;
+ ui::PixelFormat outWideColorGamutPixelFormat;
+ mFlinger->getCompositionPreference(&outDataspace, &outPixelFormat,
+ &outWideColorGamutDataspace,
+ &outWideColorGamutPixelFormat);
+ }
+
+ void overrideHdrTypes(sp<IBinder> &display, FuzzedDataProvider *fdp) {
+ std::vector<ui::Hdr> hdrTypes;
+ hdrTypes.push_back(fdp->PickValueInArray(kHdrTypes));
+ mFlinger->overrideHdrTypes(display, hdrTypes);
+ }
+
+ void getDisplayedContentSample(sp<IBinder> &display, FuzzedDataProvider *fdp) {
+ DisplayedFrameStats outDisplayedFrameStats;
+ mFlinger->getDisplayedContentSample(display, fdp->ConsumeIntegral<uint64_t>(),
+ fdp->ConsumeIntegral<uint64_t>(),
+ &outDisplayedFrameStats);
+ }
+
+ void getDisplayStats(sp<IBinder> &display) {
+ android::DisplayStatInfo stats;
+ mFlinger->getDisplayStats(display, &stats);
+ }
+
+ void getDisplayState(sp<IBinder> &display) {
+ ui::DisplayState displayState;
+ mFlinger->getDisplayState(display, &displayState);
+ }
+
+ void getStaticDisplayInfo(sp<IBinder> &display) {
+ ui::StaticDisplayInfo staticDisplayInfo;
+ mFlinger->getStaticDisplayInfo(display, &staticDisplayInfo);
+ }
+
+ void getDynamicDisplayInfo(sp<IBinder> &display) {
+ android::ui::DynamicDisplayInfo dynamicDisplayInfo;
+ mFlinger->getDynamicDisplayInfo(display, &dynamicDisplayInfo);
+ }
+ void getDisplayNativePrimaries(sp<IBinder> &display) {
+ android::ui::DisplayPrimaries displayPrimaries;
+ mFlinger->getDisplayNativePrimaries(display, displayPrimaries);
+ }
+
+ void getDesiredDisplayModeSpecs(sp<IBinder> &display) {
+ ui::DisplayModeId outDefaultMode;
+ bool outAllowGroupSwitching;
+ float outPrimaryRefreshRateMin;
+ float outPrimaryRefreshRateMax;
+ float outAppRequestRefreshRateMin;
+ float outAppRequestRefreshRateMax;
+ mFlinger->getDesiredDisplayModeSpecs(display, &outDefaultMode, &outAllowGroupSwitching,
+ &outPrimaryRefreshRateMin, &outPrimaryRefreshRateMax,
+ &outAppRequestRefreshRateMin,
+ &outAppRequestRefreshRateMax);
+ }
+
+ void setVsyncConfig(FuzzedDataProvider *fdp) {
+ const scheduler::VsyncModulator::VsyncConfig vsyncConfig{};
+ mFlinger->setVsyncConfig(vsyncConfig, fdp->ConsumeIntegral<nsecs_t>());
+ }
+
+ void updateCompositorTiming(FuzzedDataProvider *fdp) {
+ std::shared_ptr<FenceTime> presentFenceTime = FenceTime::NO_FENCE;
+ mFlinger->updateCompositorTiming({}, fdp->ConsumeIntegral<nsecs_t>(), presentFenceTime);
+ }
+
+ void getCompositorTiming() {
+ CompositorTiming compositorTiming;
+ mFlinger->getCompositorTiming(&compositorTiming);
+ }
+
+ sp<IBinder> fuzzBoot(FuzzedDataProvider *fdp) {
+ mFlinger->callingThreadHasUnscopedSurfaceFlingerAccess(fdp->ConsumeBool());
+ mFlinger->createConnection();
+
+ DisplayIdGenerator<HalVirtualDisplayId> kGenerator;
+ HalVirtualDisplayId halVirtualDisplayId = kGenerator.generateId().value();
+
+ ui::Size uiSize{fdp->ConsumeIntegral<int32_t>(), fdp->ConsumeIntegral<int32_t>()};
+ ui::PixelFormat pixelFormat{};
+ mFlinger->getHwComposer().allocateVirtualDisplay(halVirtualDisplayId, uiSize, &pixelFormat);
+
+ PhysicalDisplayId physicalDisplayId = SurfaceComposerClient::getInternalDisplayId().value();
+ mFlinger->getHwComposer().allocatePhysicalDisplay(kHwDisplayId, physicalDisplayId);
+
+ sp<IBinder> display =
+ mFlinger->createDisplay(String8(fdp->ConsumeRandomLengthString().c_str()),
+ fdp->ConsumeBool());
+
+ onInitializeDisplays();
+ mFlinger->getPhysicalDisplayToken(physicalDisplayId);
+
+ mFlinger->mStartPropertySetThread =
+ mFlinger->getFactory().createStartPropertySetThread(fdp->ConsumeBool());
+
+ mFlinger->bootFinished();
+
+ return display;
+ }
+
+ void fuzzSurfaceFlinger(const uint8_t *data, size_t size) {
+ FuzzedDataProvider mFdp(data, size);
+
+ sp<IBinder> display = fuzzBoot(&mFdp);
+
+ sp<IGraphicBufferProducer> bufferProducer = sp<mock::GraphicBufferProducer>::make();
+ mFlinger->authenticateSurfaceTexture(bufferProducer.get());
+
+ mFlinger->createDisplayEventConnection();
+
+ getDisplayStats(display);
+ getDisplayState(display);
+ getStaticDisplayInfo(display);
+ getDynamicDisplayInfo(display);
+ getDisplayNativePrimaries(display);
+
+ mFlinger->setAutoLowLatencyMode(display, mFdp.ConsumeBool());
+ mFlinger->setGameContentType(display, mFdp.ConsumeBool());
+ mFlinger->setPowerMode(display, mFdp.ConsumeIntegral<int>());
+ mFlinger->clearAnimationFrameStats();
+
+ overrideHdrTypes(display, &mFdp);
+
+ onPullAtom(&mFdp);
+
+ mFlinger->injectVSync(mFdp.ConsumeIntegral<nsecs_t>());
+
+ getCompositionPreference();
+ getDisplayedContentSample(display, &mFdp);
+ getDesiredDisplayModeSpecs(display);
+
+ bool outSupport;
+ mFlinger->getDisplayBrightnessSupport(display, &outSupport);
+
+ mFlinger->notifyPowerBoost(mFdp.ConsumeIntegral<int32_t>());
+
+ setGlobalShadowSettings(&mFdp);
+
+ mFlinger->binderDied(display);
+ mFlinger->onFirstRef();
+
+ mFlinger->commitTransactions();
+ mFlinger->updateInputFlinger();
+ mFlinger->updateCursorAsync();
+
+ setVsyncConfig(&mFdp);
+
+ mFlinger->flushTransactionQueues(0);
+
+ mFlinger->setTransactionFlags(mFdp.ConsumeIntegral<uint32_t>());
+ mFlinger->clearTransactionFlags(mFdp.ConsumeIntegral<uint32_t>());
+ mFlinger->commitOffscreenLayers();
+
+ mFlinger->frameIsEarly(mFdp.ConsumeIntegral<nsecs_t>(), mFdp.ConsumeIntegral<int64_t>());
+ mFlinger->computeLayerBounds();
+ mFlinger->startBootAnim();
+
+ mFlinger->readPersistentProperties();
+
+ mFlinger->exceedsMaxRenderTargetSize(mFdp.ConsumeIntegral<uint32_t>(),
+ mFdp.ConsumeIntegral<uint32_t>());
+
+ mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mFdp.ConsumeIntegral<uid_t>());
+
+ mFlinger->postComposition();
+
+ getCompositorTiming();
+
+ updateCompositorTiming(&mFdp);
+
+ mFlinger->setCompositorTimingSnapped({}, mFdp.ConsumeIntegral<nsecs_t>());
+ mFlinger->postFrame();
+ mFlinger->calculateExpectedPresentTime({});
+
+ mFlinger->enableHalVirtualDisplays(mFdp.ConsumeBool());
+
+ fuzzDumpsysAndDebug(&mFdp);
+
+ mFlinger->destroyDisplay(display);
+ }
+
+ void setupRenderEngine(std::unique_ptr<renderengine::RenderEngine> renderEngine) {
+ mFlinger->mCompositionEngine->setRenderEngine(std::move(renderEngine));
+ }
+
+ void setupComposer(std::unique_ptr<Hwc2::Composer> composer) {
+ mFlinger->mCompositionEngine->setHwComposer(
+ std::make_unique<impl::HWComposer>(std::move(composer)));
+ }
+
+ void setupTimeStats(const std::shared_ptr<TimeStats> &timeStats) {
+ mFlinger->mCompositionEngine->setTimeStats(timeStats);
+ }
+
+ // The ISchedulerCallback argument can be nullptr for a no-op implementation.
+ 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()};
+
+ if (hasMultipleModes) {
+ modes.emplace_back(DisplayMode::Builder(1)
+ .setId(DisplayModeId(1))
+ .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
+ .setVsyncPeriod(11'111'111)
+ .setGroup(0)
+ .build());
+ }
+
+ const auto currMode = DisplayModeId(0);
+ mRefreshRateConfigs = std::make_shared<scheduler::RefreshRateConfigs>(modes, currMode);
+ const auto currFps = mRefreshRateConfigs->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);
+
+ mScheduler = new scheduler::TestableScheduler(std::move(vsyncController),
+ std::move(vsyncTracker), mRefreshRateConfigs,
+ *(callback ?: this));
+
+ mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread));
+ mFlinger->mSfConnectionHandle = mScheduler->createConnection(std::move(sfEventThread));
+ resetScheduler(mScheduler);
+ }
+
+ void resetScheduler(scheduler::Scheduler *scheduler) { mFlinger->mScheduler.reset(scheduler); }
+
+ scheduler::TestableScheduler &mutableScheduler() const { return *mScheduler; }
+
+ using CreateBufferQueueFunction = surfaceflinger::test::Factory::CreateBufferQueueFunction;
+ void setCreateBufferQueueFunction(CreateBufferQueueFunction f) {
+ mFactory.mCreateBufferQueue = f;
+ }
+
+ using CreateNativeWindowSurfaceFunction =
+ surfaceflinger::test::Factory::CreateNativeWindowSurfaceFunction;
+ void setCreateNativeWindowSurface(CreateNativeWindowSurfaceFunction f) {
+ mFactory.mCreateNativeWindowSurface = f;
+ }
+
+ void setInternalDisplayPrimaries(const ui::DisplayPrimaries &primaries) {
+ memcpy(&mFlinger->mInternalDisplayPrimaries, &primaries, sizeof(ui::DisplayPrimaries));
+ }
+
+ static auto &mutableLayerDrawingState(const sp<Layer> &layer) { return layer->mDrawingState; }
+
+ auto &mutableStateLock() { return mFlinger->mStateLock; }
+
+ static auto findOutputLayerForDisplay(const sp<Layer> &layer,
+ const sp<const DisplayDevice> &display) {
+ return layer->findOutputLayerForDisplay(display.get());
+ }
+
+ /* ------------------------------------------------------------------------
+ * Forwarding for functions being tested
+ */
+
+ void enableHalVirtualDisplays(bool enable) { mFlinger->enableHalVirtualDisplays(enable); }
+
+ auto commitTransactionsLocked(uint32_t transactionFlags) {
+ Mutex::Autolock lock(mFlinger->mStateLock);
+ return mFlinger->commitTransactionsLocked(transactionFlags);
+ }
+
+ auto setDisplayStateLocked(const DisplayState &s) {
+ Mutex::Autolock lock(mFlinger->mStateLock);
+ return mFlinger->setDisplayStateLocked(s);
+ }
+
+ auto notifyPowerBoost(int32_t boostId) { return mFlinger->notifyPowerBoost(boostId); }
+
+ // 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 {
+ return mFlinger->setPowerModeInternal(display, mode);
+ }
+
+ auto onMessageReceived(int32_t /*what*/) { return 0; }
+
+ auto &getTransactionQueue() { return mFlinger->mTransactionQueue; }
+ auto &getPendingTransactionQueue() { return mFlinger->mPendingTransactionQueues; }
+
+ auto setTransactionState(
+ const FrameTimelineInfo &frameTimelineInfo, const Vector<ComposerState> &states,
+ const Vector<DisplayState> &displays, uint32_t flags, const sp<IBinder> &applyToken,
+ const InputWindowCommands &inputWindowCommands, int64_t desiredPresentTime,
+ bool isAutoTimestamp, const client_cache_t &uncacheBuffer, bool hasListenerCallbacks,
+ std::vector<ListenerCallbacks> &listenerCallbacks, uint64_t transactionId) {
+ return mFlinger->setTransactionState(frameTimelineInfo, states, displays, flags, applyToken,
+ inputWindowCommands, desiredPresentTime,
+ isAutoTimestamp, uncacheBuffer, hasListenerCallbacks,
+ listenerCallbacks, transactionId);
+ }
+
+ auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(0); };
+
+ auto onTransact(uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
+ return mFlinger->onTransact(code, data, reply, flags);
+ }
+
+ auto getGPUContextPriority() { return mFlinger->getGPUContextPriority(); }
+
+ auto calculateMaxAcquiredBufferCount(Fps refreshRate,
+ std::chrono::nanoseconds presentLatency) const {
+ return SurfaceFlinger::calculateMaxAcquiredBufferCount(refreshRate, presentLatency);
+ }
+
+ /* Read-write access to private data to set up preconditions and assert
+ * post-conditions.
+ */
+
+ auto &mutableCurrentState() { return mFlinger->mCurrentState; }
+ auto &mutableDisplays() { return mFlinger->mDisplays; }
+ auto &mutableDrawingState() { return mFlinger->mDrawingState; }
+ auto &mutableInterceptor() { return mFlinger->mInterceptor; }
+
+ auto fromHandle(const sp<IBinder> &handle) { return mFlinger->fromHandle(handle); }
+
+ ~TestableSurfaceFlinger() {
+ mutableDisplays().clear();
+ mutableCurrentState().displays.clear();
+ mutableDrawingState().displays.clear();
+ mutableInterceptor().clear();
+ mFlinger->mScheduler.reset();
+ mFlinger->mCompositionEngine->setHwComposer(std::unique_ptr<HWComposer>());
+ mFlinger->mCompositionEngine->setRenderEngine(
+ std::unique_ptr<renderengine::RenderEngine>());
+ }
+
+private:
+ void scheduleRefresh(FrameHint) {}
+ 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::TestableScheduler *mScheduler = nullptr;
+ std::shared_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs;
+};
+} // namespace android
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 bba880e..d649c62 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -21,6 +21,24 @@
default_applicable_licenses: ["frameworks_native_license"],
}
+filegroup {
+ name: "libsurfaceflinger_mock_sources",
+ srcs: [
+ "mock/DisplayHardware/MockComposer.cpp",
+ "mock/DisplayHardware/MockHWC2.cpp",
+ "mock/DisplayHardware/MockPowerAdvisor.cpp",
+ "mock/MockEventThread.cpp",
+ "mock/MockFrameTimeline.cpp",
+ "mock/MockFrameTracer.cpp",
+ "mock/MockNativeWindowSurface.cpp",
+ "mock/MockSurfaceInterceptor.cpp",
+ "mock/MockTimeStats.cpp",
+ "mock/MockVsyncController.cpp",
+ "mock/MockVSyncTracker.cpp",
+ "mock/system/window/MockNativeWindow.cpp",
+ ],
+}
+
cc_test {
name: "libsurfaceflinger_unittest",
defaults: [
@@ -45,6 +63,7 @@
address: true,
},
srcs: [
+ ":libsurfaceflinger_mock_sources",
":libsurfaceflinger_sources",
"libsurfaceflinger_unittest_main.cpp",
"CachingTest.cpp",
@@ -104,18 +123,6 @@
"VSyncPredictorTest.cpp",
"VSyncReactorTest.cpp",
"VsyncConfigurationTest.cpp",
- "mock/DisplayHardware/MockComposer.cpp",
- "mock/DisplayHardware/MockHWC2.cpp",
- "mock/DisplayHardware/MockPowerAdvisor.cpp",
- "mock/MockEventThread.cpp",
- "mock/MockFrameTimeline.cpp",
- "mock/MockFrameTracer.cpp",
- "mock/MockNativeWindowSurface.cpp",
- "mock/MockSurfaceInterceptor.cpp",
- "mock/MockTimeStats.cpp",
- "mock/MockVsyncController.cpp",
- "mock/MockVSyncTracker.cpp",
- "mock/system/window/MockNativeWindow.cpp",
],
static_libs: [
"android.hardware.common-V2-ndk",
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