Merge "BBQ: Fix log spam when creating a new BBQ"
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/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/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 038e23d..dd96683 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -119,16 +119,11 @@
if (needsDisconnect != nullptr) *needsDisconnect = disconnect;
}
-void BLASTBufferItemConsumer::setBlastBufferQueue(BLASTBufferQueue* blastbufferqueue) {
- std::scoped_lock lock(mBufferQueueMutex);
- mBLASTBufferQueue = blastbufferqueue;
-}
-
void BLASTBufferItemConsumer::onSidebandStreamChanged() {
- std::scoped_lock lock(mBufferQueueMutex);
- if (mBLASTBufferQueue != nullptr) {
+ sp<BLASTBufferQueue> bbq = mBLASTBufferQueue.promote();
+ if (bbq != nullptr) {
sp<NativeHandle> stream = getSidebandStream();
- mBLASTBufferQueue->setSidebandStream(stream);
+ bbq->setSidebandStream(stream);
}
}
@@ -148,7 +143,7 @@
mBufferItemConsumer = new BLASTBufferItemConsumer(mConsumer,
GraphicBuffer::USAGE_HW_COMPOSER |
GraphicBuffer::USAGE_HW_TEXTURE,
- 1, false);
+ 1, false, this);
static int32_t id = 0;
mName = name + "#" + std::to_string(id);
auto consumerName = mName + "(BLAST Consumer)" + std::to_string(id);
@@ -157,7 +152,6 @@
mBufferItemConsumer->setName(String8(consumerName.c_str()));
mBufferItemConsumer->setFrameAvailableListener(this);
mBufferItemConsumer->setBufferFreedListener(this);
- mBufferItemConsumer->setBlastBufferQueue(this);
ComposerService::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers);
mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers);
@@ -174,7 +168,6 @@
}
BLASTBufferQueue::~BLASTBufferQueue() {
- mBufferItemConsumer->setBlastBufferQueue(nullptr);
if (mPendingTransactions.empty()) {
return;
}
@@ -509,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);
@@ -624,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;
@@ -1027,7 +1019,6 @@
mBufferItemConsumer->abandon();
mBufferItemConsumer->setFrameAvailableListener(nullptr);
mBufferItemConsumer->setBufferFreedListener(nullptr);
- mBufferItemConsumer->setBlastBufferQueue(nullptr);
}
mBufferItemConsumer = nullptr;
mConsumer = nullptr;
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 7f73013..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 8b2310d..f77cfe6 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -38,11 +38,11 @@
class BLASTBufferItemConsumer : public BufferItemConsumer {
public:
BLASTBufferItemConsumer(const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage,
- int bufferCount, bool controlledByApp)
+ int bufferCount, bool controlledByApp, wp<BLASTBufferQueue> bbq)
: BufferItemConsumer(consumer, consumerUsage, bufferCount, controlledByApp),
+ mBLASTBufferQueue(std::move(bbq)),
mCurrentlyConnected(false),
- mPreviouslyConnected(false),
- mBLASTBufferQueue(nullptr) {}
+ mPreviouslyConnected(false) {}
void onDisconnect() override;
void addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
@@ -53,21 +53,20 @@
CompositorTiming compositorTiming, nsecs_t latchTime,
nsecs_t dequeueReadyTime) REQUIRES(mMutex);
void getConnectionEvents(uint64_t frameNumber, bool* needsDisconnect);
- void setBlastBufferQueue(BLASTBufferQueue* blastbufferqueue) REQUIRES(mMutex);
protected:
void onSidebandStreamChanged() override REQUIRES(mMutex);
private:
+ const wp<BLASTBufferQueue> mBLASTBufferQueue;
+
uint64_t mCurrentFrameNumber = 0;
Mutex mMutex;
- std::mutex mBufferQueueMutex;
ConsumerFrameEventHistory mFrameEventHistory GUARDED_BY(mMutex);
std::queue<uint64_t> mDisconnectEvents GUARDED_BY(mMutex);
bool mCurrentlyConnected GUARDED_BY(mMutex);
bool mPreviouslyConnected GUARDED_BY(mMutex);
- BLASTBufferQueue* mBLASTBufferQueue GUARDED_BY(mBufferQueueMutex);
};
class BLASTBufferQueue
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 2546e4c..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/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/Gralloc4.cpp b/libs/ui/Gralloc4.cpp
index 8ac08fb..3fc99bb 100644
--- a/libs/ui/Gralloc4.cpp
+++ b/libs/ui/Gralloc4.cpp
@@ -941,9 +941,10 @@
}
double allocationSizeKiB = static_cast<double>(allocationSize) / 1024;
- *outDump << "+ name:" << name << ", id:" << bufferId << ", size:" << allocationSizeKiB
- << "KiB, w/h:" << width << "x" << height << ", usage: 0x" << std::hex << usage
- << std::dec << ", req fmt:" << static_cast<int32_t>(pixelFormatRequested)
+ *outDump << "+ name:" << name << ", id:" << bufferId << ", size:" << std::fixed
+ << allocationSizeKiB << "KiB, w/h:" << width << "x" << height << ", usage: 0x"
+ << std::hex << usage << std::dec
+ << ", req fmt:" << static_cast<int32_t>(pixelFormatRequested)
<< ", fourcc/mod:" << pixelFormatFourCC << "/" << pixelFormatModifier
<< ", dataspace: 0x" << std::hex << static_cast<uint32_t>(dataspace) << std::dec
<< ", compressed: ";
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 469c9e6..ec58325 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -72,7 +72,6 @@
"libstatssocket",
"libutils",
"libui",
- "lib-platform-compat-native-api",
"server_configurable_flags",
],
static_libs: [
diff --git a/services/inputflinger/benchmarks/Android.bp b/services/inputflinger/benchmarks/Android.bp
index 902bd0d..75071d5 100644
--- a/services/inputflinger/benchmarks/Android.bp
+++ b/services/inputflinger/benchmarks/Android.bp
@@ -28,7 +28,6 @@
"libstatslog",
"libui",
"libutils",
- "lib-platform-compat-native-api",
],
static_libs: [
"libattestation",
diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp
index 4757d31..cdad9c9 100644
--- a/services/inputflinger/dispatcher/Android.bp
+++ b/services/inputflinger/dispatcher/Android.bp
@@ -66,7 +66,6 @@
"libui",
"libgui",
"libutils",
- "lib-platform-compat-native-api",
"server_configurable_flags",
],
static_libs: [
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index f190f67..3f3c0db 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -24,8 +24,6 @@
#include <android-base/stringprintf.h>
#include <android/os/IInputConstants.h>
#include <binder/Binder.h>
-#include <binder/IServiceManager.h>
-#include <com/android/internal/compat/IPlatformCompatNative.h>
#include <ftl/enum.h>
#include <gui/SurfaceComposerClient.h>
#include <input/InputDevice.h>
@@ -63,7 +61,6 @@
using android::os::IInputConstants;
using android::os::InputEventInjectionResult;
using android::os::InputEventInjectionSync;
-using com::android::internal::compat::IPlatformCompatNative;
namespace android::inputdispatcher {
@@ -411,15 +408,6 @@
return *lhs == *rhs;
}
-sp<IPlatformCompatNative> getCompatService() {
- sp<IBinder> service(defaultServiceManager()->getService(String16("platform_compat_native")));
- if (service == nullptr) {
- ALOGE("Failed to link to compat service");
- return nullptr;
- }
- return interface_cast<IPlatformCompatNative>(service);
-}
-
KeyEvent createKeyEvent(const KeyEntry& entry) {
KeyEvent event;
event.initialize(entry.id, entry.deviceId, entry.source, entry.displayId, INVALID_HMAC,
@@ -570,8 +558,7 @@
mFocusedDisplayId(ADISPLAY_ID_DEFAULT),
mWindowTokenWithPointerCapture(nullptr),
mLatencyAggregator(),
- mLatencyTracker(&mLatencyAggregator),
- mCompatService(getCompatService()) {
+ mLatencyTracker(&mLatencyAggregator) {
mLooper = new Looper(false);
mReporter = createInputReporter();
@@ -4812,18 +4799,6 @@
ALOGD("Window went away: %s", oldWindowHandle->getName().c_str());
}
oldWindowHandle->releaseChannel();
- // To avoid making too many calls into the compat framework, only
- // check for window flags when windows are going away.
- // TODO(b/157929241) : delete this. This is only needed temporarily
- // in order to gather some data about the flag usage
- if (oldWindowHandle->getInfo()->flags.test(WindowInfo::Flag::SLIPPERY)) {
- ALOGW("%s has FLAG_SLIPPERY. Please report this in b/157929241",
- oldWindowHandle->getName().c_str());
- if (mCompatService != nullptr) {
- mCompatService->reportChangeByUid(IInputConstants::BLOCK_FLAG_SLIPPERY,
- oldWindowHandle->getInfo()->ownerUid);
- }
- }
}
}
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index ee50ec5..cbb7bad 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -36,7 +36,6 @@
#include "TouchedWindow.h"
#include <attestation/HmacKeyManager.h>
-#include <com/android/internal/compat/IPlatformCompatNative.h>
#include <gui/InputApplication.h>
#include <gui/WindowInfo.h>
#include <input/Input.h>
@@ -679,7 +678,6 @@
void traceWaitQueueLength(const Connection& connection);
sp<InputReporterInterface> mReporter;
- sp<com::android::internal::compat::IPlatformCompatNative> mCompatService;
};
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 269bdab..09a62f3 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -1262,12 +1262,11 @@
bool EventHub::setKeyboardLayoutOverlay(int32_t deviceId, std::shared_ptr<KeyCharacterMap> map) {
std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device != nullptr && map != nullptr && device->keyMap.keyCharacterMap != nullptr) {
- device->keyMap.keyCharacterMap->combine(*map);
- device->keyMap.keyCharacterMapFile = device->keyMap.keyCharacterMap->getLoadFileName();
- return true;
+ if (device == nullptr || map == nullptr || device->keyMap.keyCharacterMap == nullptr) {
+ return false;
}
- return false;
+ device->keyMap.keyCharacterMap->combine(*map);
+ return true;
}
static std::string generateDescriptor(InputDeviceIdentifier& identifier) {
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 41ce116..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;
@@ -2321,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;
};
@@ -2331,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);
}
@@ -2353,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);
@@ -2360,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();
@@ -2391,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);
@@ -2399,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);
@@ -2412,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);
@@ -6640,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);
@@ -6701,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);
@@ -6777,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);
@@ -6807,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);
@@ -6954,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);
@@ -6996,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);
@@ -7042,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);
@@ -7062,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);
@@ -7128,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);
@@ -7169,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);
@@ -7211,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);
@@ -7232,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);
@@ -7398,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));
@@ -8529,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,
@@ -8540,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.
@@ -8606,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,
@@ -8617,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.
@@ -8706,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,
@@ -8716,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.
@@ -8791,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.
@@ -8801,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.
@@ -8914,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..b907478
--- /dev/null
+++ b/services/sensorservice/AidlSensorHalWrapper.cpp
@@ -0,0 +1,672 @@
+/*
+ * 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,
+ };
+
+ 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 ee621d6..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;
}
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/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 73770b7..6cb12dd 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -173,6 +173,8 @@
// Sets the projection state to use
virtual void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
const Rect& orientedDisplaySpaceRect) = 0;
+ // Sets the brightness that will take effect next frame.
+ virtual void setNextBrightness(float brightness) = 0;
// Sets the bounds to use
virtual void setDisplaySize(const ui::Size&) = 0;
// Gets the transform hint used in layers that belong to this output. Used to guide
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 844876a..a7a8e97 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -45,6 +45,7 @@
void setLayerCachingTexturePoolEnabled(bool) override;
void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
const Rect& orientedDisplaySpaceRect) override;
+ void setNextBrightness(float brightness) override;
void setDisplaySize(const ui::Size&) override;
void setLayerFilter(ui::LayerFilter) override;
ui::Transform::RotationFlags getTransformHint() const override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index c8f177b..cc7c257 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -133,6 +133,10 @@
// White point of the client target
float clientTargetWhitePointNits{-1.f};
+ // Display brightness that will take effect this frame.
+ // This is slightly distinct from nits, in that nits cannot be passed to hw composer.
+ std::optional<float> displayBrightness = std::nullopt;
+
// Debugging
void dump(std::string& result) const;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 7b0d028..b68b95d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -39,6 +39,7 @@
MOCK_METHOD1(setLayerCachingEnabled, void(bool));
MOCK_METHOD1(setLayerCachingTexturePoolEnabled, void(bool));
MOCK_METHOD3(setProjection, void(ui::Rotation, const Rect&, const Rect&));
+ MOCK_METHOD1(setNextBrightness, void(float));
MOCK_METHOD1(setDisplaySize, void(const ui::Size&));
MOCK_CONST_METHOD0(getTransformHint, ui::Transform::RotationFlags());
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 08dd22d..186e191 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -226,6 +226,17 @@
// Get any composition changes requested by the HWC device, and apply them.
std::optional<android::HWComposer::DeviceRequestedChanges> changes;
auto& hwc = getCompositionEngine().getHwComposer();
+ if (const auto physicalDisplayId = PhysicalDisplayId::tryCast(*halDisplayId);
+ physicalDisplayId && getState().displayBrightness) {
+ const status_t result =
+ hwc.setDisplayBrightness(*physicalDisplayId, *getState().displayBrightness,
+ Hwc2::Composer::DisplayBrightnessOptions{
+ .applyImmediately = false})
+ .get();
+ ALOGE_IF(result != NO_ERROR, "setDisplayBrightness failed for %s: %d, (%s)",
+ getName().c_str(), result, strerror(-result));
+ }
+
if (status_t result =
hwc.getDeviceCompositionChanges(*halDisplayId, anyLayersRequireClientComposition(),
getState().earliestPresentTime,
@@ -248,6 +259,8 @@
auto& state = editState();
state.usesClientComposition = anyLayersRequireClientComposition();
state.usesDeviceComposition = !allLayersRequireClientComposition();
+ // Clear out the display brightness now that it's been communicated to composer.
+ state.displayBrightness.reset();
}
bool Display::getSkipColorTransform() const {
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 6833584..192ee04 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -197,6 +197,10 @@
dirtyEntireOutput();
}
+void Output::setNextBrightness(float brightness) {
+ editState().displayBrightness = brightness;
+}
+
void Output::setDisplaySize(const ui::Size& size) {
mRenderSurface->setDisplaySize(size);
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 8558a80..7dd4c21 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -37,6 +37,7 @@
#include "MockHWC2.h"
#include "MockHWComposer.h"
#include "MockPowerAdvisor.h"
+#include "ftl/future.h"
#include <aidl/android/hardware/graphics/composer3/Composition.h>
@@ -48,6 +49,7 @@
namespace hal = android::hardware::graphics::composer::hal;
using testing::_;
+using testing::ByMove;
using testing::DoAll;
using testing::Eq;
using testing::InSequence;
@@ -594,6 +596,38 @@
EXPECT_TRUE(state.usesDeviceComposition);
}
+TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithDisplayBrightness) {
+ // Since two calls are made to anyLayersRequireClientComposition with different return
+ // values, use a Sequence to control the matching so the values are returned in a known
+ // order.
+ constexpr float kDisplayBrightness = 0.5f;
+ Sequence s;
+ EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition())
+ .InSequence(s)
+ .WillOnce(Return(true));
+ EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition())
+ .InSequence(s)
+ .WillOnce(Return(false));
+ EXPECT_CALL(mHwComposer,
+ setDisplayBrightness(DEFAULT_DISPLAY_ID, kDisplayBrightness,
+ Hwc2::Composer::DisplayBrightnessOptions{.applyImmediately =
+ false}))
+ .WillOnce(Return(ByMove(ftl::yield<status_t>(NO_ERROR))));
+
+ EXPECT_CALL(mHwComposer,
+ getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _))
+ .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false));
+
+ mDisplay->setNextBrightness(kDisplayBrightness);
+ mDisplay->chooseCompositionStrategy();
+
+ auto& state = mDisplay->getState();
+ EXPECT_FALSE(state.usesClientComposition);
+ EXPECT_TRUE(state.usesDeviceComposition);
+ EXPECT_FALSE(state.displayBrightness.has_value());
+}
+
TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) {
android::HWComposer::DeviceRequestedChanges changes{
{{nullptr, Composition::CLIENT}},
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index a590e2a..dc5c5c8 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -83,7 +83,9 @@
MOCK_METHOD4(setDisplayContentSamplingEnabled, status_t(HalDisplayId, bool, uint8_t, uint64_t));
MOCK_METHOD4(getDisplayedContentSample,
status_t(HalDisplayId, uint64_t, uint64_t, DisplayedFrameStats*));
- MOCK_METHOD2(setDisplayBrightness, std::future<status_t>(PhysicalDisplayId, float));
+ MOCK_METHOD3(setDisplayBrightness,
+ std::future<status_t>(PhysicalDisplayId, float,
+ const Hwc2::Composer::DisplayBrightnessOptions&));
MOCK_METHOD2(getDisplayBrightnessSupport, status_t(PhysicalDisplayId, bool*));
MOCK_METHOD2(onHotplug,
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
index db4151b..50adcfb 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
@@ -39,11 +39,10 @@
MOCK_METHOD(bool, supportsPowerHintSession, (), (override));
MOCK_METHOD(bool, isPowerHintSessionRunning, (), (override));
MOCK_METHOD(void, setTargetWorkDuration, (int64_t targetDurationNanos), (override));
- MOCK_METHOD(void, setPowerHintSessionThreadIds, (const std::vector<int32_t>& threadIds),
- (override));
MOCK_METHOD(void, sendActualWorkDuration, (int64_t actualDurationNanos, nsecs_t timestamp),
(override));
MOCK_METHOD(void, enablePowerHint, (bool enabled), (override));
+ MOCK_METHOD(bool, startPowerHintSession, (const std::vector<int32_t>& threadIds), (override));
};
} // namespace mock
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 6d96260..f7c7533 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -574,6 +574,17 @@
EXPECT_EQ(Rect(newDisplaySize), mOutput->getState().framebufferSpace.getBoundsAsRect());
}
+/**
+ * Output::setDisplayBrightness()
+ */
+
+TEST_F(OutputTest, setNextBrightness) {
+ constexpr float kDisplayBrightness = 0.5f;
+ mOutput->setNextBrightness(kDisplayBrightness);
+ ASSERT_TRUE(mOutput->getState().displayBrightness.has_value());
+ EXPECT_EQ(kDisplayBrightness, mOutput->getState().displayBrightness);
+}
+
/*
* Output::getDirtyRegion()
*/
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 76bbe2c..a36ea72 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -311,6 +311,22 @@
orientedDisplaySpaceRect);
}
+void DisplayDevice::stageBrightness(float brightness) {
+ mStagedBrightness = brightness;
+}
+
+void DisplayDevice::persistBrightness(bool needsComposite) {
+ if (needsComposite && mStagedBrightness && mBrightness != *mStagedBrightness) {
+ getCompositionDisplay()->setNextBrightness(*mStagedBrightness);
+ mBrightness = *mStagedBrightness;
+ }
+ mStagedBrightness = std::nullopt;
+}
+
+std::optional<float> DisplayDevice::getStagedBrightness() const {
+ return mStagedBrightness;
+}
+
ui::Transform::RotationFlags DisplayDevice::getPrimaryDisplayRotationFlags() {
return sPrimaryDisplayRotationFlags;
}
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 324145e..d2accaa 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -99,6 +99,9 @@
void setLayerStack(ui::LayerStack);
void setDisplaySize(int width, int height);
void setProjection(ui::Rotation orientation, Rect viewport, Rect frame);
+ void stageBrightness(float brightness) REQUIRES(SF_MAIN_THREAD);
+ void persistBrightness(bool needsComposite) REQUIRES(SF_MAIN_THREAD);
+ bool isBrightnessStale() const REQUIRES(SF_MAIN_THREAD);
void setFlags(uint32_t flags);
ui::Rotation getPhysicalOrientation() const { return mPhysicalOrientation; }
@@ -106,6 +109,7 @@
static ui::Transform::RotationFlags getPrimaryDisplayRotationFlags();
+ std::optional<float> getStagedBrightness() const REQUIRES(SF_MAIN_THREAD);
ui::Transform::RotationFlags getTransformHint() const;
const ui::Transform& getTransform() const;
const Rect& getLayerStackSpaceRect() const;
@@ -271,6 +275,8 @@
hardware::graphics::composer::hal::PowerMode mPowerMode =
hardware::graphics::composer::hal::PowerMode::OFF;
DisplayModePtr mActiveMode;
+ std::optional<float> mStagedBrightness = std::nullopt;
+ float mBrightness = -1.f;
const DisplayModes mSupportedModes;
std::atomic<nsecs_t> mLastHwVsync = 0;
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index 1091a75..34f5a39 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -246,6 +246,7 @@
switch (feature) {
case OptionalFeature::RefreshRateSwitching:
case OptionalFeature::ExpectedPresentTime:
+ case OptionalFeature::DisplayBrightnessCommand:
return true;
}
}
@@ -906,13 +907,24 @@
return Error::NONE;
}
-Error AidlComposer::setDisplayBrightness(Display display, float brightness) {
- const auto status =
- mAidlComposerClient->setDisplayBrightness(translate<int64_t>(display), brightness);
- if (!status.isOk()) {
- ALOGE("setDisplayBrightness failed %s", status.getDescription().c_str());
- return static_cast<Error>(status.getServiceSpecificError());
+Error AidlComposer::setDisplayBrightness(Display display, float brightness,
+ const DisplayBrightnessOptions& options) {
+ if (!options.sdrDimmingEnabled) {
+ const auto status =
+ mAidlComposerClient->setDisplayBrightness(translate<int64_t>(display), brightness);
+ if (!status.isOk()) {
+ ALOGE("setDisplayBrightness failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ return Error::NONE;
}
+
+ mWriter.setDisplayBrightness(translate<int64_t>(display), brightness);
+
+ if (options.applyImmediately) {
+ return execute();
+ }
+
return Error::NONE;
}
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
index 5c41982..c720932 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
@@ -180,7 +180,8 @@
Error setLayerPerFrameMetadataBlobs(
Display display, Layer layer,
const std::vector<IComposerClient::PerFrameMetadataBlob>& metadata) override;
- Error setDisplayBrightness(Display display, float brightness) override;
+ Error setDisplayBrightness(Display display, float brightness,
+ const DisplayBrightnessOptions& options) override;
// Composer HAL 2.4
Error getDisplayCapabilities(
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index f491a00..e492997 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -78,6 +78,8 @@
enum class OptionalFeature {
RefreshRateSwitching,
ExpectedPresentTime,
+ // Whether setDisplayBrightness is able to be applied as part of a display command.
+ DisplayBrightnessCommand,
};
virtual bool isSupported(OptionalFeature) const = 0;
@@ -204,7 +206,22 @@
DisplayedFrameStats* outStats) = 0;
virtual Error setLayerPerFrameMetadataBlobs(
Display display, Layer layer, const std::vector<PerFrameMetadataBlob>& metadata) = 0;
- virtual Error setDisplayBrightness(Display display, float brightness) = 0;
+ // Options for setting the display brightness
+ struct DisplayBrightnessOptions {
+ // If true, then immediately submits a brightness change request to composer. Otherwise,
+ // submission of the brightness change may be deferred until presenting the next frame.
+ // applyImmediately should only be false if OptionalFeature::DisplayBrightnessCommand is
+ // supported.
+ bool applyImmediately = true;
+ bool sdrDimmingEnabled = true;
+
+ bool operator==(const DisplayBrightnessOptions& other) const {
+ return applyImmediately == other.applyImmediately &&
+ sdrDimmingEnabled == other.sdrDimmingEnabled;
+ }
+ };
+ virtual Error setDisplayBrightness(Display display, float brightness,
+ const DisplayBrightnessOptions& options) = 0;
// Composer HAL 2.4
virtual Error getDisplayCapabilities(
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 548d839..22479d8 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -37,8 +37,6 @@
#include <iterator>
#include <set>
-#include "ComposerHal.h"
-
using aidl::android::hardware::graphics::composer3::Composition;
using aidl::android::hardware::graphics::composer3::DisplayCapability;
@@ -532,9 +530,10 @@
return error;
}
-std::future<Error> Display::setDisplayBrightness(float brightness) {
- return ftl::defer([composer = &mComposer, id = mId, brightness] {
- const auto intError = composer->setDisplayBrightness(id, brightness);
+std::future<Error> Display::setDisplayBrightness(
+ float brightness, const Hwc2::Composer::DisplayBrightnessOptions& options) {
+ return ftl::defer([composer = &mComposer, id = mId, brightness, options] {
+ const auto intError = composer->setDisplayBrightness(id, brightness, options);
return static_cast<Error>(intError);
});
}
@@ -584,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 {
@@ -674,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);
}
@@ -870,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/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 731d7f6..df4e4b8 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -34,6 +34,7 @@
#include <unordered_set>
#include <vector>
+#include "ComposerHal.h"
#include "Hal.h"
#include <aidl/android/hardware/graphics/composer3/Composition.h>
@@ -143,7 +144,7 @@
nsecs_t expectedPresentTime, uint32_t* outNumTypes, uint32_t* outNumRequests,
android::sp<android::Fence>* outPresentFence, uint32_t* state) = 0;
[[clang::warn_unused_result]] virtual std::future<hal::Error> setDisplayBrightness(
- float brightness) = 0;
+ float brightness, const Hwc2::Composer::DisplayBrightnessOptions& options) = 0;
[[clang::warn_unused_result]] virtual hal::Error setActiveConfigWithConstraints(
hal::HWConfigId configId, const hal::VsyncPeriodChangeConstraints& constraints,
hal::VsyncPeriodChangeTimeline* outTimeline) = 0;
@@ -211,7 +212,8 @@
uint32_t* outNumRequests,
android::sp<android::Fence>* outPresentFence,
uint32_t* state) override;
- std::future<hal::Error> setDisplayBrightness(float brightness) override;
+ std::future<hal::Error> setDisplayBrightness(
+ float brightness, const Hwc2::Composer::DisplayBrightnessOptions& options) override;
hal::Error setActiveConfigWithConstraints(hal::HWConfigId configId,
const hal::VsyncPeriodChangeConstraints& constraints,
hal::VsyncPeriodChangeTimeline* outTimeline) override;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 546e677..057db46 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -782,12 +782,13 @@
return NO_ERROR;
}
-std::future<status_t> HWComposer::setDisplayBrightness(PhysicalDisplayId displayId,
- float brightness) {
+std::future<status_t> HWComposer::setDisplayBrightness(
+ PhysicalDisplayId displayId, float brightness,
+ const Hwc2::Composer::DisplayBrightnessOptions& options) {
RETURN_IF_INVALID_DISPLAY(displayId, ftl::yield<status_t>(BAD_INDEX));
auto& display = mDisplayData[displayId].hwcDisplay;
- return ftl::chain(display->setDisplayBrightness(brightness))
+ return ftl::chain(display->setDisplayBrightness(brightness, options))
.then([displayId](hal::Error error) -> status_t {
if (error == hal::Error::UNSUPPORTED) {
RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 69adfcd..4fae06d 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -192,7 +192,9 @@
DisplayedFrameStats* outStats) = 0;
// Sets the brightness of a display.
- virtual std::future<status_t> setDisplayBrightness(PhysicalDisplayId, float brightness) = 0;
+ virtual std::future<status_t> setDisplayBrightness(
+ PhysicalDisplayId, float brightness,
+ const Hwc2::Composer::DisplayBrightnessOptions&) = 0;
// Events handling ---------------------------------------------------------
@@ -340,7 +342,9 @@
uint64_t maxFrames) override;
status_t getDisplayedContentSample(HalDisplayId, uint64_t maxFrames, uint64_t timestamp,
DisplayedFrameStats* outStats) override;
- std::future<status_t> setDisplayBrightness(PhysicalDisplayId, float brightness) override;
+ std::future<status_t> setDisplayBrightness(
+ PhysicalDisplayId, float brightness,
+ const Hwc2::Composer::DisplayBrightnessOptions&) override;
// Events handling ---------------------------------------------------------
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/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index 7946002..b884755 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -161,6 +161,7 @@
case OptionalFeature::RefreshRateSwitching:
return mClient_2_4 != nullptr;
case OptionalFeature::ExpectedPresentTime:
+ case OptionalFeature::DisplayBrightnessCommand:
return false;
}
}
@@ -1013,7 +1014,8 @@
return Error::NONE;
}
-Error HidlComposer::setDisplayBrightness(Display display, float brightness) {
+Error HidlComposer::setDisplayBrightness(Display display, float brightness,
+ const DisplayBrightnessOptions&) {
if (!mClient_2_3) {
return Error::UNSUPPORTED;
}
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
index 3b62fe0..6c8af5d 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
@@ -289,7 +289,8 @@
Error setLayerPerFrameMetadataBlobs(
Display display, Layer layer,
const std::vector<IComposerClient::PerFrameMetadataBlob>& metadata) override;
- Error setDisplayBrightness(Display display, float brightness) override;
+ Error setDisplayBrightness(Display display, float brightness,
+ const DisplayBrightnessOptions& options) override;
// Composer HAL 2.4
Error getDisplayCapabilities(
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 89f3bd6..58fe0ac 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -721,7 +721,6 @@
ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
mFlagManager = std::make_unique<android::FlagManager>();
- mPowerAdvisor.enablePowerHint(mFlagManager->use_adpf_cpu_hint());
mFrameTracer->initialize();
mFrameTimeline->onBootFinished();
@@ -751,7 +750,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)) {
@@ -1669,6 +1679,17 @@
return NO_ERROR;
}
+bool SurfaceFlinger::hasVisibleHdrLayer(const sp<DisplayDevice>& display) {
+ bool hasHdrLayers = false;
+ mDrawingState.traverse([&,
+ compositionDisplay = display->getCompositionDisplay()](Layer* layer) {
+ hasHdrLayers |= (layer->isVisible() &&
+ compositionDisplay->includesLayer(layer->getCompositionEngineLayerFE()) &&
+ isHdrDataspace(layer->getDataSpace()));
+ });
+ return hasHdrLayers;
+}
+
status_t SurfaceFlinger::setDisplayBrightness(const sp<IBinder>& displayToken,
const gui::DisplayBrightness& brightness) {
if (!displayToken) {
@@ -1678,13 +1699,33 @@
const char* const whence = __func__;
return ftl::chain(mScheduler->schedule([=]() MAIN_THREAD {
if (const auto display = getDisplayDeviceLocked(displayToken)) {
- if (enableSdrDimming) {
+ const bool supportsDisplayBrightnessCommand =
+ getHwComposer().getComposer()->isSupported(
+ Hwc2::Composer::OptionalFeature::DisplayBrightnessCommand);
+ // If we support applying display brightness as a command, then we also support
+ // dimming SDR layers.
+ // TODO(b/212634488): Once AIDL composer implementations are finalized, remove
+ // the enableSdrDimming check, as dimming support will be expected for AIDL
+ // composer.
+ if (enableSdrDimming && supportsDisplayBrightnessCommand) {
display->getCompositionDisplay()
->setDisplayBrightness(brightness.sdrWhitePointNits,
brightness.displayBrightnessNits);
+ MAIN_THREAD_GUARD(display->stageBrightness(brightness.displayBrightness));
+ if (hasVisibleHdrLayer(display)) {
+ scheduleComposite(FrameHint::kNone);
+ } else {
+ scheduleCommit(FrameHint::kNone);
+ }
+ return ftl::yield<status_t>(OK);
+ } else {
+ return getHwComposer().setDisplayBrightness(
+ display->getPhysicalId(), brightness.displayBrightness,
+ Hwc2::Composer::DisplayBrightnessOptions{.applyImmediately = true,
+ .sdrDimmingEnabled =
+ enableSdrDimming});
}
- return getHwComposer().setDisplayBrightness(display->getPhysicalId(),
- brightness.displayBrightness);
+
} else {
ALOGE("%s: Invalid display token %p", whence, displayToken.get());
return ftl::yield<status_t>(NAME_NOT_FOUND);
@@ -1748,6 +1789,23 @@
return NO_ERROR;
}
+status_t SurfaceFlinger::getDisplayDecorationSupport(const sp<IBinder>& displayToken,
+ bool* outSupport) const {
+ if (!displayToken || !outSupport) {
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock lock(mStateLock);
+
+ const auto displayId = getPhysicalDisplayIdLocked(displayToken);
+ if (!displayId) {
+ return NAME_NOT_FOUND;
+ }
+ *outSupport =
+ getHwComposer().hasDisplayCapability(*displayId, DisplayCapability::DISPLAY_DECORATION);
+ return NO_ERROR;
+}
+
// ----------------------------------------------------------------------------
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
@@ -1922,6 +1980,13 @@
}
bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime) {
+ MainThreadScopedGuard mainThreadGuard(SF_MAIN_THREAD);
+ // we set this once at the beginning of commit to ensure consistency throughout the whole frame
+ mPowerHintSessionData.sessionEnabled = mPowerAdvisor.usePowerHintSession();
+ if (mPowerHintSessionData.sessionEnabled) {
+ mPowerHintSessionData.commitStart = systemTime();
+ }
+
// calculate the expected present time once and use the cached
// value throughout this frame to make sure all layers are
// seeing this same value.
@@ -1935,6 +2000,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;
@@ -2069,11 +2138,17 @@
updateCursorAsync();
updateInputFlinger();
+ MAIN_THREAD_GUARD(persistDisplayBrightness(mustComposite));
+
return mustComposite && CC_LIKELY(mBootStage != BootStage::BOOTLOADER);
}
void SurfaceFlinger::composite(nsecs_t frameTime) {
ATRACE_CALL();
+ MainThreadScopedGuard mainThreadGuard(SF_MAIN_THREAD);
+ if (mPowerHintSessionData.sessionEnabled) {
+ mPowerHintSessionData.compositeStart = systemTime();
+ }
compositionengine::CompositionRefreshArgs refreshArgs;
const auto& displays = ON_MAIN_THREAD(mDisplays);
@@ -2127,6 +2202,11 @@
const auto presentTime = systemTime();
mCompositionEngine->present(refreshArgs);
+
+ if (mPowerHintSessionData.sessionEnabled) {
+ mPowerHintSessionData.presentEnd = systemTime();
+ }
+
mTimeStats->recordFrameDuration(frameTime, systemTime());
mScheduler->onPostComposition(presentTime);
@@ -2174,6 +2254,13 @@
if (mCompositionEngine->needsAnotherUpdate()) {
scheduleCommit(FrameHint::kNone);
}
+
+ // calculate total render time for performance hinting if adpf cpu hint is enabled,
+ if (mPowerHintSessionData.sessionEnabled) {
+ const nsecs_t flingerDuration =
+ (mPowerHintSessionData.presentEnd - mPowerHintSessionData.commitStart);
+ mPowerAdvisor.sendActualWorkDuration(flingerDuration, mPowerHintSessionData.presentEnd);
+ }
}
void SurfaceFlinger::updateLayerGeometry() {
@@ -3101,43 +3188,91 @@
mInputWindowCommands.clear();
}
+void SurfaceFlinger::persistDisplayBrightness(bool needsComposite) {
+ const bool supportsDisplayBrightnessCommand = getHwComposer().getComposer()->isSupported(
+ Hwc2::Composer::OptionalFeature::DisplayBrightnessCommand);
+ if (!supportsDisplayBrightnessCommand) {
+ return;
+ }
+
+ const auto& displays = ON_MAIN_THREAD(mDisplays);
+
+ for (const auto& [_, display] : displays) {
+ if (const auto brightness = display->getStagedBrightness(); brightness) {
+ if (!needsComposite) {
+ const status_t error =
+ getHwComposer()
+ .setDisplayBrightness(display->getPhysicalId(), *brightness,
+ Hwc2::Composer::DisplayBrightnessOptions{
+ .applyImmediately = true})
+ .get();
+
+ ALOGE_IF(error != NO_ERROR,
+ "Error setting display brightness for display %s: %d (%s)",
+ display->getDebugName().c_str(), error, strerror(error));
+ }
+ display->persistBrightness(needsComposite);
+ }
+ }
+}
+
void SurfaceFlinger::buildWindowInfos(std::vector<WindowInfo>& outWindowInfos,
std::vector<DisplayInfo>& outDisplayInfos) {
- 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() {
@@ -5339,6 +5474,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 e1b52c5..d64956c 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -594,6 +594,8 @@
status_t notifyPowerBoost(int32_t boostId) override;
status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
float lightPosY, float lightPosZ, float lightRadius) override;
+ status_t getDisplayDecorationSupport(const sp<IBinder>& displayToken,
+ bool* outSupport) const override;
status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
int8_t compatibility, int8_t changeFrameRateStrategy) override;
@@ -674,6 +676,9 @@
void setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode)
REQUIRES(mStateLock);
+ // Returns true if the display has a visible HDR layer in its layer stack.
+ bool hasVisibleHdrLayer(const sp<DisplayDevice>& display) REQUIRES(mStateLock);
+
// Sets the desired display mode specs.
status_t setDesiredDisplayModeSpecsInternal(
const sp<DisplayDevice>& display,
@@ -690,6 +695,7 @@
void updateLayerGeometry();
void updateInputFlinger();
+ void persistDisplayBrightness(bool needsComposite) REQUIRES(SF_MAIN_THREAD);
void buildWindowInfos(std::vector<gui::WindowInfo>& outWindowInfos,
std::vector<gui::DisplayInfo>& outDisplayInfos);
void commitInputWindowCommands() REQUIRES(mStateLock);
@@ -1357,6 +1363,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/tests/ReleaseBufferCallback_test.cpp b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
index f6b0def..027a15e 100644
--- a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
+++ b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
@@ -85,7 +85,7 @@
sp<Fence> fence, CallbackHelper& callback, const ReleaseCallbackId& id,
ReleaseBufferCallbackHelper& releaseCallback) {
Transaction t;
- t.setBuffer(layer, buffer, fence, id.framenumber, id, releaseCallback.getCallback());
+ t.setBuffer(layer, buffer, fence, id.framenumber, releaseCallback.getCallback());
t.addTransactionCompletedCallback(callback.function, callback.getContext());
t.apply();
}
@@ -300,7 +300,7 @@
nsecs_t time = systemTime() + std::chrono::nanoseconds(100ms).count();
Transaction t;
- t.setBuffer(layer, firstBuffer, std::nullopt, std::nullopt, firstBufferCallbackId,
+ t.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber,
releaseCallback->getCallback());
t.addTransactionCompletedCallback(transactionCallback.function,
transactionCallback.getContext());
@@ -316,7 +316,7 @@
// Dropping frames in transaction queue emits a callback
sp<GraphicBuffer> secondBuffer = getBuffer();
ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber());
- t.setBuffer(layer, secondBuffer, std::nullopt, std::nullopt, secondBufferCallbackId,
+ t.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber,
releaseCallback->getCallback());
t.addTransactionCompletedCallback(transactionCallback.function,
transactionCallback.getContext());
@@ -360,7 +360,7 @@
Transaction transaction1;
transaction1.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber,
- secondBufferCallbackId, releaseCallback->getCallback());
+ releaseCallback->getCallback());
transaction1.addTransactionCompletedCallback(callback1.function, callback1.getContext());
// Set a different TransactionCompletedListener to mimic a second process
@@ -395,14 +395,14 @@
// Create transaction with a buffer.
Transaction transaction;
transaction.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber,
- firstBufferCallbackId, releaseCallback->getCallback());
+ releaseCallback->getCallback());
sp<GraphicBuffer> secondBuffer = getBuffer();
ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber());
// Call setBuffer on the same transaction with a different buffer.
transaction.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber,
- secondBufferCallbackId, releaseCallback->getCallback());
+ releaseCallback->getCallback());
ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId));
}
@@ -417,7 +417,7 @@
// Create transaction with a buffer.
Transaction transaction1;
transaction1.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber,
- firstBufferCallbackId, releaseCallback->getCallback());
+ releaseCallback->getCallback());
sp<GraphicBuffer> secondBuffer = getBuffer();
ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber());
@@ -425,7 +425,7 @@
// Create a second transaction with a new buffer for the same layer.
Transaction transaction2;
transaction2.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber,
- secondBufferCallbackId, releaseCallback->getCallback());
+ releaseCallback->getCallback());
// merge transaction1 into transaction2 so ensure we get a proper buffer release callback.
transaction1.merge(std::move(transaction2));
@@ -446,7 +446,7 @@
Transaction transaction1;
transaction1.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber,
- firstBufferCallbackId, releaseCallback->getCallback());
+ releaseCallback->getCallback());
// Sent a second buffer to allow the first buffer to get released.
sp<GraphicBuffer> secondBuffer = getBuffer();
@@ -454,7 +454,7 @@
Transaction transaction2;
transaction2.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber,
- secondBufferCallbackId, releaseCallback->getCallback());
+ releaseCallback->getCallback());
// Set a different TransactionCompletedListener to mimic a second process
TransactionCompletedListener::setInstance(secondCompletedListener);
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 5568418..bba880e 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -55,6 +55,7 @@
"DisplayTransactionTest.cpp",
"DisplayDevice_GetBestColorModeTest.cpp",
"DisplayDevice_InitiateModeChange.cpp",
+ "DisplayDevice_SetDisplayBrightnessTest.cpp",
"DisplayDevice_SetProjectionTest.cpp",
"EventThreadTest.cpp",
"FlagManagerTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp
new file mode 100644
index 0000000..73c60e1
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include "DisplayTransactionTestHelpers.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace {
+
+using hal::RenderIntent;
+
+using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
+
+class SetDisplayBrightnessTest : public DisplayTransactionTest {
+public:
+ sp<DisplayDevice> getDisplayDevice() { return injectDefaultInternalDisplay({}); }
+};
+
+TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessNoComposite) {
+ MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD);
+ sp<DisplayDevice> displayDevice = getDisplayDevice();
+
+ EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
+
+ constexpr float kDisplayBrightness = 0.5f;
+ displayDevice->stageBrightness(kDisplayBrightness);
+
+ EXPECT_EQ(0.5f, displayDevice->getStagedBrightness());
+
+ displayDevice->persistBrightness(false);
+
+ EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
+ EXPECT_EQ(std::nullopt, displayDevice->getCompositionDisplay()->getState().displayBrightness);
+}
+
+TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessWithComposite) {
+ MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD);
+ sp<DisplayDevice> displayDevice = getDisplayDevice();
+
+ EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
+
+ constexpr float kDisplayBrightness = 0.5f;
+ displayDevice->stageBrightness(kDisplayBrightness);
+
+ EXPECT_EQ(0.5f, displayDevice->getStagedBrightness());
+
+ displayDevice->persistBrightness(true);
+
+ EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
+ EXPECT_EQ(kDisplayBrightness,
+ displayDevice->getCompositionDisplay()->getState().displayBrightness);
+}
+
+TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessWithCompositeShortCircuitsOnNoOp) {
+ MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD);
+ sp<DisplayDevice> displayDevice = getDisplayDevice();
+
+ EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
+
+ constexpr float kDisplayBrightness = 0.5f;
+ displayDevice->stageBrightness(kDisplayBrightness);
+
+ EXPECT_EQ(0.5f, displayDevice->getStagedBrightness());
+
+ displayDevice->persistBrightness(true);
+
+ EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
+ EXPECT_EQ(kDisplayBrightness,
+ displayDevice->getCompositionDisplay()->getState().displayBrightness);
+ displayDevice->getCompositionDisplay()->editState().displayBrightness = std::nullopt;
+
+ displayDevice->stageBrightness(kDisplayBrightness);
+ EXPECT_EQ(0.5f, displayDevice->getStagedBrightness());
+ displayDevice->persistBrightness(true);
+
+ EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
+ EXPECT_EQ(std::nullopt, displayDevice->getCompositionDisplay()->getState().displayBrightness);
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index b1f704a..c318e28 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -60,6 +60,7 @@
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+ mFlinger.resetScheduler(nullptr);
}
void DisplayTransactionTest::injectMockScheduler() {
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 0067997..361d629 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -347,6 +347,11 @@
auto notifyPowerBoost(int32_t boostId) { return mFlinger->notifyPowerBoost(boostId); }
+ auto setDisplayBrightness(const sp<IBinder>& display,
+ const gui::DisplayBrightness& brightness) {
+ return mFlinger->setDisplayBrightness(display, brightness);
+ }
+
// Allow reading display state without locking, as if called on the SF main thread.
auto setPowerModeInternal(const sp<DisplayDevice>& display,
hal::PowerMode mode) NO_THREAD_SAFETY_ANALYSIS {
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 8c51313..4932ad1 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -120,7 +120,7 @@
Error(Display, uint64_t, uint64_t, DisplayedFrameStats*));
MOCK_METHOD3(setLayerPerFrameMetadataBlobs,
Error(Display, Layer, const std::vector<IComposerClient::PerFrameMetadataBlob>&));
- MOCK_METHOD2(setDisplayBrightness, Error(Display, float));
+ MOCK_METHOD3(setDisplayBrightness, Error(Display, float, const DisplayBrightnessOptions&));
MOCK_METHOD2(
getDisplayCapabilities,
Error(Display,
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
index 821fc8f..0527d80 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
@@ -80,7 +80,8 @@
MOCK_METHOD(hal::Error, presentOrValidate,
(nsecs_t, uint32_t *, uint32_t *, android::sp<android::Fence> *, uint32_t *),
(override));
- MOCK_METHOD(std::future<hal::Error>, setDisplayBrightness, (float), (override));
+ MOCK_METHOD(std::future<hal::Error>, setDisplayBrightness,
+ (float, const Hwc2::Composer::DisplayBrightnessOptions &), (override));
MOCK_METHOD(hal::Error, setActiveConfigWithConstraints,
(hal::HWConfigId, const hal::VsyncPeriodChangeConstraints &,
hal::VsyncPeriodChangeTimeline *),
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
index 23b849a..c598cbc 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
@@ -37,11 +37,10 @@
MOCK_METHOD(bool, supportsPowerHintSession, (), (override));
MOCK_METHOD(bool, isPowerHintSessionRunning, (), (override));
MOCK_METHOD(void, setTargetWorkDuration, (int64_t targetDurationNanos), (override));
- MOCK_METHOD(void, setPowerHintSessionThreadIds, (const std::vector<int32_t>& threadIds),
- (override));
MOCK_METHOD(void, sendActualWorkDuration, (int64_t actualDurationNanos, nsecs_t timestamp),
(override));
MOCK_METHOD(void, enablePowerHint, (bool enabled), (override));
+ MOCK_METHOD(bool, startPowerHintSession, (const std::vector<int32_t>& threadIds), (override));
};
} // namespace android::Hwc2::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
index 8b48e1c..0840a2f 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
@@ -34,6 +34,7 @@
MOCK_METHOD0(createClone, sp<Layer>());
MOCK_CONST_METHOD0(getFrameRateForLayerTree, FrameRate());
MOCK_CONST_METHOD0(getOwnerUid, uid_t());
+ MOCK_CONST_METHOD0(getDataSpace, ui::Dataspace());
};
} // namespace android::mock