Merge "binder interface between ArcBridge and C2VDAAdaptorProxy"
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 3ea1d56..89ce1e5 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -6,141 +6,86 @@
chmod 0222 /sys/kernel/debug/tracing/trace_marker
chmod 0222 /sys/kernel/tracing/trace_marker
-# Allow the shell group to enable (some) kernel tracing.
- chown root shell /sys/kernel/debug/tracing/trace_clock
- chown root shell /sys/kernel/tracing/trace_clock
- chown root shell /sys/kernel/debug/tracing/buffer_size_kb
- chown root shell /sys/kernel/tracing/buffer_size_kb
- chown root shell /sys/kernel/debug/tracing/options/overwrite
- chown root shell /sys/kernel/tracing/options/overwrite
- chown root shell /sys/kernel/debug/tracing/options/print-tgid
- chown root shell /sys/kernel/tracing/options/print-tgid
- chown root shell /sys/kernel/debug/tracing/saved_cmdlines_size
- chown root shell /sys/kernel/tracing/saved_cmdlines_size
- chown root shell /sys/kernel/debug/tracing/events/sched/sched_switch/enable
- chown root shell /sys/kernel/tracing/events/sched/sched_switch/enable
- chown root shell /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
- chown root shell /sys/kernel/tracing/events/sched/sched_wakeup/enable
- chown root shell /sys/kernel/debug/tracing/events/sched/sched_blocked_reason/enable
- chown root shell /sys/kernel/tracing/events/sched/sched_blocked_reason/enable
- chown root shell /sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug/enable
- chown root shell /sys/kernel/tracing/events/sched/sched_cpu_hotplug/enable
- chown root shell /sys/kernel/debug/tracing/events/cgroup/enable
- chown root shell /sys/kernel/tracing/events/cgroup/enable
- chown root shell /sys/kernel/debug/tracing/events/power/cpu_frequency/enable
- chown root shell /sys/kernel/tracing/events/power/cpu_frequency/enable
- chown root shell /sys/kernel/debug/tracing/events/power/cpu_idle/enable
- chown root shell /sys/kernel/tracing/events/power/cpu_idle/enable
- chown root shell /sys/kernel/debug/tracing/events/power/clock_set_rate/enable
- chown root shell /sys/kernel/tracing/events/power/clock_set_rate/enable
- chown root shell /sys/kernel/debug/tracing/events/power/cpu_frequency_limits/enable
- chown root shell /sys/kernel/tracing/events/power/cpu_frequency_limits/enable
- chown root shell /sys/kernel/debug/tracing/events/cpufreq_interactive/enable
- chown root shell /sys/kernel/tracing/events/cpufreq_interactive/enable
- chown root shell /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
- chown root shell /sys/kernel/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
- chown root shell /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable
- chown root shell /sys/kernel/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable
- chown root shell /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable
- chown root shell /sys/kernel/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable
- chown root shell /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable
- chown root shell /sys/kernel/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable
- chown root shell /sys/kernel/debug/tracing/events/binder/binder_transaction/enable
- chown root shell /sys/kernel/tracing/events/binder/binder_transaction/enable
- chown root shell /sys/kernel/debug/tracing/events/binder/binder_transaction_received/enable
- chown root shell /sys/kernel/tracing/events/binder/binder_transaction_received/enable
- chown root shell /sys/kernel/debug/tracing/events/binder/binder_lock/enable
- chown root shell /sys/kernel/tracing/events/binder/binder_lock/enable
- chown root shell /sys/kernel/debug/tracing/events/binder/binder_locked/enable
- chown root shell /sys/kernel/tracing/events/binder/binder_locked/enable
- chown root shell /sys/kernel/debug/tracing/events/binder/binder_unlock/enable
- chown root shell /sys/kernel/tracing/events/binder/binder_unlock/enable
- chown root shell /sys/kernel/debug/tracing/events/lowmemorykiller/enable
- chown root shell /sys/kernel/tracing/events/lowmemorykiller/enable
+# Grant unix world read/write permissions to kernel tracepoints.
+# Access control to these files is now entirely in selinux policy.
+ chmod 0666 /sys/kernel/debug/tracing/trace_clock
+ chmod 0666 /sys/kernel/tracing/trace_clock
+ chmod 0666 /sys/kernel/debug/tracing/buffer_size_kb
+ chmod 0666 /sys/kernel/tracing/buffer_size_kb
+ chmod 0666 /sys/kernel/debug/tracing/options/overwrite
+ chmod 0666 /sys/kernel/tracing/options/overwrite
+ chmod 0666 /sys/kernel/debug/tracing/options/print-tgid
+ chmod 0666 /sys/kernel/tracing/options/print-tgid
+ chmod 0666 /sys/kernel/debug/tracing/saved_cmdlines_size
+ chmod 0666 /sys/kernel/tracing/saved_cmdlines_size
+ chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_switch/enable
+ chmod 0666 /sys/kernel/tracing/events/sched/sched_switch/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
+ chmod 0666 /sys/kernel/tracing/events/sched/sched_wakeup/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_blocked_reason/enable
+ chmod 0666 /sys/kernel/tracing/events/sched/sched_blocked_reason/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug/enable
+ chmod 0666 /sys/kernel/tracing/events/sched/sched_cpu_hotplug/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/cgroup/enable
+ chmod 0666 /sys/kernel/tracing/events/cgroup/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/power/cpu_frequency/enable
+ chmod 0666 /sys/kernel/tracing/events/power/cpu_frequency/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/power/cpu_idle/enable
+ chmod 0666 /sys/kernel/tracing/events/power/cpu_idle/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/power/clock_set_rate/enable
+ chmod 0666 /sys/kernel/tracing/events/power/clock_set_rate/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/power/cpu_frequency_limits/enable
+ chmod 0666 /sys/kernel/tracing/events/power/cpu_frequency_limits/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/cpufreq_interactive/enable
+ chmod 0666 /sys/kernel/tracing/events/cpufreq_interactive/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
+ chmod 0666 /sys/kernel/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable
+ chmod 0666 /sys/kernel/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable
+ chmod 0666 /sys/kernel/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable
+ chmod 0666 /sys/kernel/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable
+ chmod 0666 /sys/kernel/debug/tracing/tracing_on
+ chmod 0666 /sys/kernel/tracing/tracing_on
+ chmod 0666 /sys/kernel/debug/tracing/events/binder/binder_transaction/enable
+ chmod 0666 /sys/kernel/tracing/events/binder/binder_transaction/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/binder/binder_transaction_received/enable
+ chmod 0666 /sys/kernel/tracing/events/binder/binder_transaction_received/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/binder/binder_lock/enable
+ chmod 0666 /sys/kernel/tracing/events/binder/binder_lock/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/binder/binder_locked/enable
+ chmod 0666 /sys/kernel/tracing/events/binder/binder_locked/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/binder/binder_unlock/enable
+ chmod 0666 /sys/kernel/tracing/events/binder/binder_unlock/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/i2c/enable
+ chmod 0666 /sys/kernel/tracing/events/i2c/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/i2c/i2c_read/enable
+ chmod 0666 /sys/kernel/tracing/events/i2c/i2c_read/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/i2c/i2c_write/enable
+ chmod 0666 /sys/kernel/tracing/events/i2c/i2c_write/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/i2c/i2c_result/enable
+ chmod 0666 /sys/kernel/tracing/events/i2c/i2c_result/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/i2c/i2c_reply/enable
+ chmod 0666 /sys/kernel/tracing/events/i2c/i2c_reply/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/i2c/smbus_read/enable
+ chmod 0666 /sys/kernel/tracing/events/i2c/smbus_read/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/i2c/smbus_write/enable
+ chmod 0666 /sys/kernel/tracing/events/i2c/smbus_write/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/i2c/smbus_result/enable
+ chmod 0666 /sys/kernel/tracing/events/i2c/smbus_result/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/i2c/smbus_reply/enable
+ chmod 0666 /sys/kernel/tracing/events/i2c/smbus_reply/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/lowmemorykiller/enable
+ chmod 0666 /sys/kernel/tracing/events/lowmemorykiller/enable
- chown root shell /sys/kernel/debug/tracing/tracing_on
- chown root shell /sys/kernel/tracing/tracing_on
-
- chmod 0664 /sys/kernel/debug/tracing/trace_clock
- chmod 0664 /sys/kernel/tracing/trace_clock
- chmod 0664 /sys/kernel/debug/tracing/buffer_size_kb
- chmod 0664 /sys/kernel/tracing/buffer_size_kb
- chmod 0664 /sys/kernel/debug/tracing/options/overwrite
- chmod 0664 /sys/kernel/tracing/options/overwrite
- chmod 0664 /sys/kernel/debug/tracing/options/print-tgid
- chmod 0664 /sys/kernel/tracing/options/print-tgid
- chmod 0664 /sys/kernel/debug/tracing/saved_cmdlines_size
- chmod 0664 /sys/kernel/tracing/saved_cmdlines_size
- chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_switch/enable
- chmod 0664 /sys/kernel/tracing/events/sched/sched_switch/enable
- chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
- chmod 0664 /sys/kernel/tracing/events/sched/sched_wakeup/enable
- chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_blocked_reason/enable
- chmod 0664 /sys/kernel/tracing/events/sched/sched_blocked_reason/enable
- chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug/enable
- chmod 0664 /sys/kernel/tracing/events/sched/sched_cpu_hotplug/enable
- chmod 0664 /sys/kernel/debug/tracing/events/cgroup/enable
- chmod 0664 /sys/kernel/tracing/events/cgroup/enable
- chmod 0664 /sys/kernel/debug/tracing/events/power/cpu_frequency/enable
- chmod 0664 /sys/kernel/tracing/events/power/cpu_frequency/enable
- chmod 0664 /sys/kernel/debug/tracing/events/power/cpu_idle/enable
- chmod 0664 /sys/kernel/tracing/events/power/cpu_idle/enable
- chmod 0664 /sys/kernel/debug/tracing/events/power/clock_set_rate/enable
- chmod 0664 /sys/kernel/tracing/events/power/clock_set_rate/enable
- chmod 0664 /sys/kernel/debug/tracing/events/power/cpu_frequency_limits/enable
- chmod 0664 /sys/kernel/tracing/events/power/cpu_frequency_limits/enable
- chmod 0664 /sys/kernel/debug/tracing/events/cpufreq_interactive/enable
- chmod 0664 /sys/kernel/tracing/events/cpufreq_interactive/enable
- chmod 0664 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
- chmod 0664 /sys/kernel/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
- chmod 0664 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable
- chmod 0664 /sys/kernel/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable
- chmod 0664 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable
- chmod 0664 /sys/kernel/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable
- chmod 0664 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable
- chmod 0664 /sys/kernel/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable
- chmod 0664 /sys/kernel/debug/tracing/tracing_on
- chmod 0664 /sys/kernel/tracing/tracing_on
- chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_transaction/enable
- chmod 0664 /sys/kernel/tracing/events/binder/binder_transaction/enable
- chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_transaction_received/enable
- chmod 0664 /sys/kernel/tracing/events/binder/binder_transaction_received/enable
- chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_lock/enable
- chmod 0664 /sys/kernel/tracing/events/binder/binder_lock/enable
- chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_locked/enable
- chmod 0664 /sys/kernel/tracing/events/binder/binder_locked/enable
- chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_unlock/enable
- chmod 0664 /sys/kernel/tracing/events/binder/binder_unlock/enable
- chmod 0664 /sys/kernel/debug/tracing/events/i2c/enable
- chmod 0664 /sys/kernel/tracing/events/i2c/enable
- chmod 0664 /sys/kernel/debug/tracing/events/i2c/i2c_read/enable
- chmod 0664 /sys/kernel/tracing/events/i2c/i2c_read/enable
- chmod 0664 /sys/kernel/debug/tracing/events/i2c/i2c_write/enable
- chmod 0664 /sys/kernel/tracing/events/i2c/i2c_write/enable
- chmod 0664 /sys/kernel/debug/tracing/events/i2c/i2c_result/enable
- chmod 0664 /sys/kernel/tracing/events/i2c/i2c_result/enable
- chmod 0664 /sys/kernel/debug/tracing/events/i2c/i2c_reply/enable
- chmod 0664 /sys/kernel/tracing/events/i2c/i2c_reply/enable
- chmod 0664 /sys/kernel/debug/tracing/events/i2c/smbus_read/enable
- chmod 0664 /sys/kernel/tracing/events/i2c/smbus_read/enable
- chmod 0664 /sys/kernel/debug/tracing/events/i2c/smbus_write/enable
- chmod 0664 /sys/kernel/tracing/events/i2c/smbus_write/enable
- chmod 0664 /sys/kernel/debug/tracing/events/i2c/smbus_result/enable
- chmod 0664 /sys/kernel/tracing/events/i2c/smbus_result/enable
- chmod 0664 /sys/kernel/debug/tracing/events/i2c/smbus_reply/enable
- chmod 0664 /sys/kernel/tracing/events/i2c/smbus_reply/enable
- chmod 0664 /sys/kernel/debug/tracing/events/lowmemorykiller/enable
- chmod 0664 /sys/kernel/tracing/events/lowmemorykiller/enable
-
- # Tracing disabled by default
+# Tracing disabled by default
write /sys/kernel/debug/tracing/tracing_on 0
write /sys/kernel/tracing/tracing_on 0
-# Allow only the shell group to read and truncate the kernel trace.
- chown root shell /sys/kernel/debug/tracing/trace
- chown root shell /sys/kernel/tracing/trace
- chmod 0660 /sys/kernel/debug/tracing/trace
- chmod 0660 /sys/kernel/tracing/trace
+# Read and truncate the kernel trace.
+ chmod 0666 /sys/kernel/debug/tracing/trace
+ chmod 0666 /sys/kernel/tracing/trace
on property:persist.debug.atrace.boottrace=1
start boottrace
diff --git a/cmds/atrace/atrace_userdebug.rc b/cmds/atrace/atrace_userdebug.rc
index 5fd28e2..9d632cc 100644
--- a/cmds/atrace/atrace_userdebug.rc
+++ b/cmds/atrace/atrace_userdebug.rc
@@ -1,47 +1,43 @@
## Permissions to allow additional system-wide tracing to the kernel trace buffer.
## The default list of permissions is set in frameworks/native/cmds/atrace/atrace.rc
-# Allow the shell group to enable kernel tracepoints:
+# Grant unix world read/write permissions to enable kernel tracepoints.
+# Access control to these files is now entirely in selinux policy.
on post-fs
- chown root shell /sys/kernel/debug/tracing/events/sync/enable
- chown root shell /sys/kernel/debug/tracing/events/workqueue/enable
- chown root shell /sys/kernel/debug/tracing/events/regulator/enable
- chown root shell /sys/kernel/debug/tracing/events/pagecache/enable
+ chmod 0666 /sys/kernel/tracing/events/sync/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/sync/enable
+ chmod 0666 /sys/kernel/tracing/events/workqueue/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/workqueue/enable
+ chmod 0666 /sys/kernel/tracing/events/regulator/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/regulator/enable
+ chmod 0666 /sys/kernel/tracing/events/pagecache/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/pagecache/enable
# irq
- chown root shell /sys/kernel/debug/tracing/events/irq/enable
- chown root shell /sys/kernel/debug/tracing/events/ipi/enable
+ chmod 0666 /sys/kernel/tracing/events/irq/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/irq/enable
+ chmod 0666 /sys/kernel/tracing/events/ipi/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/ipi/enable
# disk
- chown root shell /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_enter/enable
- chown root shell /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_exit/enable
- chown root shell /sys/kernel/debug/tracing/events/f2fs/f2fs_write_begin/enable
- chown root shell /sys/kernel/debug/tracing/events/f2fs/f2fs_write_end/enable
- chown root shell /sys/kernel/debug/tracing/events/ext4/ext4_da_write_begin/enable
- chown root shell /sys/kernel/debug/tracing/events/ext4/ext4_da_write_end/enable
- chown root shell /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable
- chown root shell /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable
- chown root shell /sys/kernel/debug/tracing/events/block/block_rq_issue/enable
- chown root shell /sys/kernel/debug/tracing/events/block/block_rq_complete/enable
-
- chmod 0664 /sys/kernel/debug/tracing/events/sync/enable
- chmod 0664 /sys/kernel/debug/tracing/events/workqueue/enable
- chmod 0664 /sys/kernel/debug/tracing/events/regulator/enable
- chmod 0664 /sys/kernel/debug/tracing/events/pagecache/enable
-
- # irq
- chmod 0664 /sys/kernel/debug/tracing/events/irq/enable
- chmod 0664 /sys/kernel/debug/tracing/events/ipi/enable
-
- # disk
- chmod 0664 /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_enter/enable
- chmod 0664 /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_exit/enable
- chmod 0664 /sys/kernel/debug/tracing/events/f2fs/f2fs_write_begin/enable
- chmod 0664 /sys/kernel/debug/tracing/events/f2fs/f2fs_write_end/enable
- chmod 0664 /sys/kernel/debug/tracing/events/ext4/ext4_da_write_begin/enable
- chmod 0664 /sys/kernel/debug/tracing/events/ext4/ext4_da_write_end/enable
- chmod 0664 /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable
- chmod 0664 /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable
- chmod 0664 /sys/kernel/debug/tracing/events/block/block_rq_issue/enable
- chmod 0664 /sys/kernel/debug/tracing/events/block/block_rq_complete/enable
+ chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_sync_file_enter/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_enter/enable
+ chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_sync_file_exit/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_exit/enable
+ chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_write_begin/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/f2fs/f2fs_write_begin/enable
+ chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_write_end/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/f2fs/f2fs_write_end/enable
+ chmod 0666 /sys/kernel/tracing/events/ext4/ext4_da_write_begin/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_da_write_begin/enable
+ chmod 0666 /sys/kernel/tracing/events/ext4/ext4_da_write_end/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_da_write_end/enable
+ chmod 0666 /sys/kernel/tracing/events/ext4/ext4_sync_file_enter/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable
+ chmod 0666 /sys/kernel/tracing/events/ext4/ext4_sync_file_exit/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable
+ chmod 0666 /sys/kernel/tracing/events/block/block_rq_issue/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/block/block_rq_issue/enable
+ chmod 0666 /sys/kernel/tracing/events/block/block_rq_complete/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/block/block_rq_complete/enable
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 93f8d43..2eb11cb 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -657,12 +657,18 @@
return 0;
}
-/* timeout in ms */
-static unsigned long logcat_timeout(const char *name) {
- log_id_t id = android_name_to_log_id(name);
- unsigned long property_size = __android_logger_get_buffer_size(id);
- /* Engineering margin is ten-fold our guess */
- return 10 * (property_size + worst_write_perf) / worst_write_perf;
+static const long MINIMUM_LOGCAT_TIMEOUT_MS = 50000;
+
+/* timeout in ms to read a list of buffers */
+static unsigned long logcat_timeout(const std::vector<std::string>& buffers) {
+ unsigned long timeout_ms = 0;
+ for (const auto& buffer : buffers) {
+ log_id_t id = android_name_to_log_id(buffer.c_str());
+ unsigned long property_size = __android_logger_get_buffer_size(id);
+ /* Engineering margin is ten-fold our guess */
+ timeout_ms += 10 * (property_size + worst_write_perf) / worst_write_perf;
+ }
+ return timeout_ms > MINIMUM_LOGCAT_TIMEOUT_MS ? timeout_ms : MINIMUM_LOGCAT_TIMEOUT_MS;
}
void Dumpstate::PrintHeader() const {
@@ -831,13 +837,8 @@
}
}
-static const long MINIMUM_LOGCAT_TIMEOUT_MS = 50000;
-
static void DoKernelLogcat() {
- unsigned long timeout_ms = logcat_timeout("kernel");
- if (timeout_ms < MINIMUM_LOGCAT_TIMEOUT_MS) {
- timeout_ms = MINIMUM_LOGCAT_TIMEOUT_MS;
- }
+ unsigned long timeout_ms = logcat_timeout({"kernel"});
RunCommand(
"KERNEL LOG",
{"logcat", "-b", "kernel", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
@@ -848,25 +849,21 @@
unsigned long timeout_ms;
// DumpFile("EVENT LOG TAGS", "/etc/event-log-tags");
// calculate timeout
- timeout_ms = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash");
- if (timeout_ms < MINIMUM_LOGCAT_TIMEOUT_MS) {
- timeout_ms = MINIMUM_LOGCAT_TIMEOUT_MS;
- }
+ timeout_ms = logcat_timeout({"main", "system", "crash"});
RunCommand("SYSTEM LOG",
{"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
CommandOptions::WithTimeoutInMs(timeout_ms).Build());
- timeout_ms = logcat_timeout("events");
- if (timeout_ms < MINIMUM_LOGCAT_TIMEOUT_MS) {
- timeout_ms = MINIMUM_LOGCAT_TIMEOUT_MS;
- }
+ timeout_ms = logcat_timeout({"events"});
RunCommand(
"EVENT LOG",
{"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
CommandOptions::WithTimeoutInMs(timeout_ms).Build());
- timeout_ms = logcat_timeout("radio");
- if (timeout_ms < MINIMUM_LOGCAT_TIMEOUT_MS) {
- timeout_ms = MINIMUM_LOGCAT_TIMEOUT_MS;
- }
+ timeout_ms = logcat_timeout({"stats"});
+ RunCommand(
+ "STATS LOG",
+ {"logcat", "-b", "stats", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
+ CommandOptions::WithTimeoutInMs(timeout_ms).Build());
+ timeout_ms = logcat_timeout({"radio"});
RunCommand(
"RADIO LOG",
{"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
@@ -1136,7 +1133,7 @@
}
RunCommandToFd(fd,
"",
- {"lshal", "debug", interface},
+ {"lshal", "debug", "-E", interface},
CommandOptions::WithTimeout(2).AsRootIfAvailable().Build());
bool empty = 0 == lseek(fd, 0, SEEK_END);
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index ac48041..fcd6742 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -84,6 +84,7 @@
"/system/bin/drmserver",
"/system/bin/mediadrmserver",
"/system/bin/mediaextractor", // media.extractor
+ "/system/bin/mediametrics", // media.metrics
"/system/bin/mediaserver",
"/system/bin/sdcard",
"/system/bin/surfaceflinger",
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index 0862a40..ae0cc01 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -43,9 +43,11 @@
#include "dumpsys.h"
using namespace android;
-using android::base::StringPrintf;
-using android::base::unique_fd;
-using android::base::WriteFully;
+using ::android::base::StringAppendF;
+using ::android::base::StringPrintf;
+using ::android::base::unique_fd;
+using ::android::base::WriteFully;
+using ::android::base::WriteStringToFd;
static int sort_func(const String16* lhs, const String16* rhs)
{
@@ -96,6 +98,19 @@
return false;
}
+String16 ConvertBitmaskToPriorityType(int bitmask) {
+ if (bitmask == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL) {
+ return String16(PriorityDumper::PRIORITY_ARG_CRITICAL);
+ }
+ if (bitmask == IServiceManager::DUMP_FLAG_PRIORITY_HIGH) {
+ return String16(PriorityDumper::PRIORITY_ARG_HIGH);
+ }
+ if (bitmask == IServiceManager::DUMP_FLAG_PRIORITY_NORMAL) {
+ return String16(PriorityDumper::PRIORITY_ARG_NORMAL);
+ }
+ return String16("");
+}
+
int Dumpsys::main(int argc, char* const argv[]) {
Vector<String16> services;
Vector<String16> args;
@@ -104,9 +119,9 @@
Vector<String16> protoServices;
bool showListOnly = false;
bool skipServices = false;
- bool filterByProto = false;
+ bool asProto = false;
int timeoutArgMs = 10000;
- int dumpPriorityFlags = IServiceManager::DUMP_FLAG_PRIORITY_ALL;
+ int priorityFlags = IServiceManager::DUMP_FLAG_PRIORITY_ALL;
static struct option longOptions[] = {{"priority", required_argument, 0, 0},
{"proto", no_argument, 0, 0},
{"skip", no_argument, 0, 0},
@@ -131,13 +146,13 @@
if (!strcmp(longOptions[optionIndex].name, "skip")) {
skipServices = true;
} else if (!strcmp(longOptions[optionIndex].name, "proto")) {
- filterByProto = true;
+ asProto = true;
} else if (!strcmp(longOptions[optionIndex].name, "help")) {
usage();
return 0;
} else if (!strcmp(longOptions[optionIndex].name, "priority")) {
priorityType = String16(String8(optarg));
- if (!ConvertPriorityTypeToBitmask(priorityType, dumpPriorityFlags)) {
+ if (!ConvertPriorityTypeToBitmask(priorityType, priorityFlags)) {
fprintf(stderr, "\n");
usage();
return -1;
@@ -198,28 +213,11 @@
}
if (services.empty() || showListOnly) {
- // gets all services
- services = sm_->listServices(dumpPriorityFlags);
- services.sort(sort_func);
- if (filterByProto) {
- protoServices = sm_->listServices(IServiceManager::DUMP_FLAG_PROTO);
- protoServices.sort(sort_func);
- Vector<String16> intersection;
- std::set_intersection(services.begin(), services.end(), protoServices.begin(),
- protoServices.end(), std::back_inserter(intersection));
- services = std::move(intersection);
- args.insertAt(String16(PriorityDumper::PROTO_ARG), 0);
- }
- if (dumpPriorityFlags != IServiceManager::DUMP_FLAG_PRIORITY_ALL) {
- args.insertAt(String16(PriorityDumper::PRIORITY_ARG), 0);
- args.insertAt(priorityType, 1);
- } else {
- args.add(String16("-a"));
- }
+ services = listServices(priorityFlags, asProto);
+ setServiceArgs(args, asProto, priorityFlags);
}
const size_t N = services.size();
-
if (N > 1) {
// first print a list of the current services
aout << "Currently running services:" << endl;
@@ -239,129 +237,204 @@
}
for (size_t i = 0; i < N; i++) {
- const String16& service_name = std::move(services[i]);
- if (IsSkipped(skippedServices, service_name)) continue;
+ const String16& serviceName = services[i];
+ if (IsSkipped(skippedServices, serviceName)) continue;
- sp<IBinder> service = sm_->checkService(service_name);
- if (service != nullptr) {
- int sfd[2];
-
- if (pipe(sfd) != 0) {
- aerr << "Failed to create pipe to dump service info for " << service_name
- << ": " << strerror(errno) << endl;
- continue;
+ if (startDumpThread(serviceName, args) == OK) {
+ bool addSeparator = (N > 1);
+ if (addSeparator) {
+ writeDumpHeader(STDOUT_FILENO, serviceName, priorityFlags);
}
+ std::chrono::duration<double> elapsedDuration;
+ size_t bytesWritten = 0;
+ status_t status =
+ writeDump(STDOUT_FILENO, serviceName, std::chrono::milliseconds(timeoutArgMs),
+ asProto, elapsedDuration, bytesWritten);
- unique_fd local_end(sfd[0]);
- unique_fd remote_end(sfd[1]);
- sfd[0] = sfd[1] = -1;
-
- if (N > 1) {
- aout << "------------------------------------------------------------"
- "-------------------" << endl;
- if (dumpPriorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_ALL) {
- aout << "DUMP OF SERVICE " << service_name << ":" << endl;
- } else {
- aout << "DUMP OF SERVICE " << priorityType << " " << service_name << ":" << endl;
- }
- }
-
- // dump blocks until completion, so spawn a thread..
- std::thread dump_thread([=, remote_end { std::move(remote_end) }]() mutable {
- int err = service->dump(remote_end.get(), args);
-
- // It'd be nice to be able to close the remote end of the socketpair before the dump
- // call returns, to terminate our reads if the other end closes their copy of the
- // file descriptor, but then hangs for some reason. There doesn't seem to be a good
- // way to do this, though.
- remote_end.reset();
-
- if (err != 0) {
- aerr << "Error dumping service info: (" << strerror(err) << ") " << service_name
- << endl;
- }
- });
-
- auto timeout = std::chrono::milliseconds(timeoutArgMs);
- auto start = std::chrono::steady_clock::now();
- auto end = start + timeout;
-
- struct pollfd pfd = {
- .fd = local_end.get(),
- .events = POLLIN
- };
-
- bool timed_out = false;
- bool error = false;
- while (true) {
- // Wrap this in a lambda so that TEMP_FAILURE_RETRY recalculates the timeout.
- auto time_left_ms = [end]() {
- auto now = std::chrono::steady_clock::now();
- auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
- return std::max(diff.count(), 0ll);
- };
-
- int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
- if (rc < 0) {
- aerr << "Error in poll while dumping service " << service_name << " : "
- << strerror(errno) << endl;
- error = true;
- break;
- } else if (rc == 0) {
- timed_out = true;
- break;
- }
-
- char buf[4096];
- rc = TEMP_FAILURE_RETRY(read(local_end.get(), buf, sizeof(buf)));
- if (rc < 0) {
- aerr << "Failed to read while dumping service " << service_name << ": "
- << strerror(errno) << endl;
- error = true;
- break;
- } else if (rc == 0) {
- // EOF.
- break;
- }
-
- if (!WriteFully(STDOUT_FILENO, buf, rc)) {
- aerr << "Failed to write while dumping service " << service_name << ": "
- << strerror(errno) << endl;
- error = true;
- break;
- }
- }
-
- if (timed_out) {
+ if (status == TIMED_OUT) {
aout << endl
- << "*** SERVICE '" << service_name << "' DUMP TIMEOUT (" << timeoutArgMs
+ << "*** SERVICE '" << serviceName << "' DUMP TIMEOUT (" << timeoutArgMs
<< "ms) EXPIRED ***" << endl
<< endl;
}
- if (timed_out || error) {
- dump_thread.detach();
- } else {
- dump_thread.join();
+ if (addSeparator) {
+ writeDumpFooter(STDOUT_FILENO, serviceName, elapsedDuration);
}
-
- if (N > 1) {
- std::chrono::duration<double> elapsed_seconds =
- std::chrono::steady_clock::now() - start;
- aout << StringPrintf("--------- %.3fs ", elapsed_seconds.count()).c_str()
- << "was the duration of dumpsys " << service_name;
-
- using std::chrono::system_clock;
- const auto finish = system_clock::to_time_t(system_clock::now());
- std::tm finish_tm;
- localtime_r(&finish, &finish_tm);
- aout << ", ending at: " << std::put_time(&finish_tm, "%Y-%m-%d %H:%M:%S")
- << endl;
- }
- } else {
- aerr << "Can't find service: " << service_name << endl;
+ bool dumpComplete = (status == OK);
+ stopDumpThread(dumpComplete);
}
}
return 0;
}
+
+Vector<String16> Dumpsys::listServices(int priorityFilterFlags, bool filterByProto) const {
+ Vector<String16> services = sm_->listServices(priorityFilterFlags);
+ services.sort(sort_func);
+ if (filterByProto) {
+ Vector<String16> protoServices = sm_->listServices(IServiceManager::DUMP_FLAG_PROTO);
+ protoServices.sort(sort_func);
+ Vector<String16> intersection;
+ std::set_intersection(services.begin(), services.end(), protoServices.begin(),
+ protoServices.end(), std::back_inserter(intersection));
+ services = std::move(intersection);
+ }
+ return services;
+}
+
+void Dumpsys::setServiceArgs(Vector<String16>& args, bool asProto, int priorityFlags) const {
+ if ((priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_ALL) ||
+ (priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_NORMAL)) {
+ args.add(String16("-a"));
+ }
+ if (asProto) {
+ args.insertAt(String16(PriorityDumper::PROTO_ARG), 0);
+ }
+ if (priorityFlags != IServiceManager::DUMP_FLAG_PRIORITY_ALL) {
+ String16 priorityType = ConvertBitmaskToPriorityType(priorityFlags);
+ args.insertAt(String16(PriorityDumper::PRIORITY_ARG), 0);
+ args.insertAt(priorityType, 1);
+ }
+}
+
+status_t Dumpsys::startDumpThread(const String16& serviceName, const Vector<String16>& args) {
+ sp<IBinder> service = sm_->checkService(serviceName);
+ if (service == nullptr) {
+ aerr << "Can't find service: " << serviceName << endl;
+ return NAME_NOT_FOUND;
+ }
+
+ int sfd[2];
+ if (pipe(sfd) != 0) {
+ aerr << "Failed to create pipe to dump service info for " << serviceName << ": "
+ << strerror(errno) << endl;
+ return -errno;
+ }
+
+ redirectFd_ = unique_fd(sfd[0]);
+ unique_fd remote_end(sfd[1]);
+ sfd[0] = sfd[1] = -1;
+
+ // dump blocks until completion, so spawn a thread..
+ activeThread_ = std::thread([=, remote_end{std::move(remote_end)}]() mutable {
+ int err = service->dump(remote_end.get(), args);
+
+ // It'd be nice to be able to close the remote end of the socketpair before the dump
+ // call returns, to terminate our reads if the other end closes their copy of the
+ // file descriptor, but then hangs for some reason. There doesn't seem to be a good
+ // way to do this, though.
+ remote_end.reset();
+
+ if (err != 0) {
+ aerr << "Error dumping service info: (" << strerror(err) << ") "
+ << serviceName << endl;
+ }
+ });
+ return OK;
+}
+
+void Dumpsys::stopDumpThread(bool dumpComplete) {
+ if (dumpComplete) {
+ activeThread_.join();
+ } else {
+ activeThread_.detach();
+ }
+ /* close read end of the dump output redirection pipe */
+ redirectFd_.reset();
+}
+
+void Dumpsys::writeDumpHeader(int fd, const String16& serviceName, int priorityFlags) const {
+ std::string msg(
+ "----------------------------------------"
+ "---------------------------------------\n");
+ if (priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_ALL ||
+ priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_NORMAL) {
+ StringAppendF(&msg, "DUMP OF SERVICE %s:\n", String8(serviceName).c_str());
+ } else {
+ String16 priorityType = ConvertBitmaskToPriorityType(priorityFlags);
+ StringAppendF(&msg, "DUMP OF SERVICE %s %s:\n", String8(priorityType).c_str(),
+ String8(serviceName).c_str());
+ }
+ WriteStringToFd(msg, fd);
+}
+
+status_t Dumpsys::writeDump(int fd, const String16& serviceName, std::chrono::milliseconds timeout,
+ bool asProto, std::chrono::duration<double>& elapsedDuration,
+ size_t& bytesWritten) const {
+ status_t status = OK;
+ size_t totalBytes = 0;
+ auto start = std::chrono::steady_clock::now();
+ auto end = start + timeout;
+
+ int serviceDumpFd = redirectFd_.get();
+ if (serviceDumpFd == -1) {
+ return INVALID_OPERATION;
+ }
+
+ struct pollfd pfd = {.fd = serviceDumpFd, .events = POLLIN};
+
+ while (true) {
+ // Wrap this in a lambda so that TEMP_FAILURE_RETRY recalculates the timeout.
+ auto time_left_ms = [end]() {
+ auto now = std::chrono::steady_clock::now();
+ auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
+ return std::max(diff.count(), 0ll);
+ };
+
+ int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
+ if (rc < 0) {
+ aerr << "Error in poll while dumping service " << serviceName << " : "
+ << strerror(errno) << endl;
+ status = -errno;
+ break;
+ } else if (rc == 0) {
+ status = TIMED_OUT;
+ break;
+ }
+
+ char buf[4096];
+ rc = TEMP_FAILURE_RETRY(read(redirectFd_.get(), buf, sizeof(buf)));
+ if (rc < 0) {
+ aerr << "Failed to read while dumping service " << serviceName << ": "
+ << strerror(errno) << endl;
+ status = -errno;
+ break;
+ } else if (rc == 0) {
+ // EOF.
+ break;
+ }
+
+ if (!WriteFully(fd, buf, rc)) {
+ aerr << "Failed to write while dumping service " << serviceName << ": "
+ << strerror(errno) << endl;
+ status = -errno;
+ break;
+ }
+ totalBytes += rc;
+ }
+
+ if ((status == TIMED_OUT) && (!asProto)) {
+ std::string msg = StringPrintf("\n*** SERVICE '%s' DUMP TIMEOUT (%llums) EXPIRED ***\n\n",
+ String8(serviceName).string(), timeout.count());
+ WriteStringToFd(msg, fd);
+ }
+
+ elapsedDuration = std::chrono::steady_clock::now() - start;
+ bytesWritten = totalBytes;
+ return status;
+}
+
+void Dumpsys::writeDumpFooter(int fd, const String16& serviceName,
+ const std::chrono::duration<double>& elapsedDuration) const {
+ using std::chrono::system_clock;
+ const auto finish = system_clock::to_time_t(system_clock::now());
+ std::tm finish_tm;
+ localtime_r(&finish, &finish_tm);
+ std::stringstream oss;
+ oss << std::put_time(&finish_tm, "%Y-%m-%d %H:%M:%S");
+ std::string msg =
+ StringPrintf("--------- %.3fs was the duration of dumpsys %s, ending at: %s\n",
+ elapsedDuration.count(), String8(serviceName).string(), oss.str().c_str());
+ WriteStringToFd(msg, fd);
+}
diff --git a/cmds/dumpsys/dumpsys.h b/cmds/dumpsys/dumpsys.h
index 2534dde..1d78aa4 100644
--- a/cmds/dumpsys/dumpsys.h
+++ b/cmds/dumpsys/dumpsys.h
@@ -17,6 +17,9 @@
#ifndef FRAMEWORK_NATIVE_CMD_DUMPSYS_H_
#define FRAMEWORK_NATIVE_CMD_DUMPSYS_H_
+#include <thread>
+
+#include <android-base/unique_fd.h>
#include <binder/IServiceManager.h>
namespace android {
@@ -25,10 +28,97 @@
public:
Dumpsys(android::IServiceManager* sm) : sm_(sm) {
}
+ /**
+ * Main entry point into dumpsys.
+ */
int main(int argc, char* const argv[]);
+ /**
+ * Returns a list of services.
+ * @param priorityFlags filter services by specified priorities
+ * @param supportsProto filter services that support proto dumps
+ * @return list of services
+ */
+ Vector<String16> listServices(int priorityFlags, bool supportsProto) const;
+
+ /**
+ * Modifies @{code args} to add additional arguments to indicate if the service
+ * must dump as proto or dump to a certian priority bucket.
+ * @param args initial list of arguments to pass to service dump method.
+ * @param asProto dump service as proto by passing an additional --proto arg
+ * @param priorityFlags indicates priority of dump by passing additional priority args
+ * to the service
+ */
+ void setServiceArgs(Vector<String16>& args, bool asProto, int priorityFlags) const;
+
+ /**
+ * Starts a thread to connect to a service and get its dump output. The thread redirects
+ * the output to a pipe. Thread must be stopped by a subsequent callto {@code
+ * stopDumpThread}.
+ * @param serviceName
+ * @param args list of arguments to pass to service dump method.
+ * @return {@code OK} thread is started successfully.
+ * {@code NAME_NOT_FOUND} service could not be found.
+ * {@code != OK} error
+ */
+ status_t startDumpThread(const String16& serviceName, const Vector<String16>& args);
+
+ /**
+ * Writes a section header to a file descriptor.
+ * @param fd file descriptor to write data
+ * @param serviceName
+ * @param priorityFlags dump priority specified
+ */
+ void writeDumpHeader(int fd, const String16& serviceName, int priorityFlags) const;
+
+ /**
+ * Redirects service dump to a file descriptor. This requires
+ * {@code startDumpThread} to be called successfully otherwise the function will
+ * return {@code INVALID_OPERATION}.
+ * @param fd file descriptor to write data
+ * @param serviceName
+ * @param timeout timeout to terminate the dump if not completed
+ * @param asProto used to supresses additional output to the fd such as timeout
+ * error messages
+ * @param elapsedDuration returns elapsed time in seconds
+ * @param bytesWritten returns number of bytes written
+ * @return {@code OK} if successful
+ * {@code TIMED_OUT} dump timed out
+ * {@code INVALID_OPERATION} invalid state
+ * {@code != OK} error
+ */
+ status_t writeDump(int fd, const String16& serviceName, std::chrono::milliseconds timeout,
+ bool asProto, std::chrono::duration<double>& elapsedDuration,
+ size_t& bytesWritten) const;
+
+ /**
+ * Writes a section footer to a file descriptor with duration info.
+ * @param fd file descriptor to write data
+ * @param serviceName
+ * @param elapsedDuration duration of dump
+ */
+ void writeDumpFooter(int fd, const String16& serviceName,
+ const std::chrono::duration<double>& elapsedDuration) const;
+
+ /**
+ * Terminates dump thread.
+ * @param dumpComplete If {@code true}, indicates the dump was successfully completed and
+ * tries to join the thread. Otherwise thread is detached.
+ */
+ void stopDumpThread(bool dumpComplete);
+
+ /**
+ * Returns file descriptor of the pipe used to dump service data. This assumes
+ * {@code startDumpThread} was called successfully.
+ */
+ int getDumpFd() const {
+ return redirectFd_.get();
+ }
+
private:
android::IServiceManager* sm_;
+ std::thread activeThread_;
+ mutable android::base::unique_fd redirectFd_;
};
}
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index bdb0a9a..b13f59d 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -188,6 +188,22 @@
EXPECT_THAT(status, Eq(0));
}
+ void CallSingleService(const String16& serviceName, Vector<String16>& args, int priorityFlags,
+ bool supportsProto, std::chrono::duration<double>& elapsedDuration,
+ size_t& bytesWritten) {
+ CaptureStdout();
+ CaptureStderr();
+ dump_.setServiceArgs(args, supportsProto, priorityFlags);
+ status_t status = dump_.startDumpThread(serviceName, args);
+ EXPECT_THAT(status, Eq(0));
+ status = dump_.writeDump(STDOUT_FILENO, serviceName, std::chrono::milliseconds(500), false,
+ elapsedDuration, bytesWritten);
+ EXPECT_THAT(status, Eq(0));
+ dump_.stopDumpThread(/* dumpCompleted = */ true);
+ stdout_ = GetCapturedStdout();
+ stderr_ = GetCapturedStderr();
+ }
+
void AssertRunningServices(const std::vector<std::string>& services) {
std::string expected;
if (services.size() > 1) {
@@ -209,6 +225,7 @@
void AssertDumped(const std::string& service, const std::string& dump) {
EXPECT_THAT(stdout_, HasSubstr("DUMP OF SERVICE " + service + ":\n" + dump));
+ EXPECT_THAT(stdout_, HasSubstr("was the duration of dumpsys " + service + ", ending at: "));
}
void AssertDumpedWithPriority(const std::string& service, const std::string& dump,
@@ -216,6 +233,7 @@
std::string priority = String8(priorityType).c_str();
EXPECT_THAT(stdout_,
HasSubstr("DUMP OF SERVICE " + priority + " " + service + ":\n" + dump));
+ EXPECT_THAT(stdout_, HasSubstr("was the duration of dumpsys " + service + ", ending at: "));
}
void AssertNotDumped(const std::string& dump) {
@@ -425,8 +443,8 @@
CallMain({"--priority", "NORMAL"});
AssertRunningServices({"runningnormal1", "runningnormal2"});
- AssertDumpedWithPriority("runningnormal1", "dump1", PriorityDumper::PRIORITY_ARG_NORMAL);
- AssertDumpedWithPriority("runningnormal2", "dump2", PriorityDumper::PRIORITY_ARG_NORMAL);
+ AssertDumped("runningnormal1", "dump1");
+ AssertDumped("runningnormal2", "dump2");
}
// Tests 'dumpsys --proto'
@@ -461,3 +479,29 @@
AssertDumpedWithPriority("runninghigh1", "dump1", PriorityDumper::PRIORITY_ARG_HIGH);
AssertDumpedWithPriority("runninghigh2", "dump2", PriorityDumper::PRIORITY_ARG_HIGH);
}
+
+TEST_F(DumpsysTest, GetBytesWritten) {
+ const char* serviceName = "service2";
+ const char* dumpContents = "dump1";
+ ExpectDump(serviceName, dumpContents);
+
+ String16 service(serviceName);
+ Vector<String16> args;
+ std::chrono::duration<double> elapsedDuration;
+ size_t bytesWritten;
+
+ CallSingleService(service, args, IServiceManager::DUMP_FLAG_PRIORITY_ALL,
+ /* as_proto = */ false, elapsedDuration, bytesWritten);
+
+ AssertOutput(dumpContents);
+ EXPECT_THAT(bytesWritten, Eq(strlen(dumpContents)));
+}
+
+TEST_F(DumpsysTest, WriteDumpWithoutThreadStart) {
+ std::chrono::duration<double> elapsedDuration;
+ size_t bytesWritten;
+ status_t status =
+ dump_.writeDump(STDOUT_FILENO, String16("service"), std::chrono::milliseconds(500),
+ /* as_proto = */ false, elapsedDuration, bytesWritten);
+ EXPECT_THAT(status, Eq(INVALID_OPERATION));
+}
\ No newline at end of file
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 6f8c841..f787887 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -1898,7 +1898,7 @@
int32_t dexoptNeeded, const std::unique_ptr<std::string>& outputPath, int32_t dexFlags,
const std::string& compilerFilter, const std::unique_ptr<std::string>& uuid,
const std::unique_ptr<std::string>& classLoaderContext,
- const std::unique_ptr<std::string>& seInfo, bool downgrade) {
+ const std::unique_ptr<std::string>& seInfo, bool downgrade, int32_t targetSdkVersion) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
if (packageName && *packageName != "*") {
@@ -1916,7 +1916,7 @@
const char* se_info = seInfo ? seInfo->c_str() : nullptr;
int res = android::installd::dexopt(apk_path, uid, pkgname, instruction_set, dexoptNeeded,
oat_dir, dexFlags, compiler_filter, volume_uuid, class_loader_context, se_info,
- downgrade);
+ downgrade, targetSdkVersion);
return res ? error(res, "Failed to dexopt") : ok();
}
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index b494c7a..cef62cd 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -84,7 +84,8 @@
int32_t dexoptNeeded, const std::unique_ptr<std::string>& outputPath, int32_t dexFlags,
const std::string& compilerFilter, const std::unique_ptr<std::string>& uuid,
const std::unique_ptr<std::string>& classLoaderContext,
- const std::unique_ptr<std::string>& seInfo, bool downgrade);
+ const std::unique_ptr<std::string>& seInfo, bool downgrade,
+ int32_t targetSdkVersion);
binder::Status rmdex(const std::string& codePath, const std::string& instructionSet);
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 89585a0..c819e98 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -51,7 +51,7 @@
@nullable @utf8InCpp String outputPath, int dexFlags,
@utf8InCpp String compilerFilter, @nullable @utf8InCpp String uuid,
@nullable @utf8InCpp String sharedLibraries,
- @nullable @utf8InCpp String seInfo, boolean downgrade);
+ @nullable @utf8InCpp String seInfo, boolean downgrade, int targetSdkVersion);
void rmdex(@utf8InCpp String codePath, @utf8InCpp String instructionSet);
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 2e88e3c..0f635e0 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -217,7 +217,7 @@
const char* input_file_name, const char* output_file_name, int swap_fd,
const char* instruction_set, const char* compiler_filter,
bool debuggable, bool post_bootcomplete, bool background_job_compile, int profile_fd,
- const char* class_loader_context) {
+ const char* class_loader_context, int target_sdk_version, bool disable_hidden_api_checks) {
static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
@@ -328,6 +328,7 @@
bool have_dex2oat_image_fd = false;
char dex2oat_image_fd[arraysize("--app-image-fd=") + MAX_INT_LEN];
size_t class_loader_context_size = arraysize("--class-loader-context=") + PKG_PATH_MAX;
+ char target_sdk_version_arg[arraysize("-Xtarget-sdk-version:") + MAX_INT_LEN];
char class_loader_context_arg[class_loader_context_size];
if (class_loader_context != nullptr) {
snprintf(class_loader_context_arg, class_loader_context_size, "--class-loader-context=%s",
@@ -358,6 +359,7 @@
if (have_dex2oat_Xmx_flag) {
sprintf(dex2oat_Xmx_arg, "-Xmx%s", dex2oat_Xmx_flag);
}
+ sprintf(target_sdk_version_arg, "-Xtarget-sdk-version:%d", target_sdk_version);
// Compute compiler filter.
@@ -440,7 +442,9 @@
+ (has_base_dir ? 1 : 0)
+ (have_dex2oat_large_app_threshold ? 1 : 0)
+ (disable_cdex ? 1 : 0)
- + (generate_minidebug_info ? 1 : 0)];
+ + (generate_minidebug_info ? 1 : 0)
+ + (target_sdk_version != 0 ? 2 : 0)
+ + (disable_hidden_api_checks ? 2 : 0)];
int i = 0;
argv[i++] = dex2oat_bin;
argv[i++] = zip_fd_arg;
@@ -510,6 +514,14 @@
if (disable_cdex) {
argv[i++] = kDisableCompactDexFlag;
}
+ if (target_sdk_version != 0) {
+ argv[i++] = RUNTIME_ARG;
+ argv[i++] = target_sdk_version_arg;
+ }
+ if (disable_hidden_api_checks) {
+ argv[i++] = RUNTIME_ARG;
+ argv[i++] = "-Xno-hidden-api-checks";
+ }
// Do not add after dex2oat_flags, they should override others for debugging.
argv[i] = NULL;
@@ -1772,7 +1784,7 @@
int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* instruction_set,
int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
const char* volume_uuid, const char* class_loader_context, const char* se_info,
- bool downgrade) {
+ bool downgrade, int target_sdk_version) {
CHECK(pkgname != nullptr);
CHECK(pkgname[0] != 0);
if ((dexopt_flags & ~DEXOPT_MASK) != 0) {
@@ -1794,6 +1806,7 @@
bool profile_guided = (dexopt_flags & DEXOPT_PROFILE_GUIDED) != 0;
bool is_secondary_dex = (dexopt_flags & DEXOPT_SECONDARY_DEX) != 0;
bool background_job_compile = (dexopt_flags & DEXOPT_IDLE_BACKGROUND_JOB) != 0;
+ bool disable_hidden_api_checks = (dexopt_flags & DEXOPT_DISABLE_HIDDEN_API_CHECKS) != 0;
// Check if we're dealing with a secondary dex file and if we need to compile it.
std::string oat_dir_str;
@@ -1889,7 +1902,9 @@
boot_complete,
background_job_compile,
reference_profile_fd.get(),
- class_loader_context);
+ class_loader_context,
+ target_sdk_version,
+ disable_hidden_api_checks);
_exit(68); /* only get here on exec failure */
} else {
int res = wait_child(pid);
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 496f594..b1506c3 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -82,7 +82,7 @@
int dexopt(const char *apk_path, uid_t uid, const char *pkgName, const char *instruction_set,
int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
const char* volume_uuid, const char* class_loader_context, const char* se_info,
- bool downgrade);
+ bool downgrade, int target_sdk_version);
bool calculate_oat_file_path_default(char path[PKG_PATH_MAX], const char *oat_dir,
const char *apk_path, const char *instruction_set);
diff --git a/cmds/installd/installd_constants.h b/cmds/installd/installd_constants.h
index b49057d..9b6714d 100644
--- a/cmds/installd/installd_constants.h
+++ b/cmds/installd/installd_constants.h
@@ -52,6 +52,7 @@
// Tells the compiler that it is invoked from the background service. This
// controls whether extra debugging flags can be used (taking more compile time.)
constexpr int DEXOPT_IDLE_BACKGROUND_JOB = 1 << 9;
+constexpr int DEXOPT_DISABLE_HIDDEN_API_CHECKS = 1 << 10;
/* all known values for dexopt flags */
constexpr int DEXOPT_MASK =
@@ -62,7 +63,8 @@
| DEXOPT_SECONDARY_DEX
| DEXOPT_FORCE
| DEXOPT_STORAGE_CE
- | DEXOPT_STORAGE_DE;
+ | DEXOPT_STORAGE_DE
+ | DEXOPT_DISABLE_HIDDEN_API_CHECKS;
// NOTE: keep in sync with StorageManager
constexpr int FLAG_STORAGE_DE = 1 << 0;
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index d938d8a..dbd7051 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -78,8 +78,10 @@
static_assert(DEXOPT_FORCE == 1 << 6, "DEXOPT_FORCE unexpected.");
static_assert(DEXOPT_STORAGE_CE == 1 << 7, "DEXOPT_STORAGE_CE unexpected.");
static_assert(DEXOPT_STORAGE_DE == 1 << 8, "DEXOPT_STORAGE_DE unexpected.");
+static_assert(DEXOPT_DISABLE_HIDDEN_API_CHECKS == 1 << 10,
+ "DEXOPT_DISABLE_HIDDEN_API_CHECKS unexpected");
-static_assert(DEXOPT_MASK == 0x1fe, "DEXOPT_MASK unexpected.");
+static_assert(DEXOPT_MASK == 0x5fe, "DEXOPT_MASK unexpected.");
@@ -178,6 +180,7 @@
const char* shared_libraries;
const char* se_info;
bool downgrade;
+ int target_sdk_version;
};
bool ReadSystemProperties() {
@@ -358,6 +361,8 @@
return ReadArgumentsV2(argc, argv, true);
case 3:
return ReadArgumentsV3(argc, argv);
+ case 4:
+ return ReadArgumentsV4(argc, argv);
default:
LOG(ERROR) << "Unsupported version " << version;
@@ -440,6 +445,10 @@
// filter, which is not the case during ota.
package_parameters_.downgrade = false;
+ // Set target_sdk_version to 0, ie the platform SDK version. This is
+ // conservative and may force some classes to verify at runtime.
+ package_parameters_.target_sdk_version = 0;
+
if (param_index != 11) {
LOG(ERROR) << "Not enough parameters";
return false;
@@ -523,6 +532,10 @@
}
}
+ // Set target_sdk_version to 0, ie the platform SDK version. This is
+ // conservative and may force some classes to verify at runtime.
+ package_parameters_.target_sdk_version = 0;
+
if (param_index != 12) {
LOG(ERROR) << "Not enough parameters";
return false;
@@ -531,6 +544,93 @@
return true;
}
+ bool ReadArgumentsV4(int argc ATTRIBUTE_UNUSED, char** argv) {
+ size_t dexopt_index = 3;
+
+ // Check for "dexopt".
+ if (argv[dexopt_index] == nullptr) {
+ LOG(ERROR) << "Missing parameters";
+ return false;
+ }
+ if (std::string("dexopt").compare(argv[dexopt_index]) != 0) {
+ LOG(ERROR) << "Expected \"dexopt\"";
+ return false;
+ }
+
+ size_t param_index = 0;
+ for (;; ++param_index) {
+ const char* param = argv[dexopt_index + 1 + param_index];
+ if (param == nullptr) {
+ break;
+ }
+
+ switch (param_index) {
+ case 0:
+ package_parameters_.apk_path = param;
+ break;
+
+ case 1:
+ package_parameters_.uid = atoi(param);
+ break;
+
+ case 2:
+ package_parameters_.pkgName = param;
+ break;
+
+ case 3:
+ package_parameters_.instruction_set = param;
+ break;
+
+ case 4:
+ package_parameters_.dexopt_needed = atoi(param);
+ break;
+
+ case 5:
+ package_parameters_.oat_dir = param;
+ break;
+
+ case 6:
+ package_parameters_.dexopt_flags = atoi(param);
+ break;
+
+ case 7:
+ package_parameters_.compiler_filter = param;
+ break;
+
+ case 8:
+ package_parameters_.volume_uuid = ParseNull(param);
+ break;
+
+ case 9:
+ package_parameters_.shared_libraries = ParseNull(param);
+ break;
+
+ case 10:
+ package_parameters_.se_info = ParseNull(param);
+ break;
+
+ case 11:
+ package_parameters_.downgrade = ParseBool(param);
+ break;
+
+ case 12:
+ package_parameters_.target_sdk_version = atoi(param);
+ break;
+
+ default:
+ LOG(ERROR) << "Too many arguments, got " << param;
+ return false;
+ }
+ }
+
+ if (param_index != 13) {
+ LOG(ERROR) << "Not enough parameters";
+ return false;
+ }
+
+ return true;
+ }
+
static int ReplaceMask(int input, int old_mask, int new_mask) {
return (input & old_mask) != 0 ? new_mask : 0;
}
@@ -634,6 +734,10 @@
// filter, which is not the case during ota.
package_parameters_.downgrade = false;
+ // Set target_sdk_version to 0, ie the platform SDK version. This is
+ // conservative and may force some classes to verify at runtime.
+ package_parameters_.target_sdk_version = 0;
+
return true;
}
@@ -921,7 +1025,8 @@
package_parameters_.volume_uuid,
package_parameters_.shared_libraries,
package_parameters_.se_info,
- package_parameters_.downgrade);
+ package_parameters_.downgrade,
+ package_parameters_.target_sdk_version);
}
int RunPreopt() {
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index 2030997..c402c3c 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -59,6 +59,12 @@
// The file descriptor denoted by status-fd will be closed. The rest of the parameters will
// be passed on to otapreopt in the chroot.
static int otapreopt_chroot(const int argc, char **arg) {
+ // Validate arguments
+ // We need the command, status channel and target slot, at a minimum.
+ if(argc < 3) {
+ PLOG(ERROR) << "Not enough arguments.";
+ exit(208);
+ }
// Close all file descriptors. They are coming from the caller, we do not want to pass them
// on across our fork/exec into a different domain.
// 1) Default descriptors.
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index eaf0aa1..ff29506 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -258,6 +258,7 @@
std::unique_ptr<std::string> class_loader_context_ptr(new std::string("&"));
std::unique_ptr<std::string> se_info_ptr(new std::string(se_info_));
bool downgrade = false;
+ int32_t target_sdk_version = 0; // default
binder::Status result = service_->dexopt(path,
uid,
@@ -270,7 +271,8 @@
volume_uuid_,
class_loader_context_ptr,
se_info_ptr,
- downgrade);
+ downgrade,
+ target_sdk_version);
ASSERT_EQ(should_binder_call_succeed, result.isOk());
int expected_access = should_dex_be_compiled ? 0 : -1;
std::string odex = GetSecondaryDexArtifact(path, "odex");
diff --git a/cmds/lshal/DebugCommand.cpp b/cmds/lshal/DebugCommand.cpp
index f371320..dd8812d 100644
--- a/cmds/lshal/DebugCommand.cpp
+++ b/cmds/lshal/DebugCommand.cpp
@@ -35,6 +35,14 @@
if (optind >= arg.argc) {
return USAGE;
}
+
+ // Optargs cannnot be used because the flag should not be considered set
+ // if it should really be contained in mOptions.
+ if (std::string(arg.argv[optind]) == "-E") {
+ mExcludesParentInstances = true;
+ optind++;
+ }
+
mInterfaceName = arg.argv[optind];
++optind;
for (; optind < arg.argc; ++optind) {
@@ -59,6 +67,7 @@
return mLshal.emitDebugInfo(
pair.first, pair.second.empty() ? "default" : pair.second, mOptions,
+ mExcludesParentInstances,
mLshal.out().buf(),
mLshal.err());
}
@@ -67,8 +76,9 @@
static const std::string debug =
"debug:\n"
- " lshal debug <interface> [options [options [...]]] \n"
+ " lshal debug [-E] <interface> [options [options [...]]] \n"
" Print debug information of a specified interface.\n"
+ " -E: excludes debug output if HAL is actually a subclass.\n"
" <inteface>: Format is `android.hardware.foo@1.0::IFoo/default`.\n"
" If instance name is missing `default` is used.\n"
" options: space separated options to IBase::debug.\n";
diff --git a/cmds/lshal/DebugCommand.h b/cmds/lshal/DebugCommand.h
index 9b91084..6e12008 100644
--- a/cmds/lshal/DebugCommand.h
+++ b/cmds/lshal/DebugCommand.h
@@ -43,6 +43,10 @@
std::string mInterfaceName;
std::vector<std::string> mOptions;
+ // Outputs the actual descriptor of a hal instead of the debug output
+ // if the arguments provided are a superclass of the actual hal impl.
+ bool mExcludesParentInstances;
+
DISALLOW_COPY_AND_ASSIGN(DebugCommand);
};
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index 7399692..e4b3c90 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -397,7 +397,8 @@
emitDebugInfo = [this](const auto& iName) {
std::stringstream ss;
auto pair = splitFirst(iName, '/');
- mLshal.emitDebugInfo(pair.first, pair.second, {}, ss,
+ mLshal.emitDebugInfo(pair.first, pair.second, {},
+ false /* excludesParentInstances */, ss,
NullableOStream<std::ostream>(nullptr));
return ss.str();
};
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index c6f28ac..8c83457 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -23,6 +23,7 @@
#include <string>
#include <hidl/ServiceManagement.h>
+#include <hidl/HidlTransportUtils.h>
#include "DebugCommand.h"
#include "ListCommand.h"
@@ -97,9 +98,11 @@
const std::string &interfaceName,
const std::string &instanceName,
const std::vector<std::string> &options,
+ bool excludesParentInstances,
std::ostream &out,
NullableOStream<std::ostream> err) const {
using android::hidl::base::V1_0::IBase;
+ using android::hardware::details::getDescriptor;
hardware::Return<sp<IBase>> retBase = serviceManager()->get(interfaceName, instanceName);
@@ -120,6 +123,18 @@
return NO_INTERFACE;
}
+ if (excludesParentInstances) {
+ const std::string descriptor = getDescriptor(base.get());
+ if (descriptor.empty()) {
+ std::string msg = interfaceName + "/" + instanceName + " getDescriptor failed";
+ err << msg << std::endl;
+ LOG(ERROR) << msg;
+ }
+ if (descriptor != interfaceName) {
+ return OK;
+ }
+ }
+
PipeRelay relay(out);
if (relay.initCheck() != OK) {
diff --git a/cmds/lshal/Lshal.h b/cmds/lshal/Lshal.h
index 690f30e..9457f1e 100644
--- a/cmds/lshal/Lshal.h
+++ b/cmds/lshal/Lshal.h
@@ -51,6 +51,7 @@
const std::string &interfaceName,
const std::string &instanceName,
const std::vector<std::string> &options,
+ bool excludesParentInstances,
std::ostream &out,
NullableOStream<std::ostream> err) const;
diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
index d790bed..6d739a1 100644
--- a/data/etc/handheld_core_hardware.xml
+++ b/data/etc/handheld_core_hardware.xml
@@ -57,10 +57,8 @@
<!-- Feature to specify if the device support managed users. -->
<feature name="android.software.managed_users" notLowRam="true"/>
- <!-- Feature to specify if the device supports a VR mode.
- feature name="android.software.vr.mode" -->
- <!-- Devices with all optimizations required to be a "VR Ready" device that
- pass all CTS tests for this feature must include feature
+ <!-- Devices with all optimizations required to support VR Mode and
+ pass all CDD requirements for this feature may include
android.hardware.vr.high_performance -->
<!-- Devices that support VR headtracking features and pass all CDD
requirements may include
diff --git a/headers/media_plugin/media/openmax/OMX_IVCommon.h b/headers/media_plugin/media/openmax/OMX_IVCommon.h
index f9b6f4b..758d7cf 100644
--- a/headers/media_plugin/media/openmax/OMX_IVCommon.h
+++ b/headers/media_plugin/media/openmax/OMX_IVCommon.h
@@ -165,6 +165,12 @@
* format for it. */
OMX_COLOR_FormatYUV420Flexible = 0x7F420888,
+ // 10-bit or 12-bit YUV format, LSB-justified (0's on higher bits)
+ OMX_COLOR_FormatYUV420Planar16 = 0x7F42016B,
+
+ // 32-bit RGBA format, 10-bit per channel, alpha channel in highest 2-bit
+ OMX_COLOR_Format32BitRGBA1010102 = 0x7F00AAAA,
+
OMX_TI_COLOR_FormatYUV420PackedSemiPlanar = 0x7F000100,
OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00,
OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka = 0x7FA30C03,
diff --git a/include/audiomanager/IAudioManager.h b/include/audiomanager/IAudioManager.h
index ce7804b..067dc5c 100644
--- a/include/audiomanager/IAudioManager.h
+++ b/include/audiomanager/IAudioManager.h
@@ -110,6 +110,11 @@
/*
DISABLE_RINGTONE_SYNC = IBinder::FIRST_CALL_TRANSACTION + 71,
+ GET_FOCUS_RAMP_TIME_MS = IBinder::FIRST_CALL_TRANSACTION + 72,
+ DISPATCH_FOCUS_CHANGE = IBinder::FIRST_CALL_TRANSACTION + 73,
+ PLAYER_HAS_OP_PLAY_AUDIO = IBinder::FIRST_CALL_TRANSACTION + 74,
+ SET_BLUETOOTH_A2DP_DEVICE_CONNECTION_STATE_SUPPRESS_NOISY_INTENT
+ = IBinder::FIRST_CALL_TRANSACTION + 75,
*/
};
diff --git a/libs/binder/ActivityManager.cpp b/libs/binder/ActivityManager.cpp
index 2904718..7724bf1 100644
--- a/libs/binder/ActivityManager.cpp
+++ b/libs/binder/ActivityManager.cpp
@@ -39,7 +39,7 @@
if (startTime == 0) {
startTime = uptimeMillis();
ALOGI("Waiting for activity service");
- } else if ((uptimeMillis() - startTime) > 10000) {
+ } else if ((uptimeMillis() - startTime) > 1000000) {
ALOGW("Waiting too long for activity service, giving up");
service = NULL;
break;
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 2a07cd1..6103188 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -63,6 +63,7 @@
"MemoryHeapBase.cpp",
"Parcel.cpp",
"PermissionCache.cpp",
+ "PermissionController.cpp",
"PersistableBundle.cpp",
"ProcessInfoService.cpp",
"ProcessState.cpp",
@@ -94,6 +95,7 @@
"liblog",
"libcutils",
"libutils",
+ "libutilscallstack",
],
header_libs: [
diff --git a/libs/binder/IPermissionController.cpp b/libs/binder/IPermissionController.cpp
index 674bddf..ef67ab8 100644
--- a/libs/binder/IPermissionController.cpp
+++ b/libs/binder/IPermissionController.cpp
@@ -78,6 +78,18 @@
if (reply.readExceptionCode() != 0) return false;
return reply.readInt32() != 0;
}
+
+ virtual int getPackageUid(const String16& package, int flags)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor());
+ data.writeString16(package);
+ data.writeInt32(flags);
+ remote()->transact(GET_PACKAGE_UID_TRANSACTION, data, &reply);
+ // fail on exception
+ if (reply.readExceptionCode() != 0) return false;
+ return reply.readInt32();
+ }
};
IMPLEMENT_META_INTERFACE(PermissionController, "android.os.IPermissionController");
@@ -122,6 +134,16 @@
return NO_ERROR;
} break;
+ case GET_PACKAGE_UID_TRANSACTION: {
+ CHECK_INTERFACE(IPermissionController, data, reply);
+ String16 package = data.readString16();
+ int flags = data.readInt32();
+ const int uid = getPackageUid(package, flags);
+ reply->writeNoException();
+ reply->writeInt32(uid);
+ return NO_ERROR;
+ } break;
+
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/binder/PermissionController.cpp b/libs/binder/PermissionController.cpp
new file mode 100644
index 0000000..25748ca
--- /dev/null
+++ b/libs/binder/PermissionController.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <mutex>
+#include <binder/PermissionController.h>
+#include <binder/Binder.h>
+#include <binder/IServiceManager.h>
+
+#include <utils/SystemClock.h>
+
+namespace android {
+
+PermissionController::PermissionController()
+{
+}
+
+sp<IPermissionController> PermissionController::getService()
+{
+ std::lock_guard<Mutex> scoped_lock(mLock);
+ int64_t startTime = 0;
+ sp<IPermissionController> service = mService;
+ while (service == nullptr || !IInterface::asBinder(service)->isBinderAlive()) {
+ sp<IBinder> binder = defaultServiceManager()->checkService(String16("permission"));
+ if (binder == nullptr) {
+ // Wait for the activity service to come back...
+ if (startTime == 0) {
+ startTime = uptimeMillis();
+ ALOGI("Waiting for permission service");
+ } else if ((uptimeMillis() - startTime) > 10000) {
+ ALOGW("Waiting too long for permission service, giving up");
+ service = NULL;
+ break;
+ }
+ sleep(1);
+ } else {
+ service = interface_cast<IPermissionController>(binder);
+ mService = service;
+ }
+ }
+ return service;
+}
+
+bool PermissionController::checkPermission(const String16& permission, int32_t pid, int32_t uid)
+{
+ sp<IPermissionController> service = getService();
+ return service != NULL ? service->checkPermission(permission, pid, uid) : false;
+}
+
+void PermissionController::getPackagesForUid(const uid_t uid, Vector<String16> &packages)
+{
+ sp<IPermissionController> service = getService();
+ if (service != nullptr) {
+ service->getPackagesForUid(uid, packages);
+ }
+}
+
+bool PermissionController::isRuntimePermission(const String16& permission)
+{
+ sp<IPermissionController> service = getService();
+ return service != nullptr ? service->isRuntimePermission(permission) : false;
+}
+
+int PermissionController::getPackageUid(const String16& package, int flags)
+{
+ sp<IPermissionController> service = getService();
+ return service != nullptr ? service->getPackageUid(package, flags) : -1;
+}
+
+}; // namespace android
diff --git a/libs/binder/include/binder/IPermissionController.h b/libs/binder/include/binder/IPermissionController.h
index 25f3431..2f63677 100644
--- a/libs/binder/include/binder/IPermissionController.h
+++ b/libs/binder/include/binder/IPermissionController.h
@@ -36,10 +36,13 @@
virtual bool isRuntimePermission(const String16& permission) = 0;
+ virtual int getPackageUid(const String16& package, int flags) = 0;
+
enum {
CHECK_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
GET_PACKAGES_FOR_UID_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 1,
- IS_RUNTIME_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 2
+ IS_RUNTIME_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 2,
+ GET_PACKAGE_UID_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 3
};
};
diff --git a/libs/binder/include/binder/PermissionController.h b/libs/binder/include/binder/PermissionController.h
new file mode 100644
index 0000000..c4c98d0
--- /dev/null
+++ b/libs/binder/include/binder/PermissionController.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_PERMISSION_CONTROLLER_H
+#define ANDROID_PERMISSION_CONTROLLER_H
+
+#include <binder/IPermissionController.h>
+
+#include <utils/threads.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class PermissionController
+{
+public:
+
+ enum {
+ MATCH_SYSTEM_ONLY = 1<<16,
+ MATCH_UNINSTALLED_PACKAGES = 1<<13,
+ MATCH_FACTORY_ONLY = 1<<21,
+ MATCH_INSTANT = 1<<23
+ };
+
+ PermissionController();
+
+ bool checkPermission(const String16& permission, int32_t pid, int32_t uid);
+ void getPackagesForUid(const uid_t uid, Vector<String16>& packages);
+ bool isRuntimePermission(const String16& permission);
+ int getPackageUid(const String16& package, int flags);
+
+private:
+ Mutex mLock;
+ sp<IPermissionController> mService;
+
+ sp<IPermissionController> getService();
+};
+
+
+}; // namespace android
+// ---------------------------------------------------------------------------
+#endif // ANDROID_PERMISSION_CONTROLLER_H
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 7ee4d49..ad04d03 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -62,6 +62,9 @@
// Allow documentation warnings
"-Wno-documentation",
+ // Allow implicit instantiation for templated class function
+ "-Wno-undefined-func-template",
+
"-DDEBUG_ONLY_CODE=0",
],
@@ -79,6 +82,7 @@
srcs: [
"BitTube.cpp",
+ "BufferHubProducer.cpp",
"BufferItem.cpp",
"BufferItemConsumer.cpp",
"BufferQueue.cpp",
@@ -131,7 +135,15 @@
"android.hardware.configstore-utils",
],
+ // TODO(b/70046255): Remove these once BufferHub is integrated into libgui.
+ static_libs: [
+ "libbufferhub",
+ "libbufferhubqueue",
+ "libpdx_default_transport",
+ ],
+
header_libs: [
+ "libdvr_headers",
"libnativebase_headers",
"libgui_headers",
],
diff --git a/libs/gui/BufferHubProducer.cpp b/libs/gui/BufferHubProducer.cpp
new file mode 100644
index 0000000..af1f833
--- /dev/null
+++ b/libs/gui/BufferHubProducer.cpp
@@ -0,0 +1,710 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Weverything"
+#endif
+
+// The following headers are included without checking every warning.
+// TODO(b/72172820): Remove the workaround once we have enforced -Weverything
+// in these headers and their dependencies.
+#include <dvr/dvr_api.h>
+#include <gui/BufferHubProducer.h>
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
+#include <inttypes.h>
+#include <log/log.h>
+#include <system/window.h>
+
+namespace android {
+
+/* static */
+sp<BufferHubProducer> BufferHubProducer::Create(const std::shared_ptr<dvr::ProducerQueue>& queue) {
+ if (queue->metadata_size() != sizeof(DvrNativeBufferMetadata)) {
+ ALOGE("BufferHubProducer::Create producer's metadata size is different "
+ "than the size of DvrNativeBufferMetadata");
+ return nullptr;
+ }
+
+ sp<BufferHubProducer> producer = new BufferHubProducer;
+ producer->queue_ = queue;
+ return producer;
+}
+
+/* static */
+sp<BufferHubProducer> BufferHubProducer::Create(dvr::ProducerQueueParcelable parcelable) {
+ if (!parcelable.IsValid()) {
+ ALOGE("BufferHubProducer::Create: Invalid producer parcelable.");
+ return nullptr;
+ }
+
+ sp<BufferHubProducer> producer = new BufferHubProducer;
+ producer->queue_ = dvr::ProducerQueue::Import(parcelable.TakeChannelHandle());
+ return producer;
+}
+
+status_t BufferHubProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
+ ALOGV("requestBuffer: slot=%d", slot);
+
+ std::unique_lock<std::mutex> lock(mutex_);
+
+ if (connected_api_ == kNoConnectedApi) {
+ ALOGE("requestBuffer: BufferHubProducer has no connected producer");
+ return NO_INIT;
+ }
+
+ if (slot < 0 || slot >= max_buffer_count_) {
+ ALOGE("requestBuffer: slot index %d out of range [0, %d)", slot, max_buffer_count_);
+ return BAD_VALUE;
+ } else if (!buffers_[slot].mBufferState.isDequeued()) {
+ ALOGE("requestBuffer: slot %d is not owned by the producer (state = %s)", slot,
+ buffers_[slot].mBufferState.string());
+ return BAD_VALUE;
+ } else if (buffers_[slot].mGraphicBuffer != nullptr) {
+ ALOGE("requestBuffer: slot %d is not empty.", slot);
+ return BAD_VALUE;
+ } else if (buffers_[slot].mBufferProducer == nullptr) {
+ ALOGE("requestBuffer: slot %d is not dequeued.", slot);
+ return BAD_VALUE;
+ }
+
+ const auto& buffer_producer = buffers_[slot].mBufferProducer;
+ sp<GraphicBuffer> graphic_buffer = buffer_producer->buffer()->buffer();
+
+ buffers_[slot].mGraphicBuffer = graphic_buffer;
+ buffers_[slot].mRequestBufferCalled = true;
+
+ *buf = graphic_buffer;
+ return NO_ERROR;
+}
+
+status_t BufferHubProducer::setMaxDequeuedBufferCount(int max_dequeued_buffers) {
+ ALOGV("setMaxDequeuedBufferCount: max_dequeued_buffers=%d", max_dequeued_buffers);
+
+ std::unique_lock<std::mutex> lock(mutex_);
+
+ if (max_dequeued_buffers <= 0 ||
+ max_dequeued_buffers >
+ int(dvr::BufferHubQueue::kMaxQueueCapacity - kDefaultUndequeuedBuffers)) {
+ ALOGE("setMaxDequeuedBufferCount: %d out of range (0, %zu]", max_dequeued_buffers,
+ dvr::BufferHubQueue::kMaxQueueCapacity);
+ return BAD_VALUE;
+ }
+
+ // The new dequeued_buffers count should not be violated by the number
+ // of currently dequeued buffers.
+ int dequeued_count = 0;
+ for (const auto& buf : buffers_) {
+ if (buf.mBufferState.isDequeued()) {
+ dequeued_count++;
+ }
+ }
+ if (dequeued_count > max_dequeued_buffers) {
+ ALOGE("setMaxDequeuedBufferCount: the requested dequeued_buffers"
+ "count (%d) exceeds the current dequeued buffer count (%d)",
+ max_dequeued_buffers, dequeued_count);
+ return BAD_VALUE;
+ }
+
+ max_dequeued_buffer_count_ = max_dequeued_buffers;
+ return NO_ERROR;
+}
+
+status_t BufferHubProducer::setAsyncMode(bool async) {
+ if (async) {
+ // TODO(b/36724099) BufferHubQueue's consumer end always acquires the buffer
+ // automatically and behaves differently from IGraphicBufferConsumer. Thus,
+ // android::BufferQueue's async mode (a.k.a. allocating an additional buffer
+ // to prevent dequeueBuffer from being blocking) technically does not apply
+ // here.
+ //
+ // In Daydream, non-blocking producer side dequeue is guaranteed by careful
+ // buffer consumer implementations. In another word, BufferHubQueue based
+ // dequeueBuffer should never block whether setAsyncMode(true) is set or
+ // not.
+ //
+ // See: IGraphicBufferProducer::setAsyncMode and
+ // BufferQueueProducer::setAsyncMode for more about original implementation.
+ ALOGW("BufferHubProducer::setAsyncMode: BufferHubQueue should always be "
+ "asynchronous. This call makes no effact.");
+ return NO_ERROR;
+ }
+ return NO_ERROR;
+}
+
+status_t BufferHubProducer::dequeueBuffer(int* out_slot, sp<Fence>* out_fence, uint32_t width,
+ uint32_t height, PixelFormat format, uint64_t usage,
+ uint64_t* /*outBufferAge*/,
+ FrameEventHistoryDelta* /* out_timestamps */) {
+ ALOGV("dequeueBuffer: w=%u, h=%u, format=%d, usage=%" PRIu64, width, height, format, usage);
+
+ status_t ret;
+ std::unique_lock<std::mutex> lock(mutex_);
+
+ if (connected_api_ == kNoConnectedApi) {
+ ALOGE("dequeueBuffer: BufferQueue has no connected producer");
+ return NO_INIT;
+ }
+
+ const uint32_t kLayerCount = 1;
+ if (int32_t(queue_->capacity()) < max_dequeued_buffer_count_ + kDefaultUndequeuedBuffers) {
+ // Lazy allocation. When the capacity of |queue_| has not reached
+ // |max_dequeued_buffer_count_|, allocate new buffer.
+ // TODO(jwcai) To save memory, the really reasonable thing to do is to go
+ // over existing slots and find first existing one to dequeue.
+ ret = AllocateBuffer(width, height, kLayerCount, format, usage);
+ if (ret < 0) return ret;
+ }
+
+ size_t slot = 0;
+ std::shared_ptr<dvr::BufferProducer> buffer_producer;
+
+ for (size_t retry = 0; retry < dvr::BufferHubQueue::kMaxQueueCapacity; retry++) {
+ LocalHandle fence;
+ auto buffer_status = queue_->Dequeue(dequeue_timeout_ms_, &slot, &fence);
+ if (!buffer_status) return NO_MEMORY;
+
+ buffer_producer = buffer_status.take();
+ if (!buffer_producer) return NO_MEMORY;
+
+ if (width == buffer_producer->width() && height == buffer_producer->height() &&
+ uint32_t(format) == buffer_producer->format()) {
+ // The producer queue returns a buffer producer matches the request.
+ break;
+ }
+
+ // Needs reallocation.
+ // TODO(jwcai) Consider use VLOG instead if we find this log is not useful.
+ ALOGI("dequeueBuffer: requested buffer (w=%u, h=%u, format=%u) is different "
+ "from the buffer returned at slot: %zu (w=%u, h=%u, format=%u). Need "
+ "re-allocattion.",
+ width, height, format, slot, buffer_producer->width(), buffer_producer->height(),
+ buffer_producer->format());
+ // Mark the slot as reallocating, so that later we can set
+ // BUFFER_NEEDS_REALLOCATION when the buffer actually get dequeued.
+ buffers_[slot].mIsReallocating = true;
+
+ // Remove the old buffer once the allocation before allocating its
+ // replacement.
+ RemoveBuffer(slot);
+
+ // Allocate a new producer buffer with new buffer configs. Note that if
+ // there are already multiple buffers in the queue, the next one returned
+ // from |queue_->Dequeue| may not be the new buffer we just reallocated.
+ // Retry up to BufferHubQueue::kMaxQueueCapacity times.
+ ret = AllocateBuffer(width, height, kLayerCount, format, usage);
+ if (ret < 0) return ret;
+ }
+
+ // With the BufferHub backed solution. Buffer slot returned from
+ // |queue_->Dequeue| is guaranteed to avaiable for producer's use.
+ // It's either in free state (if the buffer has never been used before) or
+ // in queued state (if the buffer has been dequeued and queued back to
+ // BufferHubQueue).
+ LOG_ALWAYS_FATAL_IF((!buffers_[slot].mBufferState.isFree() &&
+ !buffers_[slot].mBufferState.isQueued()),
+ "dequeueBuffer: slot %zu is not free or queued, actual state: %s.", slot,
+ buffers_[slot].mBufferState.string());
+
+ buffers_[slot].mBufferState.freeQueued();
+ buffers_[slot].mBufferState.dequeue();
+ ALOGV("dequeueBuffer: slot=%zu", slot);
+
+ // TODO(jwcai) Handle fence properly. |BufferHub| has full fence support, we
+ // just need to exopose that through |BufferHubQueue| once we need fence.
+ *out_fence = Fence::NO_FENCE;
+ *out_slot = int(slot);
+ ret = NO_ERROR;
+
+ if (buffers_[slot].mIsReallocating) {
+ ret |= BUFFER_NEEDS_REALLOCATION;
+ buffers_[slot].mIsReallocating = false;
+ }
+
+ return ret;
+}
+
+status_t BufferHubProducer::detachBuffer(int /* slot */) {
+ ALOGE("BufferHubProducer::detachBuffer not implemented.");
+ return INVALID_OPERATION;
+}
+
+status_t BufferHubProducer::detachNextBuffer(sp<GraphicBuffer>* /* out_buffer */,
+ sp<Fence>* /* out_fence */) {
+ ALOGE("BufferHubProducer::detachNextBuffer not implemented.");
+ return INVALID_OPERATION;
+}
+
+status_t BufferHubProducer::attachBuffer(int* /* out_slot */,
+ const sp<GraphicBuffer>& /* buffer */) {
+ // With this BufferHub backed implementation, we assume (for now) all buffers
+ // are allocated and owned by the BufferHub. Thus the attempt of transfering
+ // ownership of a buffer to the buffer queue is intentionally unsupported.
+ LOG_ALWAYS_FATAL("BufferHubProducer::attachBuffer not supported.");
+ return INVALID_OPERATION;
+}
+
+status_t BufferHubProducer::queueBuffer(int slot, const QueueBufferInput& input,
+ QueueBufferOutput* output) {
+ ALOGV("queueBuffer: slot %d", slot);
+
+ if (output == nullptr) {
+ return BAD_VALUE;
+ }
+
+ int64_t timestamp;
+ bool is_auto_timestamp;
+ android_dataspace dataspace;
+ Rect crop(Rect::EMPTY_RECT);
+ int scaling_mode;
+ uint32_t transform;
+ sp<Fence> fence;
+
+ input.deflate(×tamp, &is_auto_timestamp, &dataspace, &crop, &scaling_mode, &transform,
+ &fence);
+
+ // Check input scaling mode is valid.
+ switch (scaling_mode) {
+ case NATIVE_WINDOW_SCALING_MODE_FREEZE:
+ case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
+ case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
+ case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP:
+ break;
+ default:
+ ALOGE("queueBuffer: unknown scaling mode %d", scaling_mode);
+ return BAD_VALUE;
+ }
+
+ // Check input fence is valid.
+ if (fence == nullptr) {
+ ALOGE("queueBuffer: fence is NULL");
+ return BAD_VALUE;
+ }
+
+ std::unique_lock<std::mutex> lock(mutex_);
+
+ if (connected_api_ == kNoConnectedApi) {
+ ALOGE("queueBuffer: BufferQueue has no connected producer");
+ return NO_INIT;
+ }
+
+ if (slot < 0 || slot >= max_buffer_count_) {
+ ALOGE("queueBuffer: slot index %d out of range [0, %d)", slot, max_buffer_count_);
+ return BAD_VALUE;
+ } else if (!buffers_[slot].mBufferState.isDequeued()) {
+ ALOGE("queueBuffer: slot %d is not owned by the producer (state = %s)", slot,
+ buffers_[slot].mBufferState.string());
+ return BAD_VALUE;
+ } else if ((!buffers_[slot].mRequestBufferCalled || buffers_[slot].mGraphicBuffer == nullptr)) {
+ ALOGE("queueBuffer: slot %d is not requested (mRequestBufferCalled=%d, "
+ "mGraphicBuffer=%p)",
+ slot, buffers_[slot].mRequestBufferCalled, buffers_[slot].mGraphicBuffer.get());
+ return BAD_VALUE;
+ }
+
+ // Post the buffer producer with timestamp in the metadata.
+ const auto& buffer_producer = buffers_[slot].mBufferProducer;
+
+ // Check input crop is not out of boundary of current buffer.
+ Rect buffer_rect(buffer_producer->width(), buffer_producer->height());
+ Rect cropped_rect(Rect::EMPTY_RECT);
+ crop.intersect(buffer_rect, &cropped_rect);
+ if (cropped_rect != crop) {
+ ALOGE("queueBuffer: slot %d has out-of-boundary crop.", slot);
+ return BAD_VALUE;
+ }
+
+ LocalHandle fence_fd(fence->isValid() ? fence->dup() : -1);
+
+ DvrNativeBufferMetadata meta_data;
+ meta_data.timestamp = timestamp;
+ meta_data.is_auto_timestamp = int32_t(is_auto_timestamp);
+ meta_data.dataspace = int32_t(dataspace);
+ meta_data.crop_left = crop.left;
+ meta_data.crop_top = crop.top;
+ meta_data.crop_right = crop.right;
+ meta_data.crop_bottom = crop.bottom;
+ meta_data.scaling_mode = int32_t(scaling_mode);
+ meta_data.transform = int32_t(transform);
+
+ buffer_producer->PostAsync(&meta_data, fence_fd);
+ buffers_[slot].mBufferState.queue();
+
+ output->width = buffer_producer->width();
+ output->height = buffer_producer->height();
+ output->transformHint = 0; // default value, we don't use it yet.
+
+ // |numPendingBuffers| counts of the number of buffers that has been enqueued
+ // by the producer but not yet acquired by the consumer. Due to the nature
+ // of BufferHubQueue design, this is hard to trace from the producer's client
+ // side, but it's safe to assume it's zero.
+ output->numPendingBuffers = 0;
+
+ // Note that we are not setting nextFrameNumber here as it seems to be only
+ // used by surface flinger. See more at b/22802885, ag/791760.
+ output->nextFrameNumber = 0;
+
+ return NO_ERROR;
+}
+
+status_t BufferHubProducer::cancelBuffer(int slot, const sp<Fence>& fence) {
+ ALOGV(__FUNCTION__);
+
+ std::unique_lock<std::mutex> lock(mutex_);
+
+ if (connected_api_ == kNoConnectedApi) {
+ ALOGE("cancelBuffer: BufferQueue has no connected producer");
+ return NO_INIT;
+ }
+
+ if (slot < 0 || slot >= max_buffer_count_) {
+ ALOGE("cancelBuffer: slot index %d out of range [0, %d)", slot, max_buffer_count_);
+ return BAD_VALUE;
+ } else if (!buffers_[slot].mBufferState.isDequeued()) {
+ ALOGE("cancelBuffer: slot %d is not owned by the producer (state = %s)", slot,
+ buffers_[slot].mBufferState.string());
+ return BAD_VALUE;
+ } else if (fence == nullptr) {
+ ALOGE("cancelBuffer: fence is NULL");
+ return BAD_VALUE;
+ }
+
+ auto buffer_producer = buffers_[slot].mBufferProducer;
+ queue_->Enqueue(buffer_producer, size_t(slot), 0ULL);
+ buffers_[slot].mBufferState.cancel();
+ buffers_[slot].mFence = fence;
+ ALOGV("cancelBuffer: slot %d", slot);
+
+ return NO_ERROR;
+}
+
+status_t BufferHubProducer::query(int what, int* out_value) {
+ ALOGV(__FUNCTION__);
+
+ std::unique_lock<std::mutex> lock(mutex_);
+
+ if (out_value == nullptr) {
+ ALOGE("query: out_value was NULL");
+ return BAD_VALUE;
+ }
+
+ int value = 0;
+ switch (what) {
+ case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
+ // TODO(b/36187402) This should be the maximum number of buffers that this
+ // producer queue's consumer can acquire. Set to be at least one. Need to
+ // find a way to set from the consumer side.
+ value = kDefaultUndequeuedBuffers;
+ break;
+ case NATIVE_WINDOW_BUFFER_AGE:
+ value = 0;
+ break;
+ case NATIVE_WINDOW_WIDTH:
+ value = int32_t(queue_->default_width());
+ break;
+ case NATIVE_WINDOW_HEIGHT:
+ value = int32_t(queue_->default_height());
+ break;
+ case NATIVE_WINDOW_FORMAT:
+ value = int32_t(queue_->default_format());
+ break;
+ case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND:
+ // BufferHubQueue is always operating in async mode, thus semantically
+ // consumer can never be running behind. See BufferQueueCore.cpp core
+ // for more information about the original meaning of this flag.
+ value = 0;
+ break;
+ case NATIVE_WINDOW_CONSUMER_USAGE_BITS:
+ // TODO(jwcai) This is currently not implement as we don't need
+ // IGraphicBufferConsumer parity.
+ value = 0;
+ break;
+ case NATIVE_WINDOW_DEFAULT_DATASPACE:
+ // TODO(jwcai) Return the default value android::BufferQueue is using as
+ // there is no way dvr::ConsumerQueue can set it.
+ value = 0; // HAL_DATASPACE_UNKNOWN
+ break;
+ case NATIVE_WINDOW_STICKY_TRANSFORM:
+ // TODO(jwcai) Return the default value android::BufferQueue is using as
+ // there is no way dvr::ConsumerQueue can set it.
+ value = 0;
+ break;
+ case NATIVE_WINDOW_CONSUMER_IS_PROTECTED:
+ // In Daydream's implementation, the consumer end (i.e. VR Compostior)
+ // knows how to handle protected buffers.
+ value = 1;
+ break;
+ default:
+ return BAD_VALUE;
+ }
+
+ ALOGV("query: key=%d, v=%d", what, value);
+ *out_value = value;
+ return NO_ERROR;
+}
+
+status_t BufferHubProducer::connect(const sp<IProducerListener>& /* listener */, int api,
+ bool /* producer_controlled_by_app */,
+ QueueBufferOutput* output) {
+ // Consumer interaction are actually handled by buffer hub, and we need
+ // to maintain consumer operations here. We only need to perform basic input
+ // parameter checks here.
+ ALOGV(__FUNCTION__);
+
+ if (output == nullptr) {
+ return BAD_VALUE;
+ }
+
+ std::unique_lock<std::mutex> lock(mutex_);
+
+ if (connected_api_ != kNoConnectedApi) {
+ return BAD_VALUE;
+ }
+
+ if (!queue_->is_connected()) {
+ ALOGE("BufferHubProducer::connect: This BufferHubProducer is not "
+ "connected to bufferhud. Has it been taken out as a parcelable?");
+ return BAD_VALUE;
+ }
+
+ switch (api) {
+ case NATIVE_WINDOW_API_EGL:
+ case NATIVE_WINDOW_API_CPU:
+ case NATIVE_WINDOW_API_MEDIA:
+ case NATIVE_WINDOW_API_CAMERA:
+ connected_api_ = api;
+
+ output->width = queue_->default_width();
+ output->height = queue_->default_height();
+
+ // default values, we don't use them yet.
+ output->transformHint = 0;
+ output->numPendingBuffers = 0;
+ output->nextFrameNumber = 0;
+ output->bufferReplaced = false;
+
+ break;
+ default:
+ ALOGE("BufferHubProducer::connect: unknow API %d", api);
+ return BAD_VALUE;
+ }
+
+ return NO_ERROR;
+}
+
+status_t BufferHubProducer::disconnect(int api, DisconnectMode /*mode*/) {
+ // Consumer interaction are actually handled by buffer hub, and we need
+ // to maintain consumer operations here. We only need to perform basic input
+ // parameter checks here.
+ ALOGV(__FUNCTION__);
+
+ std::unique_lock<std::mutex> lock(mutex_);
+
+ if (kNoConnectedApi == connected_api_) {
+ return NO_INIT;
+ } else if (api != connected_api_) {
+ return BAD_VALUE;
+ }
+
+ FreeAllBuffers();
+ connected_api_ = kNoConnectedApi;
+ return NO_ERROR;
+}
+
+status_t BufferHubProducer::setSidebandStream(const sp<NativeHandle>& stream) {
+ if (stream != nullptr) {
+ // TODO(jwcai) Investigate how is is used, maybe use BufferHubBuffer's
+ // metadata.
+ ALOGE("SidebandStream is not currently supported.");
+ return INVALID_OPERATION;
+ }
+ return NO_ERROR;
+}
+
+void BufferHubProducer::allocateBuffers(uint32_t /* width */, uint32_t /* height */,
+ PixelFormat /* format */, uint64_t /* usage */) {
+ // TODO(jwcai) |allocateBuffers| aims to preallocate up to the maximum number
+ // of buffers permitted by the current BufferQueue configuration (aka
+ // |max_buffer_count_|).
+ ALOGE("BufferHubProducer::allocateBuffers not implemented.");
+}
+
+status_t BufferHubProducer::allowAllocation(bool /* allow */) {
+ ALOGE("BufferHubProducer::allowAllocation not implemented.");
+ return INVALID_OPERATION;
+}
+
+status_t BufferHubProducer::setGenerationNumber(uint32_t generation_number) {
+ ALOGV(__FUNCTION__);
+
+ std::unique_lock<std::mutex> lock(mutex_);
+ generation_number_ = generation_number;
+ return NO_ERROR;
+}
+
+String8 BufferHubProducer::getConsumerName() const {
+ // BufferHub based implementation could have one to many producer/consumer
+ // relationship, thus |getConsumerName| from the producer side does not
+ // make any sense.
+ ALOGE("BufferHubProducer::getConsumerName not supported.");
+ return String8("BufferHubQueue::DummyConsumer");
+}
+
+status_t BufferHubProducer::setSharedBufferMode(bool shared_buffer_mode) {
+ if (shared_buffer_mode) {
+ ALOGE("BufferHubProducer::setSharedBufferMode(true) is not supported.");
+ // TODO(b/36373181) Front buffer mode for buffer hub queue as ANativeWindow.
+ return INVALID_OPERATION;
+ }
+ // Setting to default should just work as a no-op.
+ return NO_ERROR;
+}
+
+status_t BufferHubProducer::setAutoRefresh(bool auto_refresh) {
+ if (auto_refresh) {
+ ALOGE("BufferHubProducer::setAutoRefresh(true) is not supported.");
+ return INVALID_OPERATION;
+ }
+ // Setting to default should just work as a no-op.
+ return NO_ERROR;
+}
+
+status_t BufferHubProducer::setDequeueTimeout(nsecs_t timeout) {
+ ALOGV(__FUNCTION__);
+
+ std::unique_lock<std::mutex> lock(mutex_);
+ dequeue_timeout_ms_ = int(timeout / (1000 * 1000));
+ return NO_ERROR;
+}
+
+status_t BufferHubProducer::getLastQueuedBuffer(sp<GraphicBuffer>* /* out_buffer */,
+ sp<Fence>* /* out_fence */,
+ float /*out_transform_matrix*/[16]) {
+ ALOGE("BufferHubProducer::getLastQueuedBuffer not implemented.");
+ return INVALID_OPERATION;
+}
+
+void BufferHubProducer::getFrameTimestamps(FrameEventHistoryDelta* /*outDelta*/) {
+ ALOGE("BufferHubProducer::getFrameTimestamps not implemented.");
+}
+
+status_t BufferHubProducer::getUniqueId(uint64_t* out_id) const {
+ ALOGV(__FUNCTION__);
+
+ *out_id = unique_id_;
+ return NO_ERROR;
+}
+
+status_t BufferHubProducer::getConsumerUsage(uint64_t* out_usage) const {
+ ALOGV(__FUNCTION__);
+
+ // same value as returned by querying NATIVE_WINDOW_CONSUMER_USAGE_BITS
+ *out_usage = 0;
+ return NO_ERROR;
+}
+
+status_t BufferHubProducer::TakeAsParcelable(dvr::ProducerQueueParcelable* out_parcelable) {
+ if (!out_parcelable || out_parcelable->IsValid()) return BAD_VALUE;
+
+ if (connected_api_ != kNoConnectedApi) {
+ ALOGE("BufferHubProducer::TakeAsParcelable: BufferHubProducer has "
+ "connected client. Must disconnect first.");
+ return BAD_VALUE;
+ }
+
+ if (!queue_->is_connected()) {
+ ALOGE("BufferHubProducer::TakeAsParcelable: This BufferHubProducer "
+ "is not connected to bufferhud. Has it been taken out as a "
+ "parcelable?");
+ return BAD_VALUE;
+ }
+
+ auto status = queue_->TakeAsParcelable();
+ if (!status) {
+ ALOGE("BufferHubProducer::TakeAsParcelable: Failed to take out "
+ "ProducuerQueueParcelable from the producer queue, error: %s.",
+ status.GetErrorMessage().c_str());
+ return BAD_VALUE;
+ }
+
+ *out_parcelable = status.take();
+ return NO_ERROR;
+}
+
+status_t BufferHubProducer::AllocateBuffer(uint32_t width, uint32_t height, uint32_t layer_count,
+ PixelFormat format, uint64_t usage) {
+ auto status = queue_->AllocateBuffer(width, height, layer_count, uint32_t(format), usage);
+ if (!status) {
+ ALOGE("BufferHubProducer::AllocateBuffer: Failed to allocate buffer: %s",
+ status.GetErrorMessage().c_str());
+ return NO_MEMORY;
+ }
+
+ size_t slot = status.get();
+ auto buffer_producer = queue_->GetBuffer(slot);
+
+ LOG_ALWAYS_FATAL_IF(buffer_producer == nullptr, "Failed to get buffer producer at slot: %zu",
+ slot);
+
+ buffers_[slot].mBufferProducer = buffer_producer;
+
+ return NO_ERROR;
+}
+
+status_t BufferHubProducer::RemoveBuffer(size_t slot) {
+ auto status = queue_->RemoveBuffer(slot);
+ if (!status) {
+ ALOGE("BufferHubProducer::RemoveBuffer: Failed to remove buffer: %s",
+ status.GetErrorMessage().c_str());
+ return INVALID_OPERATION;
+ }
+
+ // Reset in memory objects related the the buffer.
+ buffers_[slot].mBufferProducer = nullptr;
+ buffers_[slot].mGraphicBuffer = nullptr;
+ buffers_[slot].mBufferState.detachProducer();
+ return NO_ERROR;
+}
+
+status_t BufferHubProducer::FreeAllBuffers() {
+ for (size_t slot = 0; slot < dvr::BufferHubQueue::kMaxQueueCapacity; slot++) {
+ // Reset in memory objects related the the buffer.
+ buffers_[slot].mGraphicBuffer = nullptr;
+ buffers_[slot].mBufferState.reset();
+ buffers_[slot].mRequestBufferCalled = false;
+ buffers_[slot].mBufferProducer = nullptr;
+ buffers_[slot].mFence = Fence::NO_FENCE;
+ }
+
+ auto status = queue_->FreeAllBuffers();
+ if (!status) {
+ ALOGE("BufferHubProducer::FreeAllBuffers: Failed to free all buffers on "
+ "the queue: %s",
+ status.GetErrorMessage().c_str());
+ }
+
+ if (queue_->capacity() != 0 || queue_->count() != 0) {
+ LOG_ALWAYS_FATAL("BufferHubProducer::FreeAllBuffers: Not all buffers are freed.");
+ }
+
+ return NO_ERROR;
+}
+
+} // namespace android
diff --git a/libs/gui/include/gui/BufferHubProducer.h b/libs/gui/include/gui/BufferHubProducer.h
new file mode 100644
index 0000000..2ee011b
--- /dev/null
+++ b/libs/gui/include/gui/BufferHubProducer.h
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GUI_BUFFERHUBPRODUCER_H_
+#define ANDROID_GUI_BUFFERHUBPRODUCER_H_
+
+#include <gui/BufferSlot.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <private/dvr/buffer_hub_queue_client.h>
+#include <private/dvr/buffer_hub_queue_parcelable.h>
+
+namespace android {
+
+class BufferHubProducer : public BnGraphicBufferProducer {
+public:
+ static constexpr int kNoConnectedApi = -1;
+
+ // TODO(b/36187402) The actual implementation of BufferHubQueue's consumer
+ // side logic doesn't limit the number of buffer it can acquire
+ // simultaneously. We need a way for consumer logic to configure and enforce
+ // that.
+ static constexpr int kDefaultUndequeuedBuffers = 1;
+
+ // Creates a BufferHubProducer instance by importing an existing prodcuer
+ // queue.
+ static sp<BufferHubProducer> Create(const std::shared_ptr<dvr::ProducerQueue>& producer);
+
+ // Creates a BufferHubProducer instance by importing an existing prodcuer
+ // parcelable. Note that this call takes the ownership of the parcelable
+ // object and is guaranteed to succeed if parcelable object is valid.
+ static sp<BufferHubProducer> Create(dvr::ProducerQueueParcelable parcelable);
+
+ // See |IGraphicBufferProducer::requestBuffer|
+ status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override;
+
+ // For the BufferHub based implementation. All buffers in the queue are
+ // allowed to be dequeued from the consumer side. It call always returns
+ // 0 for |NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS| query. Thus setting
+ // |max_dequeued_buffers| here can be considered the same as setting queue
+ // capacity.
+ //
+ // See |IGraphicBufferProducer::setMaxDequeuedBufferCount| for more info
+ status_t setMaxDequeuedBufferCount(int max_dequeued_buffers) override;
+
+ // See |IGraphicBufferProducer::setAsyncMode|
+ status_t setAsyncMode(bool async) override;
+
+ // See |IGraphicBufferProducer::dequeueBuffer|
+ status_t dequeueBuffer(int* out_slot, sp<Fence>* out_fence, uint32_t width, uint32_t height,
+ PixelFormat format, uint64_t usage, uint64_t* outBufferAge,
+ FrameEventHistoryDelta* outTimestamps) override;
+
+ // See |IGraphicBufferProducer::detachBuffer|
+ status_t detachBuffer(int slot) override;
+
+ // See |IGraphicBufferProducer::detachNextBuffer|
+ status_t detachNextBuffer(sp<GraphicBuffer>* out_buffer, sp<Fence>* out_fence) override;
+
+ // See |IGraphicBufferProducer::attachBuffer|
+ status_t attachBuffer(int* out_slot, const sp<GraphicBuffer>& buffer) override;
+
+ // See |IGraphicBufferProducer::queueBuffer|
+ status_t queueBuffer(int slot, const QueueBufferInput& input,
+ QueueBufferOutput* output) override;
+
+ // See |IGraphicBufferProducer::cancelBuffer|
+ status_t cancelBuffer(int slot, const sp<Fence>& fence) override;
+
+ // See |IGraphicBufferProducer::query|
+ status_t query(int what, int* out_value) override;
+
+ // See |IGraphicBufferProducer::connect|
+ status_t connect(const sp<IProducerListener>& listener, int api,
+ bool producer_controlled_by_app, QueueBufferOutput* output) override;
+
+ // See |IGraphicBufferProducer::disconnect|
+ status_t disconnect(int api, DisconnectMode mode = DisconnectMode::Api) override;
+
+ // See |IGraphicBufferProducer::setSidebandStream|
+ status_t setSidebandStream(const sp<NativeHandle>& stream) override;
+
+ // See |IGraphicBufferProducer::allocateBuffers|
+ void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format,
+ uint64_t usage) override;
+
+ // See |IGraphicBufferProducer::allowAllocation|
+ status_t allowAllocation(bool allow) override;
+
+ // See |IGraphicBufferProducer::setGenerationNumber|
+ status_t setGenerationNumber(uint32_t generation_number) override;
+
+ // See |IGraphicBufferProducer::getConsumerName|
+ String8 getConsumerName() const override;
+
+ // See |IGraphicBufferProducer::setSharedBufferMode|
+ status_t setSharedBufferMode(bool shared_buffer_mode) override;
+
+ // See |IGraphicBufferProducer::setAutoRefresh|
+ status_t setAutoRefresh(bool auto_refresh) override;
+
+ // See |IGraphicBufferProducer::setDequeueTimeout|
+ status_t setDequeueTimeout(nsecs_t timeout) override;
+
+ // See |IGraphicBufferProducer::getLastQueuedBuffer|
+ status_t getLastQueuedBuffer(sp<GraphicBuffer>* out_buffer, sp<Fence>* out_fence,
+ float out_transform_matrix[16]) override;
+
+ // See |IGraphicBufferProducer::getFrameTimestamps|
+ void getFrameTimestamps(FrameEventHistoryDelta* /*outDelta*/) override;
+
+ // See |IGraphicBufferProducer::getUniqueId|
+ status_t getUniqueId(uint64_t* out_id) const override;
+
+ // See |IGraphicBufferProducer::getConsumerUsage|
+ status_t getConsumerUsage(uint64_t* out_usage) const override;
+
+ // Takes out the current producer as a binder parcelable object. Note that the
+ // producer must be disconnected to be exportable. After successful export,
+ // the producer queue can no longer be connected again. Returns NO_ERROR when
+ // takeout is successful and out_parcelable will hold the new parcelable
+ // object. Also note that out_parcelable cannot be NULL and must points to an
+ // invalid parcelable.
+ status_t TakeAsParcelable(dvr::ProducerQueueParcelable* out_parcelable);
+
+private:
+ using LocalHandle = pdx::LocalHandle;
+
+ // Private constructor to force use of |Create|.
+ BufferHubProducer() {}
+
+ static uint64_t genUniqueId() {
+ static std::atomic<uint32_t> counter{0};
+ static uint64_t id = static_cast<uint64_t>(getpid()) << 32;
+ return id | counter++;
+ }
+
+ // Allocate new buffer through BufferHub and add it into |queue_| for
+ // bookkeeping.
+ status_t AllocateBuffer(uint32_t width, uint32_t height, uint32_t layer_count,
+ PixelFormat format, uint64_t usage);
+
+ // Remove a buffer via BufferHubRPC.
+ status_t RemoveBuffer(size_t slot);
+
+ // Free all buffers which are owned by the prodcuer. Note that if graphic
+ // buffers are acquired by the consumer, we can't .
+ status_t FreeAllBuffers();
+
+ // Concreate implementation backed by BufferHubBuffer.
+ std::shared_ptr<dvr::ProducerQueue> queue_;
+
+ // Mutex for thread safety.
+ std::mutex mutex_;
+
+ // Connect client API, should be one of the NATIVE_WINDOW_API_* flags.
+ int connected_api_{kNoConnectedApi};
+
+ // |max_buffer_count_| sets the capacity of the underlying buffer queue.
+ int32_t max_buffer_count_{dvr::BufferHubQueue::kMaxQueueCapacity};
+
+ // |max_dequeued_buffer_count_| set the maximum number of buffers that can
+ // be dequeued at the same momment.
+ int32_t max_dequeued_buffer_count_{1};
+
+ // Sets how long dequeueBuffer or attachBuffer will block if a buffer or
+ // slot is not yet available. The timeout is stored in milliseconds.
+ int dequeue_timeout_ms_{dvr::BufferHubQueue::kNoTimeOut};
+
+ // |generation_number_| stores the current generation number of the attached
+ // producer. Any attempt to attach a buffer with a different generation
+ // number will fail.
+ // TOOD(b/38137191) Currently not used as we don't support
+ // IGraphicBufferProducer::detachBuffer.
+ uint32_t generation_number_{0};
+
+ // |buffers_| stores the buffers that have been dequeued from
+ // |dvr::BufferHubQueue|, It is initialized to invalid buffers, and gets
+ // filled in with the result of |Dequeue|.
+ // TODO(jwcai) The buffer allocated to a slot will also be replaced if the
+ // requested buffer usage or geometry differs from that of the buffer
+ // allocated to a slot.
+ struct BufferHubSlot : public BufferSlot {
+ BufferHubSlot() : mBufferProducer(nullptr), mIsReallocating(false) {}
+ // BufferSlot comes from android framework, using m prefix to comply with
+ // the name convention with the reset of data fields from BufferSlot.
+ std::shared_ptr<dvr::BufferProducer> mBufferProducer;
+ bool mIsReallocating;
+ };
+ BufferHubSlot buffers_[dvr::BufferHubQueue::kMaxQueueCapacity];
+
+ // A uniqueId used by IGraphicBufferProducer interface.
+ const uint64_t unique_id_{genUniqueId()};
+};
+
+} // namespace android
+
+#endif // ANDROID_GUI_BUFFERHUBPRODUCER_H_
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index cd29d4a..8060b6e 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -22,6 +22,7 @@
#include <binder/ProcessState.h>
#include <configstore/Utils.h>
#include <cutils/properties.h>
+#include <inttypes.h>
#include <gui/BufferItemConsumer.h>
#include <gui/IDisplayEventConnection.h>
#include <gui/IProducerListener.h>
@@ -869,7 +870,7 @@
(iOldFrame == NO_FRAME_INDEX) ? nullptr : &mFrames[iOldFrame];
FrameEvents* newFrame = &mFrames[iNewFrame];
- uint64_t nOldFrame = iOldFrame + 1;
+ uint64_t nOldFrame = (iOldFrame == NO_FRAME_INDEX) ? 0 : iOldFrame + 1;
uint64_t nNewFrame = iNewFrame + 1;
// Latch, Composite, and Release the frames in a plausible order.
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index e54f147..57eee12 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -107,7 +107,7 @@
// this is the strategy that applications will actually use. Be very careful
// when adjusting the default strategy because it can dramatically affect
// (often in a bad way) the user experience.
-const char* VelocityTracker::DEFAULT_STRATEGY = "lsq2";
+const char* VelocityTracker::DEFAULT_STRATEGY = "impulse";
VelocityTracker::VelocityTracker(const char* strategy) :
mLastEventTime(0), mCurrentPointerIdBits(0), mActivePointerId(-1) {
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index ed292e7..a2712b4 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -29,7 +29,7 @@
#include <system/graphics.h>
#include <private/android/AHardwareBufferHelpers.h>
-#include <android/hardware/graphics/common/1.0/types.h>
+#include <android/hardware/graphics/common/1.1/types.h>
static constexpr int kFdBufferSize = 128 * sizeof(int); // 128 ints
@@ -311,6 +311,18 @@
"HAL and AHardwareBuffer pixel format don't match");
static_assert(HAL_PIXEL_FORMAT_BLOB == AHARDWAREBUFFER_FORMAT_BLOB,
"HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_DEPTH_16 == AHARDWAREBUFFER_FORMAT_D16_UNORM,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_DEPTH_24 == AHARDWAREBUFFER_FORMAT_D24_UNORM,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_DEPTH_24_STENCIL_8 == AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_DEPTH_32F == AHARDWAREBUFFER_FORMAT_D32_FLOAT,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_DEPTH_32F_STENCIL_8 == AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_STENCIL_8 == AHARDWAREBUFFER_FORMAT_S8_UINT,
+ "HAL and AHardwareBuffer pixel format don't match");
static_assert(HAL_PIXEL_FORMAT_BGRA_8888 == AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM,
"HAL and AHardwareBuffer pixel format don't match");
static_assert(HAL_PIXEL_FORMAT_YV12 == AHARDWAREBUFFER_FORMAT_YV12,
@@ -354,6 +366,12 @@
case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
case AHARDWAREBUFFER_FORMAT_BLOB:
+ case AHARDWAREBUFFER_FORMAT_D16_UNORM:
+ case AHARDWAREBUFFER_FORMAT_D24_UNORM:
+ case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT:
+ case AHARDWAREBUFFER_FORMAT_D32_FLOAT:
+ case AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT:
+ case AHARDWAREBUFFER_FORMAT_S8_UINT:
// VNDK formats only -- unfortunately we can't differentiate from where we're called
case AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM:
case AHARDWAREBUFFER_FORMAT_YV12:
@@ -388,7 +406,7 @@
}
uint64_t AHardwareBuffer_convertToGrallocUsageBits(uint64_t usage) {
- using android::hardware::graphics::common::V1_0::BufferUsage;
+ using android::hardware::graphics::common::V1_1::BufferUsage;
static_assert(AHARDWAREBUFFER_USAGE_CPU_READ_NEVER == (uint64_t)BufferUsage::CPU_READ_NEVER,
"gralloc and AHardwareBuffer flags don't match");
static_assert(AHARDWAREBUFFER_USAGE_CPU_READ_RARELY == (uint64_t)BufferUsage::CPU_READ_RARELY,
@@ -413,6 +431,10 @@
"gralloc and AHardwareBuffer flags don't match");
static_assert(AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA == (uint64_t)BufferUsage::SENSOR_DIRECT_DATA,
"gralloc and AHardwareBuffer flags don't match");
+ static_assert(AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP == (uint64_t)BufferUsage::GPU_CUBE_MAP,
+ "gralloc and AHardwareBuffer flags don't match");
+ static_assert(AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE == (uint64_t)BufferUsage::GPU_MIPMAP_COMPLETE,
+ "gralloc and AHardwareBuffer flags don't match");
return usage;
}
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 29555fd..5fbb3b2 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -60,7 +60,7 @@
"liblog",
"libutils",
"libui",
- "android.hardware.graphics.common@1.0",
+ "android.hardware.graphics.common@1.1",
],
static_libs: [
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index 52440a5..a477bf2 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -80,6 +80,48 @@
* the buffer size in bytes.
*/
AHARDWAREBUFFER_FORMAT_BLOB = 0x21,
+
+ /**
+ * Corresponding formats:
+ * Vulkan: VK_FORMAT_D16_UNORM
+ * OpenGL ES: GL_DEPTH_COMPONENT16
+ */
+ AHARDWAREBUFFER_FORMAT_D16_UNORM = 0x30,
+
+ /**
+ * Corresponding formats:
+ * Vulkan: VK_FORMAT_X8_D24_UNORM_PACK32
+ * OpenGL ES: GL_DEPTH_COMPONENT24
+ */
+ AHARDWAREBUFFER_FORMAT_D24_UNORM = 0x31,
+
+ /**
+ * Corresponding formats:
+ * Vulkan: VK_FORMAT_D24_UNORM_S8_UINT
+ * OpenGL ES: GL_DEPTH24_STENCIL8
+ */
+ AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT = 0x32,
+
+ /**
+ * Corresponding formats:
+ * Vulkan: VK_FORMAT_D32_SFLOAT
+ * OpenGL ES: GL_DEPTH_COMPONENT32F
+ */
+ AHARDWAREBUFFER_FORMAT_D32_FLOAT = 0x33,
+
+ /**
+ * Corresponding formats:
+ * Vulkan: VK_FORMAT_D32_SFLOAT_S8_UINT
+ * OpenGL ES: GL_DEPTH32F_STENCIL8
+ */
+ AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT = 0x34,
+
+ /**
+ * Corresponding formats:
+ * Vulkan: VK_FORMAT_S8_UINT
+ * OpenGL ES: GL_STENCIL_INDEX8
+ */
+ AHARDWAREBUFFER_FORMAT_S8_UINT = 0x35,
};
enum {
@@ -109,10 +151,14 @@
AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT = 1UL << 14,
/* The buffer will be read by a hardware video encoder */
AHARDWAREBUFFER_USAGE_VIDEO_ENCODE = 1UL << 16,
- /** The buffer will be used for sensor direct data */
+ /* The buffer will be used for sensor direct data */
AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA = 1UL << 23,
- /* The buffer will be used as a shader storage or uniform buffer object*/
+ /* The buffer will be used as a shader storage or uniform buffer object */
AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER = 1UL << 24,
+ /* The buffer will be used as a cube map texture */
+ AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP = 1UL << 25,
+ /* The buffer contains a complete mipmap hierarchy */
+ AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE = 1UL << 26,
AHARDWAREBUFFER_USAGE_VENDOR_0 = 1ULL << 28,
AHARDWAREBUFFER_USAGE_VENDOR_1 = 1ULL << 29,
diff --git a/libs/sensor/ISensorServer.cpp b/libs/sensor/ISensorServer.cpp
index efbbf7d..5200545 100644
--- a/libs/sensor/ISensorServer.cpp
+++ b/libs/sensor/ISensorServer.cpp
@@ -27,6 +27,7 @@
#include <binder/Parcel.h>
#include <binder/IInterface.h>
+#include <binder/IResultReceiver.h>
#include <sensor/Sensor.h>
#include <sensor/ISensorEventConnection.h>
@@ -227,6 +228,30 @@
reply->writeInt32(ret);
return NO_ERROR;
}
+ case SHELL_COMMAND_TRANSACTION: {
+ int in = data.readFileDescriptor();
+ int out = data.readFileDescriptor();
+ int err = data.readFileDescriptor();
+ int argc = data.readInt32();
+ Vector<String16> args;
+ for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
+ args.add(data.readString16());
+ }
+ sp<IBinder> unusedCallback;
+ sp<IResultReceiver> resultReceiver;
+ status_t status;
+ if ((status = data.readNullableStrongBinder(&unusedCallback)) != NO_ERROR) {
+ return status;
+ }
+ if ((status = data.readNullableStrongBinder(&resultReceiver)) != NO_ERROR) {
+ return status;
+ }
+ status = shellCommand(in, out, err, args);
+ if (resultReceiver != nullptr) {
+ resultReceiver->send(status);
+ }
+ return NO_ERROR;
+ }
}
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/sensor/include/sensor/ISensorServer.h b/libs/sensor/include/sensor/ISensorServer.h
index edf3e0f..402678f 100644
--- a/libs/sensor/include/sensor/ISensorServer.h
+++ b/libs/sensor/include/sensor/ISensorServer.h
@@ -60,6 +60,9 @@
class BnSensorServer : public BnInterface<ISensorServer>
{
public:
+ virtual status_t shellCommand(int in, int out, int err,
+ Vector<String16>& args) = 0;
+
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index abe856e..f71f814 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -85,6 +85,7 @@
"libhwbinder",
"libsync",
"libutils",
+ "libutilscallstack",
"liblog",
],
diff --git a/libs/ui/Gralloc2.cpp b/libs/ui/Gralloc2.cpp
index 1f746a2..deaf8d3 100644
--- a/libs/ui/Gralloc2.cpp
+++ b/libs/ui/Gralloc2.cpp
@@ -20,6 +20,7 @@
#include <hwbinder/IPCThreadState.h>
#include <ui/Gralloc2.h>
+#include <inttypes.h>
#include <log/log.h>
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wzero-length-array"
@@ -30,8 +31,37 @@
namespace Gralloc2 {
+namespace {
+
static constexpr Error kTransactionError = Error::NO_RESOURCES;
+uint64_t getValid10UsageBits() {
+ static const uint64_t valid10UsageBits = []() -> uint64_t {
+ using hardware::graphics::common::V1_0::BufferUsage;
+ uint64_t bits = 0;
+ for (const auto bit : hardware::hidl_enum_iterator<BufferUsage>()) {
+ bits = bits | bit;
+ }
+ return bits;
+ }();
+ return valid10UsageBits;
+}
+
+uint64_t getValid11UsageBits() {
+ static const uint64_t valid11UsageBits = []() -> uint64_t {
+ using hardware::graphics::common::V1_1::BufferUsage;
+ uint64_t bits = 0;
+ for (const auto bit : hardware::hidl_enum_iterator<BufferUsage>()) {
+ bits = bits | bit;
+ }
+ // Return only the overlapping bits.
+ return bits & ~getValid10UsageBits();
+ }();
+ return valid11UsageBits;
+}
+
+} // anonymous namespace
+
void Mapper::preload() {
android::hardware::preloadPassthroughService<hardware::graphics::mapper::V2_0::IMapper>();
}
@@ -50,11 +80,39 @@
mMapperV2_1 = hardware::graphics::mapper::V2_1::IMapper::castFrom(mMapper);
}
+Gralloc2::Error Mapper::validateBufferDescriptorInfo(
+ const IMapper::BufferDescriptorInfo& descriptorInfo) const {
+ uint64_t validUsageBits = getValid10UsageBits();
+ if (mMapperV2_1 != nullptr) {
+ validUsageBits = validUsageBits | getValid11UsageBits();
+ }
+
+ if (descriptorInfo.usage & ~validUsageBits) {
+ ALOGE("buffer descriptor contains invalid usage bits 0x%" PRIx64,
+ descriptorInfo.usage & ~validUsageBits);
+ return Error::BAD_VALUE;
+ }
+ return Error::NONE;
+}
+
Error Mapper::createDescriptor(
const IMapper::BufferDescriptorInfo& descriptorInfo,
BufferDescriptor* outDescriptor) const
{
Error error;
+
+ if (descriptorInfo.usage & getValid11UsageBits()) {
+ // TODO(b/66900669): Use mMapperV2_1->createDescriptorV2_1().
+ ALOGW("full support for new usage bits is unimplemented 0x%" PRIx64,
+ descriptorInfo.usage & getValid11UsageBits());
+ return Error::BAD_VALUE;
+ }
+
+ error = validateBufferDescriptorInfo(descriptorInfo);
+ if (error != Error::NONE) {
+ return error;
+ }
+
auto ret = mMapper->createDescriptor(descriptorInfo,
[&](const auto& tmpError, const auto& tmpDescriptor)
{
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index 2cac287..2d8e582 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -72,6 +72,7 @@
info.layerCount = layerCount;
info.format = static_cast<Gralloc2::PixelFormat>(format);
info.usage = usage;
+
error = mMapper->validateBufferSize(bufferHandle, info, stride);
if (error != Gralloc2::Error::NONE) {
ALOGE("validateBufferSize(%p) failed: %d", rawHandle, error);
diff --git a/libs/ui/include/ui/Gralloc2.h b/libs/ui/include/ui/Gralloc2.h
index 69c35f7..db3f10a 100644
--- a/libs/ui/include/ui/Gralloc2.h
+++ b/libs/ui/include/ui/Gralloc2.h
@@ -20,6 +20,7 @@
#include <string>
#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <android/hardware/graphics/common/1.1/types.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <android/hardware/graphics/mapper/2.1/IMapper.h>
#include <utils/StrongPointer.h>
@@ -29,8 +30,8 @@
namespace Gralloc2 {
using hardware::graphics::allocator::V2_0::IAllocator;
-using hardware::graphics::common::V1_0::BufferUsage;
using hardware::graphics::common::V1_0::PixelFormat;
+using hardware::graphics::common::V1_1::BufferUsage;
using hardware::graphics::mapper::V2_0::BufferDescriptor;
using hardware::graphics::mapper::V2_0::Error;
using hardware::graphics::mapper::V2_0::IMapper;
@@ -80,6 +81,10 @@
int unlock(buffer_handle_t bufferHandle) const;
private:
+ // Determines whether the passed info is compatible with the mapper.
+ Error validateBufferDescriptorInfo(
+ const IMapper::BufferDescriptorInfo& descriptorInfo) const;
+
sp<IMapper> mMapper;
sp<hardware::graphics::mapper::V2_1::IMapper> mMapperV2_1;
};
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index 9481c37..7ea37a7 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -23,7 +23,6 @@
]
staticLibraries = [
- "libdvrcommon",
"libpdx_default_transport",
]
@@ -60,6 +59,10 @@
export_header_lib_headers: [
"libnativebase_headers",
],
+ vendor_available: false,
+ vndk: {
+ enabled: true,
+ },
}
cc_test {
diff --git a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
index f9fd42d..f105b02 100644
--- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
+++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
@@ -2,8 +2,8 @@
#define ANDROID_DVR_BUFFERHUB_RPC_H_
#include <cutils/native_handle.h>
-#include <gui/BufferQueueDefs.h>
#include <sys/types.h>
+#include <ui/BufferQueueDefs.h>
#include <dvr/dvr_api.h>
#include <pdx/channel_handle.h>
diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp
index 8241809..84e7427 100644
--- a/libs/vr/libbufferhubqueue/Android.bp
+++ b/libs/vr/libbufferhubqueue/Android.bp
@@ -15,7 +15,6 @@
sourceFiles = [
"buffer_hub_queue_client.cpp",
"buffer_hub_queue_parcelable.cpp",
- "buffer_hub_queue_producer.cpp",
]
includeFiles = [
@@ -24,7 +23,6 @@
staticLibraries = [
"libbufferhub",
- "libdvrcommon",
"libpdx_default_transport",
]
@@ -36,7 +34,6 @@
"liblog",
"libui",
"libutils",
- "libgui",
]
headerLibraries = [
@@ -62,6 +59,10 @@
static_libs: staticLibraries,
shared_libs: sharedLibraries,
header_libs: headerLibraries,
+ vendor_available: false,
+ vndk: {
+ enabled: true,
+ },
}
subdirs = ["tests"]
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
deleted file mode 100644
index ace01a6..0000000
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
+++ /dev/null
@@ -1,729 +0,0 @@
-#include "include/private/dvr/buffer_hub_queue_producer.h"
-
-#include <dvr/dvr_api.h>
-#include <inttypes.h>
-#include <log/log.h>
-#include <system/window.h>
-
-namespace android {
-namespace dvr {
-
-/* static */
-sp<BufferHubQueueProducer> BufferHubQueueProducer::Create(
- const std::shared_ptr<ProducerQueue>& queue) {
- if (queue->metadata_size() != sizeof(DvrNativeBufferMetadata)) {
- ALOGE(
- "BufferHubQueueProducer::Create producer's metadata size is different "
- "than the size of DvrNativeBufferMetadata");
- return nullptr;
- }
-
- sp<BufferHubQueueProducer> producer = new BufferHubQueueProducer;
- producer->queue_ = queue;
- return producer;
-}
-
-/* static */
-sp<BufferHubQueueProducer> BufferHubQueueProducer::Create(
- ProducerQueueParcelable parcelable) {
- if (!parcelable.IsValid()) {
- ALOGE("BufferHubQueueProducer::Create: Invalid producer parcelable.");
- return nullptr;
- }
-
- sp<BufferHubQueueProducer> producer = new BufferHubQueueProducer;
- producer->queue_ = ProducerQueue::Import(parcelable.TakeChannelHandle());
- return producer;
-}
-
-status_t BufferHubQueueProducer::requestBuffer(int slot,
- sp<GraphicBuffer>* buf) {
- ALOGD_IF(TRACE, "requestBuffer: slot=%d", slot);
-
- std::unique_lock<std::mutex> lock(mutex_);
-
- if (connected_api_ == kNoConnectedApi) {
- ALOGE("requestBuffer: BufferHubQueueProducer has no connected producer");
- return NO_INIT;
- }
-
- if (slot < 0 || slot >= max_buffer_count_) {
- ALOGE("requestBuffer: slot index %d out of range [0, %d)", slot,
- max_buffer_count_);
- return BAD_VALUE;
- } else if (!buffers_[slot].mBufferState.isDequeued()) {
- ALOGE("requestBuffer: slot %d is not owned by the producer (state = %s)",
- slot, buffers_[slot].mBufferState.string());
- return BAD_VALUE;
- } else if (buffers_[slot].mGraphicBuffer != nullptr) {
- ALOGE("requestBuffer: slot %d is not empty.", slot);
- return BAD_VALUE;
- } else if (buffers_[slot].mBufferProducer == nullptr) {
- ALOGE("requestBuffer: slot %d is not dequeued.", slot);
- return BAD_VALUE;
- }
-
- const auto& buffer_producer = buffers_[slot].mBufferProducer;
- sp<GraphicBuffer> graphic_buffer = buffer_producer->buffer()->buffer();
-
- buffers_[slot].mGraphicBuffer = graphic_buffer;
- buffers_[slot].mRequestBufferCalled = true;
-
- *buf = graphic_buffer;
- return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::setMaxDequeuedBufferCount(
- int max_dequeued_buffers) {
- ALOGD_IF(TRACE, "setMaxDequeuedBufferCount: max_dequeued_buffers=%d",
- max_dequeued_buffers);
-
- std::unique_lock<std::mutex> lock(mutex_);
-
- if (max_dequeued_buffers <= 0 ||
- max_dequeued_buffers >
- static_cast<int>(BufferHubQueue::kMaxQueueCapacity -
- kDefaultUndequeuedBuffers)) {
- ALOGE("setMaxDequeuedBufferCount: %d out of range (0, %zu]",
- max_dequeued_buffers, BufferHubQueue::kMaxQueueCapacity);
- return BAD_VALUE;
- }
-
- // The new dequeued_buffers count should not be violated by the number
- // of currently dequeued buffers.
- int dequeued_count = 0;
- for (const auto& buf : buffers_) {
- if (buf.mBufferState.isDequeued()) {
- dequeued_count++;
- }
- }
- if (dequeued_count > max_dequeued_buffers) {
- ALOGE(
- "setMaxDequeuedBufferCount: the requested dequeued_buffers"
- "count (%d) exceeds the current dequeued buffer count (%d)",
- max_dequeued_buffers, dequeued_count);
- return BAD_VALUE;
- }
-
- max_dequeued_buffer_count_ = max_dequeued_buffers;
- return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::setAsyncMode(bool async) {
- if (async) {
- // TODO(b/36724099) BufferHubQueue's consumer end always acquires the buffer
- // automatically and behaves differently from IGraphicBufferConsumer. Thus,
- // android::BufferQueue's async mode (a.k.a. allocating an additional buffer
- // to prevent dequeueBuffer from being blocking) technically does not apply
- // here.
- //
- // In Daydream, non-blocking producer side dequeue is guaranteed by careful
- // buffer consumer implementations. In another word, BufferHubQueue based
- // dequeueBuffer should never block whether setAsyncMode(true) is set or
- // not.
- //
- // See: IGraphicBufferProducer::setAsyncMode and
- // BufferQueueProducer::setAsyncMode for more about original implementation.
- ALOGW(
- "BufferHubQueueProducer::setAsyncMode: BufferHubQueue should always be "
- "asynchronous. This call makes no effact.");
- return NO_ERROR;
- }
- return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::dequeueBuffer(
- int* out_slot, sp<Fence>* out_fence, uint32_t width, uint32_t height,
- PixelFormat format, uint64_t usage, uint64_t* /*outBufferAge*/,
- FrameEventHistoryDelta* /* out_timestamps */) {
- ALOGD_IF(TRACE, "dequeueBuffer: w=%u, h=%u, format=%d, usage=%" PRIu64, width,
- height, format, usage);
-
- status_t ret;
- std::unique_lock<std::mutex> lock(mutex_);
-
- if (connected_api_ == kNoConnectedApi) {
- ALOGE("dequeueBuffer: BufferQueue has no connected producer");
- return NO_INIT;
- }
-
- const uint32_t kLayerCount = 1;
- if (static_cast<int32_t>(queue_->capacity()) <
- max_dequeued_buffer_count_ + kDefaultUndequeuedBuffers) {
- // Lazy allocation. When the capacity of |queue_| has not reached
- // |max_dequeued_buffer_count_|, allocate new buffer.
- // TODO(jwcai) To save memory, the really reasonable thing to do is to go
- // over existing slots and find first existing one to dequeue.
- ret = AllocateBuffer(width, height, kLayerCount, format, usage);
- if (ret < 0)
- return ret;
- }
-
- size_t slot;
- std::shared_ptr<BufferProducer> buffer_producer;
-
- for (size_t retry = 0; retry < BufferHubQueue::kMaxQueueCapacity; retry++) {
- LocalHandle fence;
- auto buffer_status = queue_->Dequeue(dequeue_timeout_ms_, &slot, &fence);
- if (!buffer_status)
- return NO_MEMORY;
-
- buffer_producer = buffer_status.take();
- if (!buffer_producer)
- return NO_MEMORY;
-
- if (width == buffer_producer->width() &&
- height == buffer_producer->height() &&
- static_cast<uint32_t>(format) == buffer_producer->format()) {
- // The producer queue returns a buffer producer matches the request.
- break;
- }
-
- // Needs reallocation.
- // TODO(jwcai) Consider use VLOG instead if we find this log is not useful.
- ALOGI(
- "dequeueBuffer: requested buffer (w=%u, h=%u, format=%u) is different "
- "from the buffer returned at slot: %zu (w=%u, h=%u, format=%u). Need "
- "re-allocattion.",
- width, height, format, slot, buffer_producer->width(),
- buffer_producer->height(), buffer_producer->format());
- // Mark the slot as reallocating, so that later we can set
- // BUFFER_NEEDS_REALLOCATION when the buffer actually get dequeued.
- buffers_[slot].mIsReallocating = true;
-
- // Remove the old buffer once the allocation before allocating its
- // replacement.
- RemoveBuffer(slot);
-
- // Allocate a new producer buffer with new buffer configs. Note that if
- // there are already multiple buffers in the queue, the next one returned
- // from |queue_->Dequeue| may not be the new buffer we just reallocated.
- // Retry up to BufferHubQueue::kMaxQueueCapacity times.
- ret = AllocateBuffer(width, height, kLayerCount, format, usage);
- if (ret < 0)
- return ret;
- }
-
- // With the BufferHub backed solution. Buffer slot returned from
- // |queue_->Dequeue| is guaranteed to avaiable for producer's use.
- // It's either in free state (if the buffer has never been used before) or
- // in queued state (if the buffer has been dequeued and queued back to
- // BufferHubQueue).
- LOG_ALWAYS_FATAL_IF(
- (!buffers_[slot].mBufferState.isFree() &&
- !buffers_[slot].mBufferState.isQueued()),
- "dequeueBuffer: slot %zu is not free or queued, actual state: %s.", slot,
- buffers_[slot].mBufferState.string());
-
- buffers_[slot].mBufferState.freeQueued();
- buffers_[slot].mBufferState.dequeue();
- ALOGD_IF(TRACE, "dequeueBuffer: slot=%zu", slot);
-
- // TODO(jwcai) Handle fence properly. |BufferHub| has full fence support, we
- // just need to exopose that through |BufferHubQueue| once we need fence.
- *out_fence = Fence::NO_FENCE;
- *out_slot = slot;
- ret = NO_ERROR;
-
- if (buffers_[slot].mIsReallocating) {
- ret |= BUFFER_NEEDS_REALLOCATION;
- buffers_[slot].mIsReallocating = false;
- }
-
- return ret;
-}
-
-status_t BufferHubQueueProducer::detachBuffer(int /* slot */) {
- ALOGE("BufferHubQueueProducer::detachBuffer not implemented.");
- return INVALID_OPERATION;
-}
-
-status_t BufferHubQueueProducer::detachNextBuffer(
- sp<GraphicBuffer>* /* out_buffer */, sp<Fence>* /* out_fence */) {
- ALOGE("BufferHubQueueProducer::detachNextBuffer not implemented.");
- return INVALID_OPERATION;
-}
-
-status_t BufferHubQueueProducer::attachBuffer(
- int* /* out_slot */, const sp<GraphicBuffer>& /* buffer */) {
- // With this BufferHub backed implementation, we assume (for now) all buffers
- // are allocated and owned by the BufferHub. Thus the attempt of transfering
- // ownership of a buffer to the buffer queue is intentionally unsupported.
- LOG_ALWAYS_FATAL("BufferHubQueueProducer::attachBuffer not supported.");
- return INVALID_OPERATION;
-}
-
-status_t BufferHubQueueProducer::queueBuffer(int slot,
- const QueueBufferInput& input,
- QueueBufferOutput* output) {
- ALOGD_IF(TRACE, "queueBuffer: slot %d", slot);
-
- if (output == nullptr) {
- return BAD_VALUE;
- }
-
- int64_t timestamp;
- bool is_auto_timestamp;
- android_dataspace dataspace;
- Rect crop(Rect::EMPTY_RECT);
- int scaling_mode;
- uint32_t transform;
- sp<Fence> fence;
-
- input.deflate(×tamp, &is_auto_timestamp, &dataspace, &crop,
- &scaling_mode, &transform, &fence);
-
- // Check input scaling mode is valid.
- switch (scaling_mode) {
- case NATIVE_WINDOW_SCALING_MODE_FREEZE:
- case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
- case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
- case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP:
- break;
- default:
- ALOGE("queueBuffer: unknown scaling mode %d", scaling_mode);
- return BAD_VALUE;
- }
-
- // Check input fence is valid.
- if (fence == nullptr) {
- ALOGE("queueBuffer: fence is NULL");
- return BAD_VALUE;
- }
-
- status_t ret;
- std::unique_lock<std::mutex> lock(mutex_);
-
- if (connected_api_ == kNoConnectedApi) {
- ALOGE("queueBuffer: BufferQueue has no connected producer");
- return NO_INIT;
- }
-
- if (slot < 0 || slot >= max_buffer_count_) {
- ALOGE("queueBuffer: slot index %d out of range [0, %d)", slot,
- max_buffer_count_);
- return BAD_VALUE;
- } else if (!buffers_[slot].mBufferState.isDequeued()) {
- ALOGE("queueBuffer: slot %d is not owned by the producer (state = %s)",
- slot, buffers_[slot].mBufferState.string());
- return BAD_VALUE;
- } else if ((!buffers_[slot].mRequestBufferCalled ||
- buffers_[slot].mGraphicBuffer == nullptr)) {
- ALOGE(
- "queueBuffer: slot %d is not requested (mRequestBufferCalled=%d, "
- "mGraphicBuffer=%p)",
- slot, buffers_[slot].mRequestBufferCalled,
- buffers_[slot].mGraphicBuffer.get());
- return BAD_VALUE;
- }
-
- // Post the buffer producer with timestamp in the metadata.
- const auto& buffer_producer = buffers_[slot].mBufferProducer;
-
- // Check input crop is not out of boundary of current buffer.
- Rect buffer_rect(buffer_producer->width(), buffer_producer->height());
- Rect cropped_rect(Rect::EMPTY_RECT);
- crop.intersect(buffer_rect, &cropped_rect);
- if (cropped_rect != crop) {
- ALOGE("queueBuffer: slot %d has out-of-boundary crop.", slot);
- return BAD_VALUE;
- }
-
- LocalHandle fence_fd(fence->isValid() ? fence->dup() : -1);
-
- DvrNativeBufferMetadata meta_data;
- meta_data.timestamp = timestamp;
- meta_data.is_auto_timestamp = static_cast<int32_t>(is_auto_timestamp);
- meta_data.dataspace = static_cast<int32_t>(dataspace);
- meta_data.crop_left = crop.left;
- meta_data.crop_top = crop.top;
- meta_data.crop_right = crop.right;
- meta_data.crop_bottom = crop.bottom;
- meta_data.scaling_mode = static_cast<int32_t>(scaling_mode);
- meta_data.transform = static_cast<int32_t>(transform);
-
- buffer_producer->PostAsync(&meta_data, fence_fd);
- buffers_[slot].mBufferState.queue();
-
- output->width = buffer_producer->width();
- output->height = buffer_producer->height();
- output->transformHint = 0; // default value, we don't use it yet.
-
- // |numPendingBuffers| counts of the number of buffers that has been enqueued
- // by the producer but not yet acquired by the consumer. Due to the nature
- // of BufferHubQueue design, this is hard to trace from the producer's client
- // side, but it's safe to assume it's zero.
- output->numPendingBuffers = 0;
-
- // Note that we are not setting nextFrameNumber here as it seems to be only
- // used by surface flinger. See more at b/22802885, ag/791760.
- output->nextFrameNumber = 0;
-
- return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::cancelBuffer(int slot,
- const sp<Fence>& fence) {
- ALOGD_IF(TRACE, __FUNCTION__);
-
- std::unique_lock<std::mutex> lock(mutex_);
-
- if (connected_api_ == kNoConnectedApi) {
- ALOGE("cancelBuffer: BufferQueue has no connected producer");
- return NO_INIT;
- }
-
- if (slot < 0 || slot >= max_buffer_count_) {
- ALOGE("cancelBuffer: slot index %d out of range [0, %d)", slot,
- max_buffer_count_);
- return BAD_VALUE;
- } else if (!buffers_[slot].mBufferState.isDequeued()) {
- ALOGE("cancelBuffer: slot %d is not owned by the producer (state = %s)",
- slot, buffers_[slot].mBufferState.string());
- return BAD_VALUE;
- } else if (fence == nullptr) {
- ALOGE("cancelBuffer: fence is NULL");
- return BAD_VALUE;
- }
-
- auto buffer_producer = buffers_[slot].mBufferProducer;
- queue_->Enqueue(buffer_producer, slot, 0ULL);
- buffers_[slot].mBufferState.cancel();
- buffers_[slot].mFence = fence;
- ALOGD_IF(TRACE, "cancelBuffer: slot %d", slot);
-
- return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::query(int what, int* out_value) {
- ALOGD_IF(TRACE, __FUNCTION__);
-
- std::unique_lock<std::mutex> lock(mutex_);
-
- if (out_value == nullptr) {
- ALOGE("query: out_value was NULL");
- return BAD_VALUE;
- }
-
- int value = 0;
- switch (what) {
- case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
- // TODO(b/36187402) This should be the maximum number of buffers that this
- // producer queue's consumer can acquire. Set to be at least one. Need to
- // find a way to set from the consumer side.
- value = kDefaultUndequeuedBuffers;
- break;
- case NATIVE_WINDOW_BUFFER_AGE:
- value = 0;
- break;
- case NATIVE_WINDOW_WIDTH:
- value = queue_->default_width();
- break;
- case NATIVE_WINDOW_HEIGHT:
- value = queue_->default_height();
- break;
- case NATIVE_WINDOW_FORMAT:
- value = queue_->default_format();
- break;
- case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND:
- // BufferHubQueue is always operating in async mode, thus semantically
- // consumer can never be running behind. See BufferQueueCore.cpp core
- // for more information about the original meaning of this flag.
- value = 0;
- break;
- case NATIVE_WINDOW_CONSUMER_USAGE_BITS:
- // TODO(jwcai) This is currently not implement as we don't need
- // IGraphicBufferConsumer parity.
- value = 0;
- break;
- case NATIVE_WINDOW_DEFAULT_DATASPACE:
- // TODO(jwcai) Return the default value android::BufferQueue is using as
- // there is no way dvr::ConsumerQueue can set it.
- value = 0; // HAL_DATASPACE_UNKNOWN
- break;
- case NATIVE_WINDOW_STICKY_TRANSFORM:
- // TODO(jwcai) Return the default value android::BufferQueue is using as
- // there is no way dvr::ConsumerQueue can set it.
- value = 0;
- break;
- case NATIVE_WINDOW_CONSUMER_IS_PROTECTED:
- // In Daydream's implementation, the consumer end (i.e. VR Compostior)
- // knows how to handle protected buffers.
- value = 1;
- break;
- default:
- return BAD_VALUE;
- }
-
- ALOGD_IF(TRACE, "query: key=%d, v=%d", what, value);
- *out_value = value;
- return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::connect(
- const sp<IProducerListener>& /* listener */, int api,
- bool /* producer_controlled_by_app */, QueueBufferOutput* output) {
- // Consumer interaction are actually handled by buffer hub, and we need
- // to maintain consumer operations here. We only need to perform basic input
- // parameter checks here.
- ALOGD_IF(TRACE, __FUNCTION__);
-
- if (output == nullptr) {
- return BAD_VALUE;
- }
-
- std::unique_lock<std::mutex> lock(mutex_);
-
- if (connected_api_ != kNoConnectedApi) {
- return BAD_VALUE;
- }
-
- if (!queue_->is_connected()) {
- ALOGE(
- "BufferHubQueueProducer::connect: This BufferHubQueueProducer is not "
- "connected to bufferhud. Has it been taken out as a parcelable?");
- return BAD_VALUE;
- }
-
- switch (api) {
- case NATIVE_WINDOW_API_EGL:
- case NATIVE_WINDOW_API_CPU:
- case NATIVE_WINDOW_API_MEDIA:
- case NATIVE_WINDOW_API_CAMERA:
- connected_api_ = api;
-
- output->width = queue_->default_width();
- output->height = queue_->default_height();
-
- // default values, we don't use them yet.
- output->transformHint = 0;
- output->numPendingBuffers = 0;
- output->nextFrameNumber = 0;
- output->bufferReplaced = false;
-
- break;
- default:
- ALOGE("BufferHubQueueProducer::connect: unknow API %d", api);
- return BAD_VALUE;
- }
-
- return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::disconnect(int api, DisconnectMode /*mode*/) {
- // Consumer interaction are actually handled by buffer hub, and we need
- // to maintain consumer operations here. We only need to perform basic input
- // parameter checks here.
- ALOGD_IF(TRACE, __FUNCTION__);
-
- std::unique_lock<std::mutex> lock(mutex_);
-
- if (kNoConnectedApi == connected_api_) {
- return NO_INIT;
- } else if (api != connected_api_) {
- return BAD_VALUE;
- }
-
- FreeAllBuffers();
- connected_api_ = kNoConnectedApi;
- return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::setSidebandStream(
- const sp<NativeHandle>& stream) {
- if (stream != nullptr) {
- // TODO(jwcai) Investigate how is is used, maybe use BufferHubBuffer's
- // metadata.
- ALOGE("SidebandStream is not currently supported.");
- return INVALID_OPERATION;
- }
- return NO_ERROR;
-}
-
-void BufferHubQueueProducer::allocateBuffers(uint32_t /* width */,
- uint32_t /* height */,
- PixelFormat /* format */,
- uint64_t /* usage */) {
- // TODO(jwcai) |allocateBuffers| aims to preallocate up to the maximum number
- // of buffers permitted by the current BufferQueue configuration (aka
- // |max_buffer_count_|).
- ALOGE("BufferHubQueueProducer::allocateBuffers not implemented.");
-}
-
-status_t BufferHubQueueProducer::allowAllocation(bool /* allow */) {
- ALOGE("BufferHubQueueProducer::allowAllocation not implemented.");
- return INVALID_OPERATION;
-}
-
-status_t BufferHubQueueProducer::setGenerationNumber(
- uint32_t generation_number) {
- ALOGD_IF(TRACE, __FUNCTION__);
-
- std::unique_lock<std::mutex> lock(mutex_);
- generation_number_ = generation_number;
- return NO_ERROR;
-}
-
-String8 BufferHubQueueProducer::getConsumerName() const {
- // BufferHub based implementation could have one to many producer/consumer
- // relationship, thus |getConsumerName| from the producer side does not
- // make any sense.
- ALOGE("BufferHubQueueProducer::getConsumerName not supported.");
- return String8("BufferHubQueue::DummyConsumer");
-}
-
-status_t BufferHubQueueProducer::setSharedBufferMode(bool shared_buffer_mode) {
- if (shared_buffer_mode) {
- ALOGE(
- "BufferHubQueueProducer::setSharedBufferMode(true) is not supported.");
- // TODO(b/36373181) Front buffer mode for buffer hub queue as ANativeWindow.
- return INVALID_OPERATION;
- }
- // Setting to default should just work as a no-op.
- return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::setAutoRefresh(bool auto_refresh) {
- if (auto_refresh) {
- ALOGE("BufferHubQueueProducer::setAutoRefresh(true) is not supported.");
- return INVALID_OPERATION;
- }
- // Setting to default should just work as a no-op.
- return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::setDequeueTimeout(nsecs_t timeout) {
- ALOGD_IF(TRACE, __FUNCTION__);
-
- std::unique_lock<std::mutex> lock(mutex_);
- dequeue_timeout_ms_ = static_cast<int>(timeout / (1000 * 1000));
- return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::getLastQueuedBuffer(
- sp<GraphicBuffer>* /* out_buffer */, sp<Fence>* /* out_fence */,
- float /*out_transform_matrix*/[16]) {
- ALOGE("BufferHubQueueProducer::getLastQueuedBuffer not implemented.");
- return INVALID_OPERATION;
-}
-
-void BufferHubQueueProducer::getFrameTimestamps(
- FrameEventHistoryDelta* /*outDelta*/) {
- ALOGE("BufferHubQueueProducer::getFrameTimestamps not implemented.");
-}
-
-status_t BufferHubQueueProducer::getUniqueId(uint64_t* out_id) const {
- ALOGD_IF(TRACE, __FUNCTION__);
-
- *out_id = unique_id_;
- return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::getConsumerUsage(uint64_t* out_usage) const {
- ALOGD_IF(TRACE, __FUNCTION__);
-
- // same value as returned by querying NATIVE_WINDOW_CONSUMER_USAGE_BITS
- *out_usage = 0;
- return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::TakeAsParcelable(
- ProducerQueueParcelable* out_parcelable) {
- if (!out_parcelable || out_parcelable->IsValid())
- return BAD_VALUE;
-
- if (connected_api_ != kNoConnectedApi) {
- ALOGE(
- "BufferHubQueueProducer::TakeAsParcelable: BufferHubQueueProducer has "
- "connected client. Must disconnect first.");
- return BAD_VALUE;
- }
-
- if (!queue_->is_connected()) {
- ALOGE(
- "BufferHubQueueProducer::TakeAsParcelable: This BufferHubQueueProducer "
- "is not connected to bufferhud. Has it been taken out as a "
- "parcelable?");
- return BAD_VALUE;
- }
-
- auto status = queue_->TakeAsParcelable();
- if (!status) {
- ALOGE(
- "BufferHubQueueProducer::TakeAsParcelable: Failed to take out "
- "ProducuerQueueParcelable from the producer queue, error: %s.",
- status.GetErrorMessage().c_str());
- return BAD_VALUE;
- }
-
- *out_parcelable = status.take();
- return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::AllocateBuffer(uint32_t width, uint32_t height,
- uint32_t layer_count,
- PixelFormat format,
- uint64_t usage) {
- auto status =
- queue_->AllocateBuffer(width, height, layer_count, format, usage);
- if (!status) {
- ALOGE(
- "BufferHubQueueProducer::AllocateBuffer: Failed to allocate buffer: %s",
- status.GetErrorMessage().c_str());
- return NO_MEMORY;
- }
-
- size_t slot = status.get();
- auto buffer_producer = queue_->GetBuffer(slot);
-
- LOG_ALWAYS_FATAL_IF(buffer_producer == nullptr,
- "Failed to get buffer producer at slot: %zu", slot);
-
- buffers_[slot].mBufferProducer = buffer_producer;
-
- return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::RemoveBuffer(size_t slot) {
- auto status = queue_->RemoveBuffer(slot);
- if (!status) {
- ALOGE("BufferHubQueueProducer::RemoveBuffer: Failed to remove buffer: %s",
- status.GetErrorMessage().c_str());
- return INVALID_OPERATION;
- }
-
- // Reset in memory objects related the the buffer.
- buffers_[slot].mBufferProducer = nullptr;
- buffers_[slot].mGraphicBuffer = nullptr;
- buffers_[slot].mBufferState.detachProducer();
- return NO_ERROR;
-}
-
-status_t BufferHubQueueProducer::FreeAllBuffers() {
- for (size_t slot = 0; slot < BufferHubQueue::kMaxQueueCapacity; slot++) {
- // Reset in memory objects related the the buffer.
- buffers_[slot].mGraphicBuffer = nullptr;
- buffers_[slot].mBufferState.reset();
- buffers_[slot].mRequestBufferCalled = false;
- buffers_[slot].mBufferProducer = nullptr;
- buffers_[slot].mFence = Fence::NO_FENCE;
- }
-
- auto status = queue_->FreeAllBuffers();
- if (!status) {
- ALOGE(
- "BufferHubQueueProducer::FreeAllBuffers: Failed to free all buffers on "
- "the queue: %s",
- status.GetErrorMessage().c_str());
- }
-
- if (queue_->capacity() != 0 || queue_->count() != 0) {
- LOG_ALWAYS_FATAL(
- "BufferHubQueueProducer::FreeAllBuffers: Not all buffers are freed.");
- }
-
- return NO_ERROR;
-}
-
-} // namespace dvr
-} // namespace android
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
index 5b320a4..8965530 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
@@ -1,7 +1,7 @@
#ifndef ANDROID_DVR_BUFFER_HUB_QUEUE_CLIENT_H_
#define ANDROID_DVR_BUFFER_HUB_QUEUE_CLIENT_H_
-#include <gui/BufferQueueDefs.h>
+#include <ui/BufferQueueDefs.h>
#include <pdx/client.h>
#include <pdx/status.h>
@@ -9,7 +9,6 @@
#include <private/dvr/buffer_hub_queue_parcelable.h>
#include <private/dvr/bufferhub_rpc.h>
#include <private/dvr/epoll_file_descriptor.h>
-#include <private/dvr/ring_buffer.h>
#include <memory>
#include <queue>
@@ -157,7 +156,7 @@
int poll_events);
pdx::Status<void> HandleQueueEvent(int poll_events);
- // Entry in the ring buffer of available buffers that stores related
+ // Entry in the priority queue of available buffers that stores related
// per-buffer data.
struct Entry {
Entry() : slot(0) {}
@@ -242,7 +241,6 @@
std::array<std::shared_ptr<BufferHubBuffer>, kMaxQueueCapacity> buffers_;
// Buffers and related data that are available for dequeue.
- // RingBuffer<Entry> available_buffers_{kMaxQueueCapacity};
std::priority_queue<Entry, std::vector<Entry>, EntryComparator>
available_buffers_;
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h
deleted file mode 100644
index 9c85048..0000000
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h
+++ /dev/null
@@ -1,202 +0,0 @@
-#ifndef ANDROID_DVR_BUFFER_HUB_QUEUE_PRODUCER_H_
-#define ANDROID_DVR_BUFFER_HUB_QUEUE_PRODUCER_H_
-
-#include <gui/IGraphicBufferProducer.h>
-#include <private/dvr/buffer_hub_queue_client.h>
-#include <private/dvr/buffer_hub_queue_parcelable.h>
-
-namespace android {
-namespace dvr {
-
-class BufferHubQueueProducer : public BnGraphicBufferProducer {
- public:
- static constexpr int kNoConnectedApi = -1;
-
- // TODO(b/36187402) The actual implementation of BufferHubQueue's consumer
- // side logic doesn't limit the number of buffer it can acquire
- // simultaneously. We need a way for consumer logic to configure and enforce
- // that.
- static constexpr int kDefaultUndequeuedBuffers = 1;
-
- // Creates a BufferHubQueueProducer instance by importing an existing prodcuer
- // queue.
- static sp<BufferHubQueueProducer> Create(
- const std::shared_ptr<ProducerQueue>& producer);
-
- // Creates a BufferHubQueueProducer instance by importing an existing prodcuer
- // parcelable. Note that this call takes the ownership of the parcelable
- // object and is guaranteed to succeed if parcelable object is valid.
- static sp<BufferHubQueueProducer> Create(ProducerQueueParcelable parcelable);
-
- // See |IGraphicBufferProducer::requestBuffer|
- status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override;
-
- // For the BufferHub based implementation. All buffers in the queue are
- // allowed to be dequeued from the consumer side. It call always returns
- // 0 for |NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS| query. Thus setting
- // |max_dequeued_buffers| here can be considered the same as setting queue
- // capacity.
- //
- // See |IGraphicBufferProducer::setMaxDequeuedBufferCount| for more info
- status_t setMaxDequeuedBufferCount(int max_dequeued_buffers) override;
-
- // See |IGraphicBufferProducer::setAsyncMode|
- status_t setAsyncMode(bool async) override;
-
- // See |IGraphicBufferProducer::dequeueBuffer|
- status_t dequeueBuffer(int* out_slot, sp<Fence>* out_fence, uint32_t width,
- uint32_t height, PixelFormat format, uint64_t usage,
- uint64_t* outBufferAge,
- FrameEventHistoryDelta* outTimestamps) override;
-
- // See |IGraphicBufferProducer::detachBuffer|
- status_t detachBuffer(int slot) override;
-
- // See |IGraphicBufferProducer::detachNextBuffer|
- status_t detachNextBuffer(sp<GraphicBuffer>* out_buffer,
- sp<Fence>* out_fence) override;
-
- // See |IGraphicBufferProducer::attachBuffer|
- status_t attachBuffer(int* out_slot,
- const sp<GraphicBuffer>& buffer) override;
-
- // See |IGraphicBufferProducer::queueBuffer|
- status_t queueBuffer(int slot, const QueueBufferInput& input,
- QueueBufferOutput* output) override;
-
- // See |IGraphicBufferProducer::cancelBuffer|
- status_t cancelBuffer(int slot, const sp<Fence>& fence) override;
-
- // See |IGraphicBufferProducer::query|
- status_t query(int what, int* out_value) override;
-
- // See |IGraphicBufferProducer::connect|
- status_t connect(const sp<IProducerListener>& listener, int api,
- bool producer_controlled_by_app,
- QueueBufferOutput* output) override;
-
- // See |IGraphicBufferProducer::disconnect|
- status_t disconnect(int api,
- DisconnectMode mode = DisconnectMode::Api) override;
-
- // See |IGraphicBufferProducer::setSidebandStream|
- status_t setSidebandStream(const sp<NativeHandle>& stream) override;
-
- // See |IGraphicBufferProducer::allocateBuffers|
- void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format,
- uint64_t usage) override;
-
- // See |IGraphicBufferProducer::allowAllocation|
- status_t allowAllocation(bool allow) override;
-
- // See |IGraphicBufferProducer::setGenerationNumber|
- status_t setGenerationNumber(uint32_t generation_number) override;
-
- // See |IGraphicBufferProducer::getConsumerName|
- String8 getConsumerName() const override;
-
- // See |IGraphicBufferProducer::setSharedBufferMode|
- status_t setSharedBufferMode(bool shared_buffer_mode) override;
-
- // See |IGraphicBufferProducer::setAutoRefresh|
- status_t setAutoRefresh(bool auto_refresh) override;
-
- // See |IGraphicBufferProducer::setDequeueTimeout|
- status_t setDequeueTimeout(nsecs_t timeout) override;
-
- // See |IGraphicBufferProducer::getLastQueuedBuffer|
- status_t getLastQueuedBuffer(sp<GraphicBuffer>* out_buffer,
- sp<Fence>* out_fence,
- float out_transform_matrix[16]) override;
-
- // See |IGraphicBufferProducer::getFrameTimestamps|
- void getFrameTimestamps(FrameEventHistoryDelta* /*outDelta*/) override;
-
- // See |IGraphicBufferProducer::getUniqueId|
- status_t getUniqueId(uint64_t* out_id) const override;
-
- // See |IGraphicBufferProducer::getConsumerUsage|
- status_t getConsumerUsage(uint64_t* out_usage) const override;
-
- // Takes out the current producer as a binder parcelable object. Note that the
- // producer must be disconnected to be exportable. After successful export,
- // the producer queue can no longer be connected again. Returns NO_ERROR when
- // takeout is successful and out_parcelable will hold the new parcelable
- // object. Also note that out_parcelable cannot be NULL and must points to an
- // invalid parcelable.
- status_t TakeAsParcelable(ProducerQueueParcelable* out_parcelable);
-
- private:
- using LocalHandle = pdx::LocalHandle;
-
- // Private constructor to force use of |Create|.
- BufferHubQueueProducer() {}
-
- static uint64_t genUniqueId() {
- static std::atomic<uint32_t> counter{0};
- static uint64_t id = static_cast<uint64_t>(getpid()) << 32;
- return id | counter++;
- }
-
- // Allocate new buffer through BufferHub and add it into |queue_| for
- // bookkeeping.
- status_t AllocateBuffer(uint32_t width, uint32_t height, uint32_t layer_count,
- PixelFormat format, uint64_t usage);
-
- // Remove a buffer via BufferHubRPC.
- status_t RemoveBuffer(size_t slot);
-
- // Free all buffers which are owned by the prodcuer. Note that if graphic
- // buffers are acquired by the consumer, we can't .
- status_t FreeAllBuffers();
-
- // Concreate implementation backed by BufferHubBuffer.
- std::shared_ptr<ProducerQueue> queue_;
-
- // Mutex for thread safety.
- std::mutex mutex_;
-
- // Connect client API, should be one of the NATIVE_WINDOW_API_* flags.
- int connected_api_{kNoConnectedApi};
-
- // |max_buffer_count_| sets the capacity of the underlying buffer queue.
- int32_t max_buffer_count_{BufferHubQueue::kMaxQueueCapacity};
-
- // |max_dequeued_buffer_count_| set the maximum number of buffers that can
- // be dequeued at the same momment.
- int32_t max_dequeued_buffer_count_{1};
-
- // Sets how long dequeueBuffer or attachBuffer will block if a buffer or
- // slot is not yet available. The timeout is stored in milliseconds.
- int dequeue_timeout_ms_{BufferHubQueue::kNoTimeOut};
-
- // |generation_number_| stores the current generation number of the attached
- // producer. Any attempt to attach a buffer with a different generation
- // number will fail.
- // TOOD(b/38137191) Currently not used as we don't support
- // IGraphicBufferProducer::detachBuffer.
- uint32_t generation_number_{0};
-
- // |buffers_| stores the buffers that have been dequeued from
- // |dvr::BufferHubQueue|, It is initialized to invalid buffers, and gets
- // filled in with the result of |Dequeue|.
- // TODO(jwcai) The buffer allocated to a slot will also be replaced if the
- // requested buffer usage or geometry differs from that of the buffer
- // allocated to a slot.
- struct BufferHubSlot : public BufferSlot {
- BufferHubSlot() : mBufferProducer(nullptr), mIsReallocating(false) {}
- // BufferSlot comes from android framework, using m prefix to comply with
- // the name convention with the reset of data fields from BufferSlot.
- std::shared_ptr<BufferProducer> mBufferProducer;
- bool mIsReallocating;
- };
- BufferHubSlot buffers_[BufferHubQueue::kMaxQueueCapacity];
-
- // A uniqueId used by IGraphicBufferProducer interface.
- const uint64_t unique_id_{genUniqueId()};
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_BUFFER_HUB_QUEUE_PRODUCER_H_
diff --git a/libs/vr/libdvrcommon/include/private/dvr/epoll_file_descriptor.h b/libs/vr/libbufferhubqueue/include/private/dvr/epoll_file_descriptor.h
similarity index 84%
rename from libs/vr/libdvrcommon/include/private/dvr/epoll_file_descriptor.h
rename to libs/vr/libbufferhubqueue/include/private/dvr/epoll_file_descriptor.h
index 099a409..6e303a5 100644
--- a/libs/vr/libdvrcommon/include/private/dvr/epoll_file_descriptor.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/epoll_file_descriptor.h
@@ -1,5 +1,5 @@
-#ifndef LIBS_VR_LIBDVRCOMMON_INCLUDE_PRIVATE_DVR_EPOLL_FILE_DESCRIPTOR_H_
-#define LIBS_VR_LIBDVRCOMMON_INCLUDE_PRIVATE_DVR_EPOLL_FILE_DESCRIPTOR_H_
+#ifndef ANDROID_DVR_EPOLL_FILE_DESCRIPTOR_H_
+#define ANDROID_DVR_EPOLL_FILE_DESCRIPTOR_H_
#include <android-base/unique_fd.h>
#include <log/log.h>
@@ -61,4 +61,4 @@
} // namespace dvr
} // namespace android
-#endif // LIBS_VR_LIBDVRCOMMON_INCLUDE_PRIVATE_DVR_EPOLL_FILE_DESCRIPTOR_H_
+#endif // ANDROID_DVR_EPOLL_FILE_DESCRIPTOR_H_
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
index 96f5404..3e96989 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
@@ -1,6 +1,5 @@
-#include <private/dvr/buffer_hub_queue_producer.h>
-
#include <base/logging.h>
+#include <gui/BufferHubProducer.h>
#include <gui/IProducerListener.h>
#include <gui/Surface.h>
#include <pdx/default_transport/channel_parcelable.h>
@@ -101,7 +100,7 @@
auto queue = ProducerQueue::Create(config, UsagePolicy{});
ASSERT_TRUE(queue != nullptr);
- mProducer = BufferHubQueueProducer::Create(std::move(queue));
+ mProducer = BufferHubProducer::Create(std::move(queue));
ASSERT_TRUE(mProducer != nullptr);
mSurface = new Surface(mProducer, true);
ASSERT_TRUE(mSurface != nullptr);
@@ -145,7 +144,7 @@
const sp<IProducerListener> kDummyListener{new DummyProducerListener};
- sp<BufferHubQueueProducer> mProducer;
+ sp<BufferHubProducer> mProducer;
sp<Surface> mSurface;
};
@@ -596,8 +595,8 @@
// Create a new producer from the parcelable and connect to kTestApi should
// succeed.
- sp<BufferHubQueueProducer> new_producer =
- BufferHubQueueProducer::Create(std::move(producer_parcelable));
+ sp<BufferHubProducer> new_producer =
+ BufferHubProducer::Create(std::move(producer_parcelable));
ASSERT_TRUE(new_producer != nullptr);
EXPECT_EQ(new_producer->connect(kDummyListener, kTestApi,
kTestControlledByApp, &output),
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_transport_benchmark.cpp b/libs/vr/libbufferhubqueue/tests/buffer_transport_benchmark.cpp
index d4d25b0..73932c2 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_transport_benchmark.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_transport_benchmark.cpp
@@ -5,10 +5,10 @@
#include <binder/IServiceManager.h>
#include <dvr/dvr_api.h>
#include <dvr/performance_client_api.h>
+#include <gui/BufferHubProducer.h>
#include <gui/BufferItem.h>
#include <gui/BufferItemConsumer.h>
#include <gui/Surface.h>
-#include <private/dvr/buffer_hub_queue_producer.h>
#include <utils/Trace.h>
#include <chrono>
@@ -338,7 +338,7 @@
}
});
- producer_ = BufferHubQueueProducer::Create(producer_queue_);
+ producer_ = BufferHubProducer::Create(producer_queue_);
}
int count_ = 0;
diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp
index 04418d2..4f0e561 100644
--- a/libs/vr/libdvr/Android.bp
+++ b/libs/vr/libdvr/Android.bp
@@ -15,8 +15,11 @@
cc_library_headers {
name: "libdvr_headers",
- owner: "google",
export_include_dirs: ["include"],
+ vendor_available: false,
+ vndk: {
+ enabled: true,
+ },
}
cflags = [
diff --git a/libs/vr/libdvr/dvr_buffer_queue.cpp b/libs/vr/libdvr/dvr_buffer_queue.cpp
index 09a49dd..c36d190 100644
--- a/libs/vr/libdvr/dvr_buffer_queue.cpp
+++ b/libs/vr/libdvr/dvr_buffer_queue.cpp
@@ -2,7 +2,7 @@
#include "include/dvr/dvr_buffer_queue.h"
#include <android/native_window.h>
-#include <private/dvr/buffer_hub_queue_producer.h>
+#include <gui/BufferHubProducer.h>
#include "dvr_internal.h"
#include "dvr_buffer_queue_internal.h"
@@ -10,7 +10,6 @@
using namespace android;
using android::dvr::BufferConsumer;
using android::dvr::BufferHubBuffer;
-using android::dvr::BufferHubQueueProducer;
using android::dvr::BufferProducer;
using android::dvr::ConsumerQueue;
using android::dvr::ProducerQueue;
@@ -30,8 +29,7 @@
if (native_window_ == nullptr) {
// Lazy creation of |native_window|, as not everyone is using
// DvrWriteBufferQueue as an external surface.
- sp<IGraphicBufferProducer> gbp =
- BufferHubQueueProducer::Create(producer_queue_);
+ sp<IGraphicBufferProducer> gbp = BufferHubProducer::Create(producer_queue_);
native_window_ = new Surface(gbp, true);
}
diff --git a/libs/vr/libpdx/Android.bp b/libs/vr/libpdx/Android.bp
index 10c0b31..9b84d65 100644
--- a/libs/vr/libpdx/Android.bp
+++ b/libs/vr/libpdx/Android.bp
@@ -16,6 +16,16 @@
"service_dispatcher.cpp",
"status.cpp",
],
+ shared_libs: [
+ "libbinder",
+ "libcutils",
+ "libutils",
+ "liblog",
+ ],
+ vendor_available: false,
+ vndk: {
+ enabled: true,
+ },
}
cc_test {
diff --git a/libs/vr/libpdx_default_transport/Android.bp b/libs/vr/libpdx_default_transport/Android.bp
index cda3c95..779e3a1 100644
--- a/libs/vr/libpdx_default_transport/Android.bp
+++ b/libs/vr/libpdx_default_transport/Android.bp
@@ -12,6 +12,10 @@
name: "pdx_default_transport_lib_defaults",
export_include_dirs: ["private"],
whole_static_libs: ["libpdx"],
+ vendor_available: false,
+ vndk: {
+ enabled: true,
+ },
}
cc_defaults {
diff --git a/libs/vr/libpdx_uds/Android.bp b/libs/vr/libpdx_uds/Android.bp
index d640950..79cfdf6 100644
--- a/libs/vr/libpdx_uds/Android.bp
+++ b/libs/vr/libpdx_uds/Android.bp
@@ -30,6 +30,10 @@
whole_static_libs: [
"libselinux",
],
+ vendor_available: false,
+ vndk: {
+ enabled: true,
+ },
}
cc_test {
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index 5d796dc..4f5d548 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -457,13 +457,6 @@
layer.Prepare();
}
- HWC::Error error = Validate(composer_callback_->GetDisplayId());
- if (error != HWC::Error::None) {
- ALOGE("HardwareComposer::PostLayers: Validate failed: %s",
- error.to_string().c_str());
- return;
- }
-
// Now that we have taken in a frame from the application, we have a chance
// to drop the frame before passing the frame along to HWC.
// If the display driver has become backed up, we detect it here and then
@@ -504,6 +497,13 @@
}
#endif
+ HWC::Error error = Validate(composer_callback_->GetDisplayId());
+ if (error != HWC::Error::None) {
+ ALOGE("HardwareComposer::PostLayers: Validate failed: %s",
+ error.to_string().c_str());
+ return;
+ }
+
error = Present(composer_callback_->GetDisplayId());
if (error != HWC::Error::None) {
ALOGE("HardwareComposer::PostLayers: Present failed: %s",
@@ -862,17 +862,13 @@
ATRACE_INT64("sleep_time_ns", sleep_time_ns);
if (sleep_time_ns > 0) {
int error = SleepUntil(wakeup_time_ns);
- ALOGE_IF(error < 0, "HardwareComposer::PostThread: Failed to sleep: %s",
+ ALOGE_IF(error < 0 && error != kPostThreadInterrupted,
+ "HardwareComposer::PostThread: Failed to sleep: %s",
strerror(-error));
- if (error == kPostThreadInterrupted) {
- if (layer_config_changed) {
- // If the layer config changed we need to validateDisplay() even if
- // we're going to drop the frame, to flush the Composer object's
- // internal command buffer and apply our layer changes.
- Validate(composer_callback_->GetDisplayId());
- }
- continue;
- }
+ // If the sleep was interrupted (error == kPostThreadInterrupted),
+ // we still go through and present this frame because we may have set
+ // layers earlier and we want to flush the Composer's internal command
+ // buffer by continuing through to validate and present.
}
}
diff --git a/opengl/specs/README b/opengl/specs/README
index cba4453..fdafb1b 100644
--- a/opengl/specs/README
+++ b/opengl/specs/README
@@ -24,7 +24,8 @@
0x314A EGL_IMAGE_CROP_RIGHT_ANDROID (EGL_ANDROID_image_crop)
0x314B EGL_IMAGE_CROP_BOTTOM_ANDROID (EGL_ANDROID_image_crop)
0x314C EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID (EGL_ANDROID_front_buffer_auto_refresh)
-0x314D - 0x314F (unused)
+0x314D EGL_GL_COLORSPACE_DEFAULT_EXT (EGL_EXT_image_gl_colorspace)
+0x314E - 0x314F (unused)
Value Extension
================ ==================================
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index 0a05dd1..956844f 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -29,11 +29,11 @@
SensorService::SensorEventConnection::SensorEventConnection(
const sp<SensorService>& service, uid_t uid, String8 packageName, bool isDataInjectionMode,
- const String16& opPackageName)
+ const String16& opPackageName, bool hasSensorAccess)
: mService(service), mUid(uid), mWakeLockRefCount(0), mHasLooperCallbacks(false),
mDead(false), mDataInjectionMode(isDataInjectionMode), mEventCache(NULL),
mCacheSize(0), mMaxCacheSize(0), mPackageName(packageName), mOpPackageName(opPackageName),
- mDestroyed(false) {
+ mDestroyed(false), mHasSensorAccess(hasSensorAccess) {
mChannel = new BitTube(mService->mSocketBufferSize);
#if DEBUG_CONNECTIONS
mEventsReceived = mEventsSentFromCache = mEventsSent = 0;
@@ -223,6 +223,9 @@
sensors_event_t* scratch,
wp<const SensorEventConnection> const * mapFlushEventsToConnections) {
// filter out events not for this connection
+
+ sensors_event_t* sanitizedBuffer = nullptr;
+
int count = 0;
Mutex::Autolock _l(mConnectionLock);
if (scratch) {
@@ -273,24 +276,36 @@
if (mapFlushEventsToConnections[i] == this) {
scratch[count++] = buffer[i];
}
- ++i;
} else {
// Regular sensor event, just copy it to the scratch buffer.
- scratch[count++] = buffer[i++];
+ if (mHasSensorAccess) {
+ scratch[count++] = buffer[i];
+ }
}
+ i++;
} while ((i<numEvents) && ((buffer[i].sensor == sensor_handle &&
buffer[i].type != SENSOR_TYPE_META_DATA) ||
(buffer[i].type == SENSOR_TYPE_META_DATA &&
buffer[i].meta_data.sensor == sensor_handle)));
}
} else {
- scratch = const_cast<sensors_event_t *>(buffer);
- count = numEvents;
+ if (mHasSensorAccess) {
+ scratch = const_cast<sensors_event_t *>(buffer);
+ count = numEvents;
+ } else {
+ scratch = sanitizedBuffer = new sensors_event_t[numEvents];
+ for (size_t i = 0; i < numEvents; i++) {
+ if (buffer[i].type == SENSOR_TYPE_META_DATA) {
+ scratch[count++] = buffer[i++];
+ }
+ }
+ }
}
sendPendingFlushEventsLocked();
// Early return if there are no events for this connection.
if (count == 0) {
+ delete sanitizedBuffer;
return status_t(NO_ERROR);
}
@@ -308,6 +323,7 @@
// the max cache size that is desired.
if (mCacheSize + count < computeMaxCacheSizeLocked()) {
reAllocateCacheLocked(scratch, count);
+ delete sanitizedBuffer;
return status_t(NO_ERROR);
}
// Some events need to be dropped.
@@ -326,16 +342,20 @@
memcpy(&mEventCache[mCacheSize - numEventsDropped], scratch + remaningCacheSize,
numEventsDropped * sizeof(sensors_event_t));
}
+ delete sanitizedBuffer;
return status_t(NO_ERROR);
}
- int index_wake_up_event = findWakeUpSensorEventLocked(scratch, count);
- if (index_wake_up_event >= 0) {
- scratch[index_wake_up_event].flags |= WAKE_UP_SENSOR_EVENT_NEEDS_ACK;
- ++mWakeLockRefCount;
+ int index_wake_up_event = -1;
+ if (mHasSensorAccess) {
+ index_wake_up_event = findWakeUpSensorEventLocked(scratch, count);
+ if (index_wake_up_event >= 0) {
+ scratch[index_wake_up_event].flags |= WAKE_UP_SENSOR_EVENT_NEEDS_ACK;
+ ++mWakeLockRefCount;
#if DEBUG_CONNECTIONS
- ++mTotalAcksNeeded;
+ ++mTotalAcksNeeded;
#endif
+ }
}
// NOTE: ASensorEvent and sensors_event_t are the same type.
@@ -364,6 +384,7 @@
// Add this file descriptor to the looper to get a callback when this fd is available for
// writing.
updateLooperRegistrationLocked(mService->getLooper());
+ delete sanitizedBuffer;
return size;
}
@@ -373,9 +394,15 @@
}
#endif
+ delete sanitizedBuffer;
return size < 0 ? status_t(size) : status_t(NO_ERROR);
}
+void SensorService::SensorEventConnection::setSensorAccess(const bool hasAccess) {
+ Mutex::Autolock _l(mConnectionLock);
+ mHasSensorAccess = hasAccess;
+}
+
void SensorService::SensorEventConnection::reAllocateCacheLocked(sensors_event_t const* scratch,
int count) {
sensors_event_t *eventCache_new;
@@ -437,15 +464,18 @@
sendPendingFlushEventsLocked();
for (int numEventsSent = 0; numEventsSent < mCacheSize;) {
const int numEventsToWrite = helpers::min(mCacheSize - numEventsSent, maxWriteSize);
- int index_wake_up_event =
- findWakeUpSensorEventLocked(mEventCache + numEventsSent, numEventsToWrite);
- if (index_wake_up_event >= 0) {
- mEventCache[index_wake_up_event + numEventsSent].flags |=
- WAKE_UP_SENSOR_EVENT_NEEDS_ACK;
- ++mWakeLockRefCount;
+ int index_wake_up_event = -1;
+ if (mHasSensorAccess) {
+ index_wake_up_event =
+ findWakeUpSensorEventLocked(mEventCache + numEventsSent, numEventsToWrite);
+ if (index_wake_up_event >= 0) {
+ mEventCache[index_wake_up_event + numEventsSent].flags |=
+ WAKE_UP_SENSOR_EVENT_NEEDS_ACK;
+ ++mWakeLockRefCount;
#if DEBUG_CONNECTIONS
- ++mTotalAcksNeeded;
+ ++mTotalAcksNeeded;
#endif
+ }
}
ssize_t size = SensorEventQueue::write(mChannel,
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index 6f282cd..032721e 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -49,7 +49,8 @@
public:
SensorEventConnection(const sp<SensorService>& service, uid_t uid, String8 packageName,
- bool isDataInjectionMode, const String16& opPackageName);
+ bool isDataInjectionMode, const String16& opPackageName,
+ bool hasSensorAccess);
status_t sendEvents(sensors_event_t const* buffer, size_t count, sensors_event_t* scratch,
wp<const SensorEventConnection> const * mapFlushEventsToConnections = NULL);
@@ -66,6 +67,8 @@
uid_t getUid() const { return mUid; }
+ void setSensorAccess(const bool hasAccess);
+
private:
virtual ~SensorEventConnection();
virtual void onFirstRef();
@@ -167,6 +170,7 @@
mutable Mutex mDestroyLock;
bool mDestroyed;
+ bool mHasSensorAccess;
};
} // namepsace android
diff --git a/services/sensorservice/SensorRegistrationInfo.h b/services/sensorservice/SensorRegistrationInfo.h
index 75e8989..bba8372 100644
--- a/services/sensorservice/SensorRegistrationInfo.h
+++ b/services/sensorservice/SensorRegistrationInfo.h
@@ -35,12 +35,12 @@
}
SensorRegistrationInfo(int32_t handle, const String8 &packageName,
- int32_t samplingRateNs, int32_t maxReportLatencyNs, bool activate) {
+ int64_t samplingRateNs, int64_t maxReportLatencyNs, bool activate) {
mSensorHandle = handle;
mPackageName = packageName;
- mSamplingRateUs = static_cast<int32_t>(samplingRateNs/1000);
- mMaxReportLatencyUs = static_cast<int32_t>(maxReportLatencyNs/1000);
+ mSamplingRateUs = static_cast<int64_t>(samplingRateNs/1000);
+ mMaxReportLatencyUs = static_cast<int64_t>(maxReportLatencyNs/1000);
mActivated = activate;
IPCThreadState *thread = IPCThreadState::self();
@@ -82,8 +82,8 @@
String8 mPackageName;
pid_t mPid;
uid_t mUid;
- int32_t mSamplingRateUs;
- int32_t mMaxReportLatencyUs;
+ int64_t mSamplingRateUs;
+ int64_t mMaxReportLatencyUs;
bool mActivated;
int8_t mHour, mMin, mSec;
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index dc491d9..c32ffb9 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -13,11 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include <binder/ActivityManager.h>
#include <binder/AppOpsManager.h>
#include <binder/BinderService.h>
#include <binder/IServiceManager.h>
#include <binder/PermissionCache.h>
+#include <binder/PermissionController.h>
#include <cutils/ashmem.h>
+#include <cutils/misc.h>
#include <cutils/properties.h>
#include <hardware/sensors.h>
#include <hardware_legacy/power.h>
@@ -52,6 +55,8 @@
#include <sys/types.h>
#include <unistd.h>
+#include <private/android_filesystem_config.h>
+
namespace android {
// ---------------------------------------------------------------------------
@@ -75,6 +80,7 @@
// Permissions.
static const String16 sDumpPermission("android.permission.DUMP");
static const String16 sLocationHardwarePermission("android.permission.LOCATION_HARDWARE");
+static const String16 sManageSensorsPermission("android.permission.MANAGE_SENSORS");
SensorService::SensorService()
: mInitCheck(NO_INIT), mSocketBufferSize(SOCKET_BUFFER_SIZE_NON_BATCHED),
@@ -274,6 +280,23 @@
// priority can only be changed after run
enableSchedFifoMode();
+
+ // Start watching UID changes to apply policy.
+ mUidPolicy = new UidPolicy(this);
+ mUidPolicy->registerSelf();
+ }
+ }
+}
+
+void SensorService::setSensorAccess(uid_t uid, bool hasAccess) {
+ SortedVector< sp<SensorEventConnection> > activeConnections;
+ populateActiveConnections(&activeConnections);
+ {
+ Mutex::Autolock _l(mLock);
+ for (size_t i = 0 ; i < activeConnections.size(); i++) {
+ if (activeConnections[i] != 0 && activeConnections[i]->getUid() == uid) {
+ activeConnections[i]->setSensorAccess(hasAccess);
+ }
}
}
}
@@ -312,6 +335,7 @@
for (auto && entry : mRecentEvent) {
delete entry.second;
}
+ mUidPolicy->unregisterSelf();
}
status_t SensorService::dump(int fd, const Vector<String16>& args) {
@@ -488,6 +512,82 @@
return NO_ERROR;
}
+// NOTE: This is a remote API - make sure all args are validated
+status_t SensorService::shellCommand(int in, int out, int err, Vector<String16>& args) {
+ if (!checkCallingPermission(sManageSensorsPermission, nullptr, nullptr)) {
+ return PERMISSION_DENIED;
+ }
+ if (in == BAD_TYPE || out == BAD_TYPE || err == BAD_TYPE) {
+ return BAD_VALUE;
+ }
+ if (args.size() == 3 && args[0] == String16("set-uid-state")) {
+ return handleSetUidState(args, err);
+ } else if (args.size() == 2 && args[0] == String16("reset-uid-state")) {
+ return handleResetUidState(args, err);
+ } else if (args.size() == 2 && args[0] == String16("get-uid-state")) {
+ return handleGetUidState(args, out, err);
+ } else if (args.size() == 1 && args[0] == String16("help")) {
+ printHelp(out);
+ return NO_ERROR;
+ }
+ printHelp(err);
+ return BAD_VALUE;
+}
+
+status_t SensorService::handleSetUidState(Vector<String16>& args, int err) {
+ PermissionController pc;
+ int uid = pc.getPackageUid(args[1], 0);
+ if (uid <= 0) {
+ ALOGE("Unknown package: '%s'", String8(args[1]).string());
+ dprintf(err, "Unknown package: '%s'\n", String8(args[1]).string());
+ return BAD_VALUE;
+ }
+ bool active = false;
+ if (args[2] == String16("active")) {
+ active = true;
+ } else if ((args[2] != String16("idle"))) {
+ ALOGE("Expected active or idle but got: '%s'", String8(args[2]).string());
+ return BAD_VALUE;
+ }
+ mUidPolicy->addOverrideUid(uid, active);
+ return NO_ERROR;
+}
+
+status_t SensorService::handleResetUidState(Vector<String16>& args, int err) {
+ PermissionController pc;
+ int uid = pc.getPackageUid(args[1], 0);
+ if (uid < 0) {
+ ALOGE("Unknown package: '%s'", String8(args[1]).string());
+ dprintf(err, "Unknown package: '%s'\n", String8(args[1]).string());
+ return BAD_VALUE;
+ }
+ mUidPolicy->removeOverrideUid(uid);
+ return NO_ERROR;
+}
+
+status_t SensorService::handleGetUidState(Vector<String16>& args, int out, int err) {
+ PermissionController pc;
+ int uid = pc.getPackageUid(args[1], 0);
+ if (uid < 0) {
+ ALOGE("Unknown package: '%s'", String8(args[1]).string());
+ dprintf(err, "Unknown package: '%s'\n", String8(args[1]).string());
+ return BAD_VALUE;
+ }
+ if (mUidPolicy->isUidActive(uid)) {
+ return dprintf(out, "active\n");
+ } else {
+ return dprintf(out, "idle\n");
+ }
+}
+
+status_t SensorService::printHelp(int out) {
+ return dprintf(out, "Sensor service commands:\n"
+ " get-uid-state <PACKAGE> gets the uid state\n"
+ " set-uid-state <PACKAGE> <active|idle> overrides the uid state\n"
+ " reset-uid-state <PACKAGE> clears the uid state override\n"
+ " help print this message\n");
+}
+
//TODO: move to SensorEventConnection later
void SensorService::cleanupAutoDisabledSensorLocked(const sp<SensorEventConnection>& connection,
sensors_event_t const* buffer, const int count) {
@@ -677,7 +777,6 @@
}
}
-
// Send our events to clients. Check the state of wake lock for each client and release the
// lock if none of the clients need it.
bool needsWakeLock = false;
@@ -939,8 +1038,9 @@
(packageName == "") ? String8::format("unknown_package_pid_%d", pid) : packageName;
String16 connOpPackageName =
(opPackageName == String16("")) ? String16(connPackageName) : opPackageName;
+ bool hasSensorAccess = mUidPolicy->isUidActive(uid);
sp<SensorEventConnection> result(new SensorEventConnection(this, uid, connPackageName,
- requestedMode == DATA_INJECTION, connOpPackageName));
+ requestedMode == DATA_INJECTION, connOpPackageName, hasSensorAccess));
if (requestedMode == DATA_INJECTION) {
if (mActiveConnections.indexOf(result) < 0) {
mActiveConnections.add(result);
@@ -1530,4 +1630,98 @@
return false;
}
+void SensorService::UidPolicy::registerSelf() {
+ ActivityManager am;
+ am.registerUidObserver(this, ActivityManager::UID_OBSERVER_GONE
+ | ActivityManager::UID_OBSERVER_IDLE
+ | ActivityManager::UID_OBSERVER_ACTIVE,
+ ActivityManager::PROCESS_STATE_UNKNOWN,
+ String16("android"));
+}
+
+void SensorService::UidPolicy::unregisterSelf() {
+ ActivityManager am;
+ am.unregisterUidObserver(this);
+}
+
+void SensorService::UidPolicy::onUidGone(__unused uid_t uid, __unused bool disabled) {
+ onUidIdle(uid, disabled);
+}
+
+void SensorService::UidPolicy::onUidActive(uid_t uid) {
+ {
+ Mutex::Autolock _l(mUidLock);
+ mActiveUids.insert(uid);
+ }
+ sp<SensorService> service = mService.promote();
+ if (service != nullptr) {
+ service->setSensorAccess(uid, true);
+ }
+}
+
+void SensorService::UidPolicy::onUidIdle(uid_t uid, __unused bool disabled) {
+ bool deleted = false;
+ {
+ Mutex::Autolock _l(mUidLock);
+ if (mActiveUids.erase(uid) > 0) {
+ deleted = true;
+ }
+ }
+ if (deleted) {
+ sp<SensorService> service = mService.promote();
+ if (service != nullptr) {
+ service->setSensorAccess(uid, false);
+ }
+ }
+}
+
+void SensorService::UidPolicy::addOverrideUid(uid_t uid, bool active) {
+ updateOverrideUid(uid, active, true);
+}
+
+void SensorService::UidPolicy::removeOverrideUid(uid_t uid) {
+ updateOverrideUid(uid, false, false);
+}
+
+void SensorService::UidPolicy::updateOverrideUid(uid_t uid, bool active, bool insert) {
+ bool wasActive = false;
+ bool isActive = false;
+ {
+ Mutex::Autolock _l(mUidLock);
+ wasActive = isUidActiveLocked(uid);
+ mOverrideUids.erase(uid);
+ if (insert) {
+ mOverrideUids.insert(std::pair<uid_t, bool>(uid, active));
+ }
+ isActive = isUidActiveLocked(uid);
+ }
+ if (wasActive != isActive) {
+ sp<SensorService> service = mService.promote();
+ if (service != nullptr) {
+ service->setSensorAccess(uid, isActive);
+ }
+ }
+}
+
+bool SensorService::UidPolicy::isUidActive(uid_t uid) {
+ // Non-app UIDs are considered always active
+ if (uid < FIRST_APPLICATION_UID) {
+ return true;
+ }
+ Mutex::Autolock _l(mUidLock);
+ return isUidActiveLocked(uid);
+}
+
+bool SensorService::UidPolicy::isUidActiveLocked(uid_t uid) {
+ // Non-app UIDs are considered always active
+ if (uid < FIRST_APPLICATION_UID) {
+ return true;
+ }
+ auto it = mOverrideUids.find(uid);
+ if (it != mOverrideUids.end()) {
+ return it->second;
+ }
+ return mActiveUids.find(uid) != mActiveUids.end();
+}
+
}; // namespace android
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 3e18394..f71723d 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -21,6 +21,7 @@
#include "RecentEventLogger.h"
#include <binder/BinderService.h>
+#include <binder/IUidObserver.h>
#include <cutils/compiler.h>
#include <sensor/ISensorServer.h>
#include <sensor/ISensorEventConnection.h>
@@ -85,6 +86,9 @@
status_t flushSensor(const sp<SensorEventConnection>& connection,
const String16& opPackageName);
+
+ virtual status_t shellCommand(int in, int out, int err, Vector<String16>& args);
+
private:
friend class BinderService<SensorService>;
@@ -93,6 +97,40 @@
class SensorEventAckReceiver;
class SensorRegistrationInfo;
+ // If accessing a sensor we need to make sure the UID has access to it. If
+ // the app UID is idle then it cannot access sensors and gets no trigger
+ // events, no on-change events, flush event behavior does not change, and
+ // recurring events are the same as the first one delivered in idle state
+ // emulating no sensor change. As soon as the app UID transitions to an
+ // active state we will start reporting events as usual and vise versa. This
+ // approach transparently handles observing sensors while the app UID transitions
+ // between idle/active state avoiding to get stuck in a state receiving sensor
+ // data while idle or not receiving sensor data while active.
+ class UidPolicy : public BnUidObserver {
+ public:
+ explicit UidPolicy(wp<SensorService> service)
+ : mService(service) {}
+ void registerSelf();
+ void unregisterSelf();
+
+ bool isUidActive(uid_t uid);
+
+ void onUidGone(uid_t uid, bool disabled);
+ void onUidActive(uid_t uid);
+ void onUidIdle(uid_t uid, bool disabled);
+
+ void addOverrideUid(uid_t uid, bool active);
+ void removeOverrideUid(uid_t uid);
+ private:
+ bool isUidActiveLocked(uid_t uid);
+ void updateOverrideUid(uid_t uid, bool active, bool insert);
+
+ Mutex mUidLock;
+ wp<SensorService> mService;
+ std::unordered_set<uid_t> mActiveUids;
+ std::unordered_map<uid_t, bool> mOverrideUids;
+ };
+
enum Mode {
// The regular operating mode where any application can register/unregister/call flush on
// sensors.
@@ -161,7 +199,6 @@
virtual int setOperationParameter(
int32_t handle, int32_t type, const Vector<float> &floats, const Vector<int32_t> &ints);
virtual status_t dump(int fd, const Vector<String16>& args);
-
String8 getSensorName(int handle) const;
bool isVirtualSensor(int handle) const;
sp<SensorInterface> getSensorInterfaceFromHandle(int handle) const;
@@ -225,6 +262,18 @@
// Enable SCHED_FIFO priority for thread
void enableSchedFifoMode();
+ // Sets whether the given UID can get sensor data
+ void setSensorAccess(uid_t uid, bool hasAccess);
+
+ // Overrides the UID state as if it is idle
+ status_t handleSetUidState(Vector<String16>& args, int err);
+ // Clears the override for the UID state
+ status_t handleResetUidState(Vector<String16>& args, int err);
+ // Gets the UID state
+ status_t handleGetUidState(Vector<String16>& args, int out, int err);
+ // Prints the shell command help
+ status_t printHelp(int out);
+
static uint8_t sHmacGlobalKey[128];
static bool sHmacGlobalKeyIsValid;
@@ -257,6 +306,8 @@
int mNextSensorRegIndex;
Vector<SensorRegistrationInfo> mLastNSensorRegistrations;
+
+ sp<UidPolicy> mUidPolicy;
};
} // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index a663487..d121a86 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -203,7 +203,7 @@
}
void DisplayDevice::swapBuffers(HWComposer& hwc) const {
- if (hwc.hasClientComposition(mHwcDisplayId)) {
+ if (hwc.hasClientComposition(mHwcDisplayId) || hwc.hasFlipClientTargetRequest(mHwcDisplayId)) {
mSurface.swapBuffers();
}
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 1677b07..7eb3998 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -564,6 +564,20 @@
return mDisplayData[displayId].hasDeviceComposition;
}
+bool HWComposer::hasFlipClientTargetRequest(int32_t displayId) const {
+ if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
+ // Displays without a corresponding HWC display are never composed by
+ // the device
+ return false;
+ }
+ if (!isValidDisplay(displayId)) {
+ ALOGE("hasFlipClientTargetRequest: Invalid display %d", displayId);
+ return false;
+ }
+ return ((static_cast<uint32_t>(mDisplayData[displayId].displayRequests) &
+ static_cast<uint32_t>(HWC2::DisplayRequest::FlipClientTarget)) != 0);
+}
+
bool HWComposer::hasClientComposition(int32_t displayId) const {
if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
// Displays without a corresponding HWC display are always composed by
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index ee0a725..2e4f5d4 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -108,6 +108,9 @@
// does this display have layers handled by HWC
bool hasDeviceComposition(int32_t displayId) const;
+ // does this display have pending request to flip client target
+ bool hasFlipClientTargetRequest(int32_t displayId) const;
+
// does this display have layers handled by GLES
bool hasClientComposition(int32_t displayId) const;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 63f6781..067a09f 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -626,9 +626,15 @@
transform = Transform(invTransform) * tr * bufferOrientation;
}
+ // STOPSHIP (b/72106793): If we have less than 25% scaling, HWC usually needs to use the rotator
+ // to handle it. However, there is one guaranteed frame of jank when we switch to using the
+ // rotator. In the meantime, we force GL composition instead until we have a better fix for the
+ // HWC issue.
+ bool extremeScaling = abs(t[0][0]) <= 0.25 || abs(t[1][1]) <= 0.25;
+
// this gives us only the "orientation" component of the transform
const uint32_t orientation = transform.getOrientation();
- if (orientation & Transform::ROT_INVALID) {
+ if (orientation & Transform::ROT_INVALID || extremeScaling) {
// we can only handle simple transformation
hwcInfo.forceClientComposition = true;
} else {
@@ -871,6 +877,12 @@
this->visibleNonTransparentRegion = setVisibleNonTransparentRegion;
}
+void Layer::clearVisibilityRegions() {
+ visibleRegion.clear();
+ visibleNonTransparentRegion.clear();
+ coveredRegion.clear();
+}
+
// ----------------------------------------------------------------------------
// transaction
// ----------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index e44ccf8..c63399e 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -435,6 +435,11 @@
void setVisibleNonTransparentRegion(const Region& visibleNonTransparentRegion);
/*
+ * Clear the visible, covered, and non-transparent regions.
+ */
+ void clearVisibilityRegions();
+
+ /*
* latchBuffer - called each time the screen is redrawn and returns whether
* the visible regions need to be recomputed (this is a fairly heavy
* operation, so this should be set only if needed). Typically this is used
diff --git a/services/surfaceflinger/RenderEngine/GLExtensions.cpp b/services/surfaceflinger/RenderEngine/GLExtensions.cpp
index e6e4df1..dc09a37 100644
--- a/services/surfaceflinger/RenderEngine/GLExtensions.cpp
+++ b/services/surfaceflinger/RenderEngine/GLExtensions.cpp
@@ -106,6 +106,9 @@
if (hasEGLExtension("EGL_EXT_protected_content")) {
mHasProtectedContent = true;
}
+ if (hasEGLExtension("EGL_IMG_context_priority")) {
+ mHasContextPriority = true;
+ }
}
char const* GLExtensions::getEGLVersion() const {
diff --git a/services/surfaceflinger/RenderEngine/GLExtensions.h b/services/surfaceflinger/RenderEngine/GLExtensions.h
index 81078e0..0d8c10b 100644
--- a/services/surfaceflinger/RenderEngine/GLExtensions.h
+++ b/services/surfaceflinger/RenderEngine/GLExtensions.h
@@ -41,6 +41,7 @@
bool mHasWaitSync = false;
bool mHasImageCrop = false;
bool mHasProtectedContent = false;
+ bool mHasContextPriority = false;
String8 mVendor;
String8 mRenderer;
@@ -67,6 +68,7 @@
bool hasWaitSync() const { return mHasWaitSync; }
bool hasImageCrop() const { return mHasImageCrop; }
bool hasProtectedContent() const { return mHasProtectedContent; }
+ bool hasContextPriority() const { return mHasContextPriority; }
void initWithGLStrings(GLubyte const* vendor, GLubyte const* renderer, GLubyte const* version,
GLubyte const* extensions);
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index 179b790..22016ed 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -27,6 +27,12 @@
#include <SurfaceFlinger.h>
#include <vector>
+#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <configstore/Utils.h>
+
+using namespace android::hardware::configstore;
+using namespace android::hardware::configstore::V1_0;
+
extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
// ---------------------------------------------------------------------------
@@ -70,13 +76,11 @@
contextAttributes.reserve(6);
contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
contextAttributes.push_back(contextClientVersion);
-#ifdef EGL_IMG_context_priority
- if (SurfaceFlinger::useContextPriority) {
+ bool useContextPriority = overrideUseContextPriorityFromConfig(extensions.hasContextPriority());
+ if (useContextPriority) {
contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG);
contextAttributes.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG);
}
-#endif
- contextAttributes.push_back(EGL_NONE);
contextAttributes.push_back(EGL_NONE);
EGLContext ctxt = eglCreateContext(display, config, nullptr, contextAttributes.data());
@@ -131,6 +135,18 @@
return engine;
}
+bool RenderEngine::overrideUseContextPriorityFromConfig(bool useContextPriority) {
+ OptionalBool ret;
+ ISurfaceFlingerConfigs::getService()->useContextPriority([&ret](OptionalBool b) {
+ ret = b;
+ });
+ if (ret.specified) {
+ return ret.value;
+ } else {
+ return useContextPriority;
+ }
+}
+
RenderEngine::RenderEngine()
: mEGLDisplay(EGL_NO_DISPLAY), mEGLConfig(nullptr), mEGLContext(EGL_NO_CONTEXT) {}
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index f886919..737b1dd 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -66,6 +66,8 @@
uint32_t* status) = 0;
virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName) = 0;
+ static bool overrideUseContextPriorityFromConfig(bool useContextPriority);
+
protected:
RenderEngine();
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f21a691..a91525d 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -129,7 +129,6 @@
// ---------------------------------------------------------------------------
int64_t SurfaceFlinger::vsyncPhaseOffsetNs;
int64_t SurfaceFlinger::sfVsyncPhaseOffsetNs;
-bool SurfaceFlinger::useContextPriority;
int64_t SurfaceFlinger::dispSyncPresentTimeOffset;
bool SurfaceFlinger::useHwcForRgbToYuv;
uint64_t SurfaceFlinger::maxVirtualDisplaySize;
@@ -207,9 +206,6 @@
hasSyncFramework = getBool< ISurfaceFlingerConfigs,
&ISurfaceFlingerConfigs::hasSyncFramework>(true);
- useContextPriority = getBool< ISurfaceFlingerConfigs,
- &ISurfaceFlingerConfigs::useContextPriority>(false);
-
dispSyncPresentTimeOffset = getInt64< ISurfaceFlingerConfigs,
&ISurfaceFlingerConfigs::presentTimeOffsetFromVSyncNs>(0);
@@ -2534,6 +2530,11 @@
}
}
+ if (visibleRegion.isEmpty()) {
+ layer->clearVisibilityRegions();
+ return;
+ }
+
// Clip the covered region to the visible region
coveredRegion = aboveCoveredLayers.intersect(visibleRegion);
@@ -3687,7 +3688,6 @@
void SurfaceFlinger::appendSfConfigString(String8& result) const
{
result.append(" [sf");
- result.appendFormat(" HAS_CONTEXT_PRIORITY=%d", useContextPriority);
if (isLayerTripleBufferingDisabled())
result.append(" DISABLE_TRIPLE_BUFFERING");
@@ -4645,6 +4645,9 @@
continue;
}
layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
+ if (!layer->belongsToDisplay(hw->getLayerStack(), false)) {
+ return;
+ }
if (!layer->isVisible()) {
return;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index a18be9b..4da0803 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -227,9 +227,6 @@
// If fences from sync Framework are supported.
static bool hasSyncFramework;
- // Instruct the Render Engine to use EGL_IMG_context_priority is available.
- static bool useContextPriority;
-
// The offset in nanoseconds to use when DispSync timestamps present fence
// signaling time.
static int64_t dispSyncPresentTimeOffset;
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index ade0bde..26f60fb 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -19,9 +19,9 @@
#include <string.h>
#include <sys/prctl.h>
+#include <dlfcn.h>
#include <algorithm>
#include <array>
-#include <dlfcn.h>
#include <new>
#include <log/log.h>
@@ -1047,17 +1047,54 @@
VkInstance instance,
uint32_t* pPhysicalDeviceGroupCount,
VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) {
+ VkResult result = VK_SUCCESS;
const auto& data = GetData(instance);
- VkResult result = data.driver.EnumeratePhysicalDeviceGroups(
- instance, pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties);
- if ((result == VK_SUCCESS || result == VK_INCOMPLETE) &&
- *pPhysicalDeviceGroupCount && pPhysicalDeviceGroupProperties) {
- for (uint32_t i = 0; i < *pPhysicalDeviceGroupCount; i++) {
- for (uint32_t j = 0;
- j < pPhysicalDeviceGroupProperties->physicalDeviceCount; j++) {
- SetData(pPhysicalDeviceGroupProperties->physicalDevices[j],
+ if (!data.driver.EnumeratePhysicalDeviceGroups) {
+ uint32_t device_count = 0;
+ result = EnumeratePhysicalDevices(instance, &device_count, nullptr);
+ if (result < 0)
+ return result;
+ if (!pPhysicalDeviceGroupProperties) {
+ *pPhysicalDeviceGroupCount = device_count;
+ return result;
+ }
+
+ device_count = std::min(device_count, *pPhysicalDeviceGroupCount);
+ if (!device_count) {
+ *pPhysicalDeviceGroupCount = 0;
+ return result;
+ }
+
+ android::Vector<VkPhysicalDevice> devices;
+ devices.resize(device_count);
+
+ result = EnumeratePhysicalDevices(instance, &device_count,
+ devices.editArray());
+ if (result < 0)
+ return result;
+
+ devices.resize(device_count);
+ *pPhysicalDeviceGroupCount = device_count;
+ for (uint32_t i = 0; i < device_count; ++i) {
+ pPhysicalDeviceGroupProperties[i].physicalDeviceCount = 1;
+ pPhysicalDeviceGroupProperties[i].physicalDevices[0] = devices[i];
+ pPhysicalDeviceGroupProperties[i].subsetAllocation = 0;
+ }
+ } else {
+ result = data.driver.EnumeratePhysicalDeviceGroups(
+ instance, pPhysicalDeviceGroupCount,
+ pPhysicalDeviceGroupProperties);
+ if ((result == VK_SUCCESS || result == VK_INCOMPLETE) &&
+ *pPhysicalDeviceGroupCount && pPhysicalDeviceGroupProperties) {
+ for (uint32_t i = 0; i < *pPhysicalDeviceGroupCount; i++) {
+ for (uint32_t j = 0;
+ j < pPhysicalDeviceGroupProperties[i].physicalDeviceCount;
+ j++) {
+ SetData(
+ pPhysicalDeviceGroupProperties[i].physicalDevices[j],
data);
+ }
}
}
}
diff --git a/vulkan/libvulkan/libvulkan.map.txt b/vulkan/libvulkan/libvulkan.map.txt
index 1745925..d1f6241 100644
--- a/vulkan/libvulkan/libvulkan.map.txt
+++ b/vulkan/libvulkan/libvulkan.map.txt
@@ -1,12 +1,15 @@
LIBVULKAN {
global:
+ vkAcquireNextImage2KHR; # introduced=28
vkAcquireNextImageKHR;
vkAllocateCommandBuffers;
vkAllocateDescriptorSets;
vkAllocateMemory;
vkBeginCommandBuffer;
vkBindBufferMemory;
+ vkBindBufferMemory2; # introduced=28
vkBindImageMemory;
+ vkBindImageMemory2; # introduced=28
vkCmdBeginQuery;
vkCmdBeginRenderPass;
vkCmdBindDescriptorSets;
@@ -23,6 +26,7 @@
vkCmdCopyImageToBuffer;
vkCmdCopyQueryPoolResults;
vkCmdDispatch;
+ vkCmdDispatchBase; # introduced=28
vkCmdDispatchIndirect;
vkCmdDraw;
vkCmdDrawIndexed;
@@ -41,6 +45,7 @@
vkCmdSetBlendConstants;
vkCmdSetDepthBias;
vkCmdSetDepthBounds;
+ vkCmdSetDeviceMask; # introduced=28
vkCmdSetEvent;
vkCmdSetLineWidth;
vkCmdSetScissor;
@@ -58,6 +63,7 @@
vkCreateComputePipelines;
vkCreateDescriptorPool;
vkCreateDescriptorSetLayout;
+ vkCreateDescriptorUpdateTemplate; # introduced=28
vkCreateDevice;
vkCreateEvent;
vkCreateFence;
@@ -71,6 +77,7 @@
vkCreateQueryPool;
vkCreateRenderPass;
vkCreateSampler;
+ vkCreateSamplerYcbcrConversion; # introduced=28
vkCreateSemaphore;
vkCreateShaderModule;
vkCreateSwapchainKHR;
@@ -79,6 +86,7 @@
vkDestroyCommandPool;
vkDestroyDescriptorPool;
vkDestroyDescriptorSetLayout;
+ vkDestroyDescriptorUpdateTemplate; # introduced=28
vkDestroyDevice;
vkDestroyEvent;
vkDestroyFence;
@@ -92,6 +100,7 @@
vkDestroyQueryPool;
vkDestroyRenderPass;
vkDestroySampler;
+ vkDestroySamplerYcbcrConversion; # introduced=28
vkDestroySemaphore;
vkDestroyShaderModule;
vkDestroySurfaceKHR;
@@ -102,28 +111,49 @@
vkEnumerateDeviceLayerProperties;
vkEnumerateInstanceExtensionProperties;
vkEnumerateInstanceLayerProperties;
+ vkEnumerateInstanceVersion; # introduced=28
+ vkEnumeratePhysicalDeviceGroups; # introduced=28
vkEnumeratePhysicalDevices;
vkFlushMappedMemoryRanges;
vkFreeCommandBuffers;
vkFreeDescriptorSets;
vkFreeMemory;
vkGetBufferMemoryRequirements;
+ vkGetBufferMemoryRequirements2; # introduced=28
+ vkGetDescriptorSetLayoutSupport; # introduced=28
+ vkGetDeviceGroupPeerMemoryFeatures; # introduced=28
+ vkGetDeviceGroupPresentCapabilitiesKHR; # introduced=28
+ vkGetDeviceGroupSurfacePresentModesKHR; # introduced=28
vkGetDeviceMemoryCommitment;
vkGetDeviceProcAddr;
vkGetDeviceQueue;
+ vkGetDeviceQueue2; # introduced=28
vkGetEventStatus;
vkGetFenceStatus;
vkGetImageMemoryRequirements;
+ vkGetImageMemoryRequirements2; # introduced=28
vkGetImageSparseMemoryRequirements;
+ vkGetImageSparseMemoryRequirements2; # introduced=28
vkGetImageSubresourceLayout;
vkGetInstanceProcAddr;
+ vkGetPhysicalDeviceExternalBufferProperties; # introduced=28
+ vkGetPhysicalDeviceExternalFenceProperties; # introduced=28
+ vkGetPhysicalDeviceExternalSemaphoreProperties; # introduced=28
vkGetPhysicalDeviceFeatures;
+ vkGetPhysicalDeviceFeatures2; # introduced=28
vkGetPhysicalDeviceFormatProperties;
+ vkGetPhysicalDeviceFormatProperties2; # introduced=28
vkGetPhysicalDeviceImageFormatProperties;
+ vkGetPhysicalDeviceImageFormatProperties2; # introduced=28
vkGetPhysicalDeviceMemoryProperties;
+ vkGetPhysicalDeviceMemoryProperties2; # introduced=28
+ vkGetPhysicalDevicePresentRectanglesKHR; # introduced=28
vkGetPhysicalDeviceProperties;
+ vkGetPhysicalDeviceProperties2; # introduced=28
vkGetPhysicalDeviceQueueFamilyProperties;
+ vkGetPhysicalDeviceQueueFamilyProperties2; # introduced=28
vkGetPhysicalDeviceSparseImageFormatProperties;
+ vkGetPhysicalDeviceSparseImageFormatProperties2; # introduced=28
vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
vkGetPhysicalDeviceSurfaceFormatsKHR;
vkGetPhysicalDeviceSurfacePresentModesKHR;
@@ -145,8 +175,10 @@
vkResetEvent;
vkResetFences;
vkSetEvent;
+ vkTrimCommandPool; # introduced=28
vkUnmapMemory;
vkUpdateDescriptorSets;
+ vkUpdateDescriptorSetWithTemplate; # introduced=28
vkWaitForFences;
local:
*;