Merge "Update CommandWriter to CommandWriterBase"
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 0fc03e6..4be0432 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
- #define LOG_TAG "atrace"
+#define LOG_TAG "atrace"
#include <errno.h>
#include <fcntl.h>
@@ -112,81 +112,81 @@
{ "adb", "ADB", ATRACE_TAG_ADB, { } },
{ k_coreServiceCategory, "Core services", 0, { } },
{ "sched", "CPU Scheduling", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/sched/sched_switch/enable" },
- { REQ, "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable" },
- { OPT, "/sys/kernel/debug/tracing/events/sched/sched_blocked_reason/enable" },
- { OPT, "/sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug/enable" },
+ { REQ, "events/sched/sched_switch/enable" },
+ { REQ, "events/sched/sched_wakeup/enable" },
+ { OPT, "events/sched/sched_blocked_reason/enable" },
+ { OPT, "events/sched/sched_cpu_hotplug/enable" },
} },
{ "irq", "IRQ Events", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/irq/enable" },
- { OPT, "/sys/kernel/debug/tracing/events/ipi/enable" },
+ { REQ, "events/irq/enable" },
+ { OPT, "events/ipi/enable" },
} },
{ "i2c", "I2C Events", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/i2c/enable" },
- { REQ, "/sys/kernel/debug/tracing/events/i2c/i2c_read/enable" },
- { REQ, "/sys/kernel/debug/tracing/events/i2c/i2c_write/enable" },
- { REQ, "/sys/kernel/debug/tracing/events/i2c/i2c_result/enable" },
- { REQ, "/sys/kernel/debug/tracing/events/i2c/i2c_reply/enable" },
- { OPT, "/sys/kernel/debug/tracing/events/i2c/smbus_read/enable" },
- { OPT, "/sys/kernel/debug/tracing/events/i2c/smbus_write/enable" },
- { OPT, "/sys/kernel/debug/tracing/events/i2c/smbus_result/enable" },
- { OPT, "/sys/kernel/debug/tracing/events/i2c/smbus_reply/enable" },
+ { REQ, "events/i2c/enable" },
+ { REQ, "events/i2c/i2c_read/enable" },
+ { REQ, "events/i2c/i2c_write/enable" },
+ { REQ, "events/i2c/i2c_result/enable" },
+ { REQ, "events/i2c/i2c_reply/enable" },
+ { OPT, "events/i2c/smbus_read/enable" },
+ { OPT, "events/i2c/smbus_write/enable" },
+ { OPT, "events/i2c/smbus_result/enable" },
+ { OPT, "events/i2c/smbus_reply/enable" },
} },
{ "freq", "CPU Frequency", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable" },
- { OPT, "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable" },
- { OPT, "/sys/kernel/debug/tracing/events/power/cpu_frequency_limits/enable" },
+ { REQ, "events/power/cpu_frequency/enable" },
+ { OPT, "events/power/clock_set_rate/enable" },
+ { OPT, "events/power/cpu_frequency_limits/enable" },
} },
{ "membus", "Memory Bus Utilization", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/memory_bus/enable" },
+ { REQ, "events/memory_bus/enable" },
} },
{ "idle", "CPU Idle", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/power/cpu_idle/enable" },
+ { REQ, "events/power/cpu_idle/enable" },
} },
{ "disk", "Disk I/O", 0, {
- { OPT, "/sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_enter/enable" },
- { OPT, "/sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_exit/enable" },
- { OPT, "/sys/kernel/debug/tracing/events/f2fs/f2fs_write_begin/enable" },
- { OPT, "/sys/kernel/debug/tracing/events/f2fs/f2fs_write_end/enable" },
- { OPT, "/sys/kernel/debug/tracing/events/ext4/ext4_da_write_begin/enable" },
- { OPT, "/sys/kernel/debug/tracing/events/ext4/ext4_da_write_end/enable" },
- { OPT, "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable" },
- { OPT, "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable" },
- { REQ, "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable" },
- { REQ, "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable" },
+ { OPT, "events/f2fs/f2fs_sync_file_enter/enable" },
+ { OPT, "events/f2fs/f2fs_sync_file_exit/enable" },
+ { OPT, "events/f2fs/f2fs_write_begin/enable" },
+ { OPT, "events/f2fs/f2fs_write_end/enable" },
+ { OPT, "events/ext4/ext4_da_write_begin/enable" },
+ { OPT, "events/ext4/ext4_da_write_end/enable" },
+ { OPT, "events/ext4/ext4_sync_file_enter/enable" },
+ { OPT, "events/ext4/ext4_sync_file_exit/enable" },
+ { REQ, "events/block/block_rq_issue/enable" },
+ { REQ, "events/block/block_rq_complete/enable" },
} },
{ "mmc", "eMMC commands", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/mmc/enable" },
+ { REQ, "events/mmc/enable" },
} },
{ "load", "CPU Load", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable" },
+ { REQ, "events/cpufreq_interactive/enable" },
} },
{ "sync", "Synchronization", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/sync/enable" },
+ { REQ, "events/sync/enable" },
} },
{ "workq", "Kernel Workqueues", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/workqueue/enable" },
+ { REQ, "events/workqueue/enable" },
} },
{ "memreclaim", "Kernel Memory Reclaim", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable" },
- { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable" },
- { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable" },
- { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable" },
+ { REQ, "events/vmscan/mm_vmscan_direct_reclaim_begin/enable" },
+ { REQ, "events/vmscan/mm_vmscan_direct_reclaim_end/enable" },
+ { REQ, "events/vmscan/mm_vmscan_kswapd_wake/enable" },
+ { REQ, "events/vmscan/mm_vmscan_kswapd_sleep/enable" },
} },
{ "regulators", "Voltage and Current Regulators", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/regulator/enable" },
+ { REQ, "events/regulator/enable" },
} },
{ "binder_driver", "Binder Kernel driver", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/binder/binder_transaction/enable" },
- { REQ, "/sys/kernel/debug/tracing/events/binder/binder_transaction_received/enable" },
+ { REQ, "events/binder/binder_transaction/enable" },
+ { REQ, "events/binder/binder_transaction_received/enable" },
} },
{ "binder_lock", "Binder global lock trace", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/binder/binder_lock/enable" },
- { REQ, "/sys/kernel/debug/tracing/events/binder/binder_locked/enable" },
- { REQ, "/sys/kernel/debug/tracing/events/binder/binder_unlock/enable" },
+ { REQ, "events/binder/binder_lock/enable" },
+ { REQ, "events/binder/binder_locked/enable" },
+ { REQ, "events/binder/binder_unlock/enable" },
} },
{ "pagecache", "Page cache", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/filemap/enable" },
+ { REQ, "events/filemap/enable" },
} },
};
@@ -205,61 +205,62 @@
/* Global state */
static bool g_traceAborted = false;
static bool g_categoryEnables[NELEM(k_categories)] = {};
+static std::string g_traceFolder;
/* Sys file paths */
static const char* k_traceClockPath =
- "/sys/kernel/debug/tracing/trace_clock";
+ "trace_clock";
static const char* k_traceBufferSizePath =
- "/sys/kernel/debug/tracing/buffer_size_kb";
+ "buffer_size_kb";
static const char* k_tracingOverwriteEnablePath =
- "/sys/kernel/debug/tracing/options/overwrite";
+ "options/overwrite";
static const char* k_currentTracerPath =
- "/sys/kernel/debug/tracing/current_tracer";
+ "current_tracer";
static const char* k_printTgidPath =
- "/sys/kernel/debug/tracing/options/print-tgid";
+ "options/print-tgid";
static const char* k_funcgraphAbsTimePath =
- "/sys/kernel/debug/tracing/options/funcgraph-abstime";
+ "options/funcgraph-abstime";
static const char* k_funcgraphCpuPath =
- "/sys/kernel/debug/tracing/options/funcgraph-cpu";
+ "options/funcgraph-cpu";
static const char* k_funcgraphProcPath =
- "/sys/kernel/debug/tracing/options/funcgraph-proc";
+ "options/funcgraph-proc";
static const char* k_funcgraphFlatPath =
- "/sys/kernel/debug/tracing/options/funcgraph-flat";
+ "options/funcgraph-flat";
static const char* k_funcgraphDurationPath =
- "/sys/kernel/debug/tracing/options/funcgraph-duration";
+ "options/funcgraph-duration";
static const char* k_ftraceFilterPath =
- "/sys/kernel/debug/tracing/set_ftrace_filter";
+ "set_ftrace_filter";
static const char* k_tracingOnPath =
- "/sys/kernel/debug/tracing/tracing_on";
+ "tracing_on";
static const char* k_tracePath =
- "/sys/kernel/debug/tracing/trace";
+ "trace";
static const char* k_traceStreamPath =
- "/sys/kernel/debug/tracing/trace_pipe";
+ "trace_pipe";
static const char* k_traceMarkerPath =
- "/sys/kernel/debug/tracing/trace_marker";
+ "trace_marker";
// Check whether a file exists.
static bool fileExists(const char* filename) {
- return access(filename, F_OK) != -1;
+ return access((g_traceFolder + filename).c_str(), F_OK) != -1;
}
// Check whether a file is writable.
static bool fileIsWritable(const char* filename) {
- return access(filename, W_OK) != -1;
+ return access((g_traceFolder + filename).c_str(), W_OK) != -1;
}
// Truncate a file.
@@ -268,9 +269,9 @@
// This uses creat rather than truncate because some of the debug kernel
// device nodes (e.g. k_ftraceFilterPath) currently aren't changed by
// calls to truncate, but they are cleared by calls to creat.
- int traceFD = creat(path, 0);
+ int traceFD = creat((g_traceFolder + path).c_str(), 0);
if (traceFD == -1) {
- fprintf(stderr, "error truncating %s: %s (%d)\n", path,
+ fprintf(stderr, "error truncating %s: %s (%d)\n", (g_traceFolder + path).c_str(),
strerror(errno), errno);
return false;
}
@@ -282,9 +283,10 @@
static bool _writeStr(const char* filename, const char* str, int flags)
{
- int fd = open(filename, flags);
+ std::string fullFilename = g_traceFolder + filename;
+ int fd = open(fullFilename.c_str(), flags);
if (fd == -1) {
- fprintf(stderr, "error opening %s: %s (%d)\n", filename,
+ fprintf(stderr, "error opening %s: %s (%d)\n", fullFilename.c_str(),
strerror(errno), errno);
return false;
}
@@ -292,7 +294,7 @@
bool ok = true;
ssize_t len = strlen(str);
if (write(fd, str, len) != len) {
- fprintf(stderr, "error writing to %s: %s (%d)\n", filename,
+ fprintf(stderr, "error writing to %s: %s (%d)\n", fullFilename.c_str(),
strerror(errno), errno);
ok = false;
}
@@ -318,7 +320,7 @@
{
char buffer[128];
int len = 0;
- int fd = open(k_traceMarkerPath, O_WRONLY);
+ int fd = open((g_traceFolder + k_traceMarkerPath).c_str(), O_WRONLY);
if (fd == -1) {
fprintf(stderr, "error opening %s: %s (%d)\n", k_traceMarkerPath,
strerror(errno), errno);
@@ -439,7 +441,7 @@
// local [global] counter uptime perf
static bool isTraceClock(const char *mode)
{
- int fd = open(k_traceClockPath, O_RDONLY);
+ int fd = open((g_traceFolder + k_traceClockPath).c_str(), O_RDONLY);
if (fd == -1) {
fprintf(stderr, "error opening %s: %s (%d)\n", k_traceClockPath,
strerror(errno), errno);
@@ -652,7 +654,7 @@
static bool verifyKernelTraceFuncs(const char* funcs)
{
std::string buf;
- if (!android::base::ReadFileToString(k_ftraceFilterPath, &buf)) {
+ if (!android::base::ReadFileToString(g_traceFolder + k_ftraceFilterPath, &buf)) {
fprintf(stderr, "error opening %s: %s (%d)\n", k_ftraceFilterPath,
strerror(errno), errno);
return false;
@@ -873,7 +875,7 @@
static void streamTrace()
{
char trace_data[4096];
- int traceFD = open(k_traceStreamPath, O_RDWR);
+ int traceFD = open((g_traceFolder + k_traceStreamPath).c_str(), O_RDWR);
if (traceFD == -1) {
fprintf(stderr, "error opening %s: %s (%d)\n", k_traceStreamPath,
strerror(errno), errno);
@@ -898,7 +900,7 @@
static void dumpTrace(int outFd)
{
ALOGI("Dumping trace");
- int traceFD = open(k_tracePath, O_RDWR);
+ int traceFD = open((g_traceFolder + k_tracePath).c_str(), O_RDWR);
if (traceFD == -1) {
fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
strerror(errno), errno);
@@ -1053,6 +1055,29 @@
);
}
+bool findTraceFiles()
+{
+ static const std::string debugfs_path = "/sys/kernel/debug/tracing/";
+ static const std::string tracefs_path = "/sys/kernel/tracing/";
+ static const std::string trace_file = "trace_marker";
+
+ bool tracefs = access((tracefs_path + trace_file).c_str(), F_OK) != -1;
+ bool debugfs = access((debugfs_path + trace_file).c_str(), F_OK) != -1;
+
+ if (!tracefs && !debugfs) {
+ fprintf(stderr, "Error: Did not find trace folder\n");
+ return false;
+ }
+
+ if (tracefs) {
+ g_traceFolder = tracefs_path;
+ } else {
+ g_traceFolder = debugfs_path;
+ }
+
+ return true;
+}
+
int main(int argc, char **argv)
{
bool async = false;
@@ -1066,6 +1091,11 @@
exit(0);
}
+ if (!findTraceFiles()) {
+ fprintf(stderr, "No trace folder found\n");
+ exit(-1);
+ }
+
for (;;) {
int ret;
int option_index = 0;
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 54ba5ca..cef41be 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -4,72 +4,131 @@
# Allow writing to the kernel trace log.
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/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/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/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/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/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
# 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
on property:persist.debug.atrace.boottrace=1
start boottrace
diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk
index 983700f..efc050b 100644
--- a/cmds/dumpstate/Android.mk
+++ b/cmds/dumpstate/Android.mk
@@ -20,13 +20,13 @@
libbase \
libbinder \
libcutils \
+ libdebuggerd_client \
libdumpstateaidl \
+ libdumpstateutil \
liblog \
libselinux \
libutils \
$(COMMON_ZIP_LIBRARIES)
-COMMON_STATIC_LIBRARIES := \
- libdumpstateutil
# ====================#
# libdumpstateutil #
@@ -42,9 +42,10 @@
DumpstateInternal.cpp \
DumpstateUtil.cpp
LOCAL_SHARED_LIBRARIES := \
- libbase
+ libbase \
+ liblog \
-include $(BUILD_STATIC_LIBRARY)
+include $(BUILD_SHARED_LIBRARY)
# ====================#
# libdumpstateheaders #
@@ -107,8 +108,6 @@
LOCAL_STATIC_LIBRARIES := $(COMMON_STATIC_LIBRARIES)
-LOCAL_HAL_STATIC_LIBRARIES := libdumpstate
-
LOCAL_CFLAGS += $(COMMON_LOCAL_CFLAGS)
LOCAL_INIT_RC := dumpstate.rc
@@ -181,14 +180,3 @@
LOCAL_PICKUP_FILES := $(dumpstate_tests_intermediates)
include $(BUILD_NATIVE_TEST)
-
-# =======================#
-# libdumpstate.default #
-# =======================#
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := libdumpstate_default.cpp
-LOCAL_MODULE := libdumpstate.default
-
-LOCAL_STATIC_LIBRARIES := libdumpstateheaders
-include $(BUILD_STATIC_LIBRARY)
diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp
index d517797..26702c4 100644
--- a/cmds/dumpstate/DumpstateUtil.cpp
+++ b/cmds/dumpstate/DumpstateUtil.cpp
@@ -34,10 +34,14 @@
#include "DumpstateInternal.h"
-// TODO: move to unnamed namespace
+namespace android {
+namespace os {
+namespace dumpstate {
+
+namespace {
+
static constexpr const char* kSuPath = "/system/xbin/su";
-// TODO: move to unnamed namespace
static bool waitpid_with_timeout(pid_t pid, int timeout_seconds, int* status) {
sigset_t child_mask, old_mask;
sigemptyset(&child_mask);
@@ -81,10 +85,10 @@
}
return true;
}
+} // unnamed namespace
CommandOptions CommandOptions::DEFAULT = CommandOptions::WithTimeout(10).Build();
CommandOptions CommandOptions::AS_ROOT = CommandOptions::WithTimeout(10).AsRoot().Build();
-CommandOptions CommandOptions::AS_ROOT_5 = CommandOptions::WithTimeout(5).AsRoot().Build();
CommandOptions::CommandOptionsBuilder::CommandOptionsBuilder(int64_t timeout) : values(timeout) {
}
@@ -374,3 +378,7 @@
closedir(proc_dir);
return -1;
}
+
+} // namespace dumpstate
+} // namespace os
+} // namespace android
diff --git a/cmds/dumpstate/DumpstateUtil.h b/cmds/dumpstate/DumpstateUtil.h
index c5ba83e..5a8ce5b 100644
--- a/cmds/dumpstate/DumpstateUtil.h
+++ b/cmds/dumpstate/DumpstateUtil.h
@@ -13,13 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#ifndef FRAMEWORK_NATIVE_CMD_DUMPSTATE_UTIL_H_
-#define FRAMEWORK_NATIVE_CMD_DUMPSTATE_UTIL_H_
+#ifndef ANDROID_OS_DUMPSTATE_UTIL_H_
+#define ANDROID_OS_DUMPSTATE_UTIL_H_
#include <cstdint>
#include <string>
-// TODO: use android::os::dumpstate (must wait until device code is refactored)
+namespace android {
+namespace os {
+namespace dumpstate {
/*
* Defines the Linux account that should be executing a command.
@@ -120,9 +122,6 @@
// Common options.
static CommandOptions DEFAULT;
static CommandOptions AS_ROOT;
-
- // TODO: temporary, until device implementations use AS_ROOT
- static CommandOptions AS_ROOT_5;
};
/*
@@ -180,4 +179,8 @@
*/
int GetPidByName(const std::string& ps_name);
-#endif // FRAMEWORK_NATIVE_CMD_DUMPSTATE_UTIL_H_
+} // namespace dumpstate
+} // namespace os
+} // namespace android
+
+#endif // ANDROID_OS_DUMPSTATE_UTIL_H_
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index b6ea8a3..ed29e07 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -57,6 +57,12 @@
using ::android::hardware::vibrator::V1_0::IVibrator;
using VibratorStatus = ::android::hardware::vibrator::V1_0::Status;
+// TODO: remove once moved to namespace
+using android::os::dumpstate::CommandOptions;
+using android::os::dumpstate::DumpFileToFd;
+using android::os::dumpstate::PropertiesHelper;
+using android::os::dumpstate::GetPidByName;
+
/* read before root is shed */
static char cmdline_buf[16384] = "(unknown)";
static const char *dump_traces_path = NULL;
@@ -107,6 +113,9 @@
// Relative directory (inside the zip) for all files copied as-is into the bugreport.
static const std::string ZIP_ROOT_DIR = "FS";
+// Must be hardcoded because dumpstate HAL implementation need SELinux access to it
+static const std::string kDumpstateBoardPath = "/bugreports/dumpstate_board.txt";
+
static constexpr char PROPERTY_EXTRA_OPTIONS[] = "dumpstate.options";
static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id";
static constexpr char PROPERTY_VERSION[] = "dumpstate.version";
@@ -1026,11 +1035,11 @@
CommandOptions::WithTimeout(20).Build());
#ifdef FWDUMP_bcmdhd
- RunCommand("ND OFFLOAD TABLE", {WLUTIL, "nd_hostip"}, CommandOptions::AS_ROOT_5);
+ RunCommand("ND OFFLOAD TABLE", {WLUTIL, "nd_hostip"}, CommandOptions::AS_ROOT);
RunCommand("DUMP WIFI INTERNAL COUNTERS (1)", {WLUTIL, "counters"}, AS_ROOT_20);
- RunCommand("ND OFFLOAD STATUS (1)", {WLUTIL, "nd_status"}, CommandOptions::AS_ROOT_5);
+ RunCommand("ND OFFLOAD STATUS (1)", {WLUTIL, "nd_status"}, CommandOptions::AS_ROOT);
#endif
DumpFile("INTERRUPTS (1)", "/proc/interrupts");
@@ -1043,7 +1052,7 @@
RunCommand("DUMP WIFI INTERNAL COUNTERS (2)", {WLUTIL, "counters"}, AS_ROOT_20);
- RunCommand("ND OFFLOAD STATUS (2)", {WLUTIL, "nd_status"}, CommandOptions::AS_ROOT_5);
+ RunCommand("ND OFFLOAD STATUS (2)", {WLUTIL, "nd_status"}, CommandOptions::AS_ROOT);
#endif
DumpFile("INTERRUPTS (2)", "/proc/interrupts");
@@ -1080,7 +1089,7 @@
ds.DumpstateBoard();
- /* Migrate the ril_dumpstate to a dumpstate_board()? */
+ /* Migrate the ril_dumpstate to a device specific dumpstate? */
int rilDumpstateTimeout = android::base::GetIntProperty("ril.dumpstate.timeout", 0);
if (rilDumpstateTimeout > 0) {
// su does not exist on user builds, so try running without it.
@@ -1149,21 +1158,18 @@
printf("== Board\n");
printf("========================================================\n");
- ::android::sp<IDumpstateDevice> dumpstate_device(
- IDumpstateDevice::getService("DumpstateDevice"));
+ ::android::sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService("dumpstate"));
if (dumpstate_device == nullptr) {
- // TODO: temporary workaround until devices on master implement it
- MYLOGE("no IDumpstateDevice implementation; using legacy dumpstate_board()\n");
- dumpstate_board();
+ MYLOGE("No IDumpstateDevice implementation\n");
return;
}
if (!IsZipping()) {
- MYLOGE("Not dumping board info because it's not a zipped bugreport\n");
+ MYLOGD("Not dumping board info because it's not a zipped bugreport\n");
return;
}
- std::string path = ds.GetPath("-dumpstate-board.txt");
+ std::string path = kDumpstateBoardPath;
MYLOGI("Calling IDumpstateDevice implementation using path %s\n", path.c_str());
int fd =
@@ -1182,7 +1188,13 @@
handle->data[0] = fd;
// TODO: need a timeout mechanism so dumpstate does not hang on device implementation call.
- dumpstate_device->dumpstateBoard(handle);
+ android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle);
+ if (!status.isOk()) {
+ MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
+ native_handle_close(handle);
+ native_handle_delete(handle);
+ return;
+ }
AddZipEntry("dumpstate-board.txt", path);
printf("*** See dumpstate-board.txt entry ***\n");
@@ -1493,7 +1505,10 @@
if (is_redirecting) {
ds.bugreport_dir_ = dirname(use_outfile);
- ds.base_name_ = basename(use_outfile);
+ std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
+ std::string device_name = android::base::GetProperty("ro.product.device", "UNKNOWN_DEVICE");
+ ds.base_name_ = android::base::StringPrintf("%s-%s-%s", basename(use_outfile),
+ device_name.c_str(), build_id.c_str());
if (do_add_date) {
char date[80];
strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
@@ -1501,13 +1516,11 @@
} else {
ds.name_ = "undated";
}
- std::string buildId = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
if (telephony_only) {
ds.base_name_ += "-telephony";
}
- ds.base_name_ += "-" + buildId;
if (do_fb) {
ds.screenshot_path_ = ds.GetPath(".png");
}
@@ -1566,7 +1579,7 @@
::android::sp<IVibrator> vibrator = nullptr;
if (do_vibrate) {
- vibrator = IVibrator::getService("vibrator");
+ vibrator = IVibrator::getService();
if (vibrator != nullptr) {
// cancel previous vibration if any
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 2c11c0c..b2cd241 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -36,6 +36,19 @@
// TODO: remove once not used
#define MAX_ARGS_ARRAY_SIZE 1000
+// TODO: move everything under this namespace
+// TODO: and then remove explicitly android::os::dumpstate:: prefixes
+namespace android {
+namespace os {
+namespace dumpstate {
+
+class DumpstateTest;
+class ProgressTest;
+
+} // namespace dumpstate
+} // namespace os
+} // namespace android
+
// TODO: remove once moved to HAL
#ifdef __cplusplus
extern "C" {
@@ -74,8 +87,8 @@
*
*/
class Progress {
- friend class ProgressTest;
- friend class DumpstateTest;
+ friend class android::os::dumpstate::ProgressTest;
+ friend class android::os::dumpstate::DumpstateTest;
public:
/*
@@ -152,13 +165,10 @@
friend class DumpstateTest;
public:
- static CommandOptions DEFAULT_DUMPSYS;
+ static android::os::dumpstate::CommandOptions DEFAULT_DUMPSYS;
static Dumpstate& GetInstance();
- // TODO: temporary function until device code uses PropertiesHelper::IsUserBuild()
- bool IsUserBuild();
-
/* Checkes whether dumpstate is generating a zipped bugreport. */
bool IsZipping() const;
@@ -172,7 +182,8 @@
* |options| optional argument defining the command's behavior.
*/
int RunCommand(const std::string& title, const std::vector<std::string>& fullCommand,
- const CommandOptions& options = CommandOptions::DEFAULT);
+ const android::os::dumpstate::CommandOptions& options =
+ android::os::dumpstate::CommandOptions::DEFAULT);
/*
* Runs `dumpsys` with the given arguments, automatically setting its timeout
@@ -187,7 +198,8 @@
* timeout from `options`)
*/
void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args,
- const CommandOptions& options = DEFAULT_DUMPSYS, long dumpsys_timeout = 0);
+ const android::os::dumpstate::CommandOptions& options = DEFAULT_DUMPSYS,
+ long dumpsys_timeout = 0);
/*
* Prints the contents of a file.
@@ -399,9 +411,6 @@
/* Play a sound via Stagefright */
void play_sound(const char *path);
-/* Implemented by libdumpstate_board to dump board-specific info */
-void dumpstate_board();
-
/* Checks if a given path is a directory. */
bool is_dir(const char* pathname);
diff --git a/cmds/dumpstate/libdumpstate_default.cpp b/cmds/dumpstate/libdumpstate_default.cpp
deleted file mode 100644
index f3997ab..0000000
--- a/cmds/dumpstate/libdumpstate_default.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2013 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 "dumpstate.h"
-
-void dumpstate_board(void)
-{
-}
-
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index 5ca6102..1c19268 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -37,7 +37,9 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
-using namespace android;
+namespace android {
+namespace os {
+namespace dumpstate {
using ::testing::EndsWith;
using ::testing::HasSubstr;
@@ -52,14 +54,6 @@
using ::testing::internal::GetCapturedStderr;
using ::testing::internal::GetCapturedStdout;
-using os::DumpstateService;
-using os::IDumpstateListener;
-using os::IDumpstateToken;
-
-// Not used on test cases yet...
-void dumpstate_board(void) {
-}
-
class DumpstateListenerMock : public IDumpstateListener {
public:
MOCK_METHOD1(onProgressUpdated, binder::Status(int32_t progress));
@@ -1157,3 +1151,7 @@
EXPECT_EQ(-1, FindPidOfProcess("abcdef12345-543"));
EXPECT_THAT(err, StrEq("can't find the pid\n"));
}
+
+} // namespace dumpstate
+} // namespace os
+} // namespace android
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 7ee5959..c6dfa37 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -45,14 +45,19 @@
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
-#include <cutils/debugger.h>
#include <cutils/properties.h>
#include <cutils/sockets.h>
+#include <debuggerd/client.h>
#include <log/log.h>
#include <private/android_filesystem_config.h>
#include "DumpstateInternal.h"
+// TODO: remove once moved to namespace
+using android::os::dumpstate::CommandOptions;
+using android::os::dumpstate::DumpFileToFd;
+using android::os::dumpstate::PropertiesHelper;
+
static const int TRACE_DUMP_TIMEOUT_MS = 10000; // 10 seconds
/* Most simple commands have 10 as timeout, so 5 is a good estimate */
@@ -64,9 +69,6 @@
const CommandOptions& options = CommandOptions::DEFAULT) {
return ds.RunCommand(title, full_command, options);
}
-bool Dumpstate::IsUserBuild() {
- return PropertiesHelper::IsUserBuild();
-}
/* list of native processes to include in the native dumps */
// This matches the /proc/pid/exe link instead of /proc/pid/cmdline.
@@ -862,9 +864,9 @@
}
/* create a new, empty traces.txt file to receive stack dumps */
- int fd = TEMP_FAILURE_RETRY(open(traces_path.c_str(),
- O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW | O_CLOEXEC,
- 0666)); /* -rw-rw-rw- */
+ int fd = TEMP_FAILURE_RETRY(
+ open(traces_path.c_str(), O_CREAT | O_WRONLY | O_APPEND | O_TRUNC | O_NOFOLLOW | O_CLOEXEC,
+ 0666)); /* -rw-rw-rw- */
if (fd < 0) {
MYLOGE("%s: %s\n", traces_path.c_str(), strerror(errno));
return nullptr;
diff --git a/cmds/dumpsys/Android.bp b/cmds/dumpsys/Android.bp
index 3476964..c5ae9d2 100644
--- a/cmds/dumpsys/Android.bp
+++ b/cmds/dumpsys/Android.bp
@@ -15,6 +15,8 @@
"libutils",
"liblog",
"libbinder",
+ "android.hidl.manager@1.0",
+ "libhidlbase"
],
clang: true,
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index f0e7200..860b7b4 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -45,8 +45,7 @@
using android::base::unique_fd;
using android::base::WriteFully;
-static int sort_func(const String16* lhs, const String16* rhs)
-{
+static int sort_func(const String16* lhs, const String16* rhs) {
return lhs->compare(*rhs);
}
@@ -55,10 +54,11 @@
"usage: dumpsys\n"
" To dump all services.\n"
"or:\n"
- " dumpsys [-t TIMEOUT] [--help | -l | --skip SERVICES | SERVICE [ARGS]]\n"
+ " dumpsys [-t TIMEOUT] [--help | --hw | -l | --skip SERVICES | SERVICE [ARGS]]\n"
" --help: shows this help\n"
" -l: only list services, do not dump them\n"
" -t TIMEOUT: TIMEOUT to use in seconds instead of default 10 seconds\n"
+ " --hw: list all hw services running on the device\n"
" --skip SERVICES: dumps all services but SERVICES (comma-separated list)\n"
" SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n");
}
@@ -72,16 +72,42 @@
return false;
}
+static void ListHardwareServices(android::hidl::manager::V1_0::IServiceManager* hm) {
+ using android::hardware::hidl_vec;
+ using android::hardware::hidl_string;
+ using android::hardware::Return;
+ using android::sp;
+
+ if (hm == nullptr) {
+ ALOGE("Unable to get hardware service manager!");
+ aerr << "Failed to get hardware service manager!";
+ return;
+ }
+
+ Return<void> ret = hm->list([](const hidl_vec<hidl_string> ®istered){
+ aout << "Currently running hardware services:" << endl;
+ for (const auto &service : registered) {
+ aout << " " << service << endl;
+ }
+ });
+
+ if (!ret.isOk()) {
+ aerr << "Failed to list hardware services: " << ret.description();
+ }
+}
+
int Dumpsys::main(int argc, char* const argv[]) {
Vector<String16> services;
Vector<String16> args;
Vector<String16> skippedServices;
bool showListOnly = false;
+ bool listHwOnly = false;
bool skipServices = false;
int timeoutArg = 10;
static struct option longOptions[] = {
{"skip", no_argument, 0, 0 },
{"help", no_argument, 0, 0 },
+ {"hw", no_argument, 0, 0 },
{ 0, 0, 0, 0 }
};
@@ -105,6 +131,8 @@
} else if (!strcmp(longOptions[optionIndex].name, "help")) {
usage();
return 0;
+ } else if (!strcmp(longOptions[optionIndex].name, "hw")) {
+ listHwOnly = true;
}
break;
@@ -143,11 +171,17 @@
}
if ((skipServices && skippedServices.empty()) ||
- (showListOnly && (!services.empty() || !skippedServices.empty()))) {
+ (showListOnly && (!services.empty() || !skippedServices.empty())) ||
+ (listHwOnly && (skipServices || services.size() > 0 || showListOnly))) {
usage();
return -1;
}
+ if (listHwOnly) {
+ ListHardwareServices(hm_);
+ return 0;
+ }
+
if (services.empty() || showListOnly) {
// gets all services
services = sm_->listServices();
diff --git a/cmds/dumpsys/dumpsys.h b/cmds/dumpsys/dumpsys.h
index 2534dde..20d515d 100644
--- a/cmds/dumpsys/dumpsys.h
+++ b/cmds/dumpsys/dumpsys.h
@@ -17,18 +17,21 @@
#ifndef FRAMEWORK_NATIVE_CMD_DUMPSYS_H_
#define FRAMEWORK_NATIVE_CMD_DUMPSYS_H_
+#include <android/hidl/manager/1.0/IServiceManager.h>
#include <binder/IServiceManager.h>
namespace android {
class Dumpsys {
public:
- Dumpsys(android::IServiceManager* sm) : sm_(sm) {
+ Dumpsys(android::IServiceManager* sm,
+ android::hidl::manager::V1_0::IServiceManager* hm) : sm_(sm), hm_(hm) {
}
int main(int argc, char* const argv[]);
private:
android::IServiceManager* sm_;
+ android::hidl::manager::V1_0::IServiceManager* hm_;
};
}
diff --git a/cmds/dumpsys/main.cpp b/cmds/dumpsys/main.cpp
index 8ba0eba..b180c98 100644
--- a/cmds/dumpsys/main.cpp
+++ b/cmds/dumpsys/main.cpp
@@ -27,6 +27,7 @@
#include <stdio.h>
using namespace android;
+using HServiceManager = android::hidl::manager::V1_0::IServiceManager;
int main(int argc, char* const argv[]) {
signal(SIGPIPE, SIG_IGN);
@@ -38,6 +39,8 @@
return 20;
}
- Dumpsys dumpsys(sm.get());
+ sp<HServiceManager> hm = HServiceManager::getService("manager");
+
+ Dumpsys dumpsys(sm.get(), hm.get());
return dumpsys.main(argc, argv);
}
diff --git a/cmds/dumpsys/tests/Android.bp b/cmds/dumpsys/tests/Android.bp
index 7698ed5..e00444f 100644
--- a/cmds/dumpsys/tests/Android.bp
+++ b/cmds/dumpsys/tests/Android.bp
@@ -5,8 +5,12 @@
srcs: ["dumpsys_test.cpp"],
shared_libs: [
+ "android.hidl.manager@1.0",
"libbase",
"libbinder",
+ "liblog",
+ "libhidlbase",
+ "libhidltransport",
"libutils",
],
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index a61cb00..a66685d 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -44,6 +44,12 @@
using ::testing::internal::GetCapturedStderr;
using ::testing::internal::GetCapturedStdout;
+using android::hardware::hidl_vec;
+using android::hardware::hidl_string;
+using android::hardware::Void;
+using HServiceManager = android::hidl::manager::V1_0::IServiceManager;
+using IServiceNotification = android::hidl::manager::V1_0::IServiceNotification;
+
class ServiceManagerMock : public IServiceManager {
public:
MOCK_CONST_METHOD1(getService, sp<IBinder>(const String16&));
@@ -55,6 +61,26 @@
MOCK_METHOD0(onAsBinder, IBinder*());
};
+class HardwareServiceManagerMock : public HServiceManager {
+ public:
+ template<typename T>
+ using R = android::hardware::Return<T>; // conflicts with ::testing::Return
+
+ MOCK_METHOD2(get, R<sp<IBase>>(const hidl_string&, const hidl_string&));
+ MOCK_METHOD3(add,
+ R<bool>(const hidl_vec<hidl_string>&,
+ const hidl_string&,
+ const sp<IBase>&));
+ MOCK_METHOD1(list, R<void>(list_cb));
+ MOCK_METHOD2(listByInterface,
+ R<void>(const hidl_string&, listByInterface_cb));
+ MOCK_METHOD3(registerForNotifications,
+ R<bool>(const hidl_string&,
+ const hidl_string&,
+ const sp<IServiceNotification>&));
+
+};
+
class BinderMock : public BBinder {
public:
BinderMock() {
@@ -84,6 +110,26 @@
return MakeAction(new WriteOnFdAction(output));
}
+// gmock black magic to provide a WithArg<0>(List(services)) matcher
+typedef void HardwareListFunction(HServiceManager::list_cb);
+
+class HardwareListAction : public ActionInterface<HardwareListFunction> {
+ public:
+ explicit HardwareListAction(const hidl_vec<hidl_string> &services) : services_(services) {
+ }
+ virtual Result Perform(const ArgumentTuple& args) {
+ auto cb = ::std::tr1::get<0>(args);
+ cb(services_);
+ }
+
+ private:
+ hidl_vec<hidl_string> services_;
+};
+
+Action<HardwareListFunction> HardwareList(const hidl_vec<hidl_string> &services) {
+ return MakeAction(new HardwareListAction(services));
+}
+
// Matcher for args using Android's Vector<String16> format
// TODO: move it to some common testing library
MATCHER_P(AndroidElementsAre, expected, "") {
@@ -121,7 +167,7 @@
class DumpsysTest : public Test {
public:
- DumpsysTest() : sm_(), dump_(&sm_), stdout_(), stderr_() {
+ DumpsysTest() : sm_(), hm_(), dump_(&sm_, &hm_), stdout_(), stderr_() {
}
void ExpectListServices(std::vector<std::string> services) {
@@ -129,9 +175,22 @@
for (auto& service : services) {
services16.add(String16(service.c_str()));
}
+
EXPECT_CALL(sm_, listServices()).WillRepeatedly(Return(services16));
}
+ void ExpectListHardwareServices(std::vector<std::string> services) {
+ hidl_vec<hidl_string> hidl_services;
+ hidl_services.resize(services.size());
+ for (size_t i = 0; i < services.size(); i++) {
+ hidl_services[i] = services[i];
+ }
+
+ EXPECT_CALL(hm_, list(_)).WillRepeatedly(DoAll(
+ WithArg<0>(HardwareList(hidl_services)),
+ Return(Void())));
+ }
+
sp<BinderMock> ExpectCheckService(const char* name, bool running = true) {
sp<BinderMock> binder_mock;
if (running) {
@@ -175,8 +234,10 @@
EXPECT_THAT(status, Eq(0));
}
- void AssertRunningServices(const std::vector<std::string>& services) {
- std::string expected("Currently running services:\n");
+ void AssertRunningServices(const std::vector<std::string>& services,
+ const std::string &message = "Currently running services:") {
+ std::string expected(message);
+ expected.append("\n");
for (const std::string& service : services) {
expected.append(" ").append(service).append("\n");
}
@@ -204,12 +265,21 @@
}
ServiceManagerMock sm_;
+ HardwareServiceManagerMock hm_;
Dumpsys dump_;
private:
std::string stdout_, stderr_;
};
+TEST_F(DumpsysTest, ListHwServices) {
+ ExpectListHardwareServices({"Locksmith", "Valet"});
+
+ CallMain({"--hw"});
+
+ AssertRunningServices({"Locksmith", "Valet"}, "Currently running hardware services:");
+}
+
// Tests 'dumpsys -l' when all services are running
TEST_F(DumpsysTest, ListAllServices) {
ExpectListServices({"Locksmith", "Valet"});
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 93174bf..33db6db 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -6,6 +6,8 @@
"-Werror",
],
srcs: [
+ "CacheItem.cpp",
+ "CacheTracker.cpp",
"InstalldNativeService.cpp",
"dexopt.cpp",
"globals.cpp",
diff --git a/cmds/installd/CacheItem.cpp b/cmds/installd/CacheItem.cpp
new file mode 100644
index 0000000..d1bdded
--- /dev/null
+++ b/cmds/installd/CacheItem.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2017 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 "CacheItem.h"
+
+#include <stdint.h>
+#include <inttypes.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
+#include "utils.h"
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace installd {
+
+CacheItem::CacheItem(const std::shared_ptr<CacheItem>& parent, FTSENT* p) : mParent(parent) {
+ level = p->fts_level;
+ directory = S_ISDIR(p->fts_statp->st_mode);
+ size = p->fts_statp->st_blocks * 512;
+ modified = p->fts_statp->st_mtime;
+ mName = p->fts_path;
+}
+
+CacheItem::~CacheItem() {
+}
+
+std::string CacheItem::toString() {
+ return StringPrintf("%s size=%" PRId64 " mod=%ld", buildPath().c_str(), size, modified);
+}
+
+std::string CacheItem::buildPath() {
+ std::string res = mName;
+ std::shared_ptr<CacheItem> parent = mParent;
+ while (parent) {
+ res.insert(0, parent->mName);
+ parent = parent->mParent;
+ }
+ return res;
+}
+
+int CacheItem::purge() {
+ auto path = buildPath();
+ if (directory) {
+ return delete_dir_contents_and_dir(path, true);
+ } else {
+ int res = unlink(path.c_str());
+ if (res != 0) {
+ PLOG(WARNING) << "Failed to unlink " << path;
+ }
+ return res;
+ }
+}
+
+} // namespace installd
+} // namespace android
diff --git a/cmds/installd/CacheItem.h b/cmds/installd/CacheItem.h
new file mode 100644
index 0000000..bec8bc8
--- /dev/null
+++ b/cmds/installd/CacheItem.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 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_INSTALLD_CACHE_ITEM_H
+#define ANDROID_INSTALLD_CACHE_ITEM_H
+
+#include <memory>
+#include <string>
+
+#include <fts.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <android-base/macros.h>
+
+namespace android {
+namespace installd {
+
+/**
+ * Single cache item that can be purged to free up space. This may be an
+ * isolated file, or an entire directory tree that should be atomically
+ * deleted.
+ */
+class CacheItem {
+public:
+ CacheItem(const std::shared_ptr<CacheItem>& parent, FTSENT* p);
+ ~CacheItem();
+
+ std::string toString();
+ std::string buildPath();
+
+ int purge();
+
+ short level;
+ bool directory;
+ int64_t size;
+ time_t modified;
+
+private:
+ std::shared_ptr<CacheItem> mParent;
+ std::string mName;
+
+ DISALLOW_COPY_AND_ASSIGN(CacheItem);
+};
+
+} // namespace installd
+} // namespace android
+
+#endif // ANDROID_INSTALLD_CACHE_ITEM_H
diff --git a/cmds/installd/CacheTracker.cpp b/cmds/installd/CacheTracker.cpp
new file mode 100644
index 0000000..23c4330
--- /dev/null
+++ b/cmds/installd/CacheTracker.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
+
+#include "CacheTracker.h"
+
+#include <fts.h>
+#include <sys/quota.h>
+#include <utils/Trace.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
+#include "utils.h"
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace installd {
+
+CacheTracker::CacheTracker(userid_t userId, appid_t appId, const std::string& quotaDevice) :
+ cacheUsed(0), cacheQuota(0), mUserId(userId), mAppId(appId), mQuotaDevice(quotaDevice),
+ mItemsLoaded(false) {
+}
+
+CacheTracker::~CacheTracker() {
+}
+
+std::string CacheTracker::toString() {
+ return StringPrintf("UID=%d used=%" PRId64 " quota=%" PRId64 " ratio=%d",
+ multiuser_get_uid(mUserId, mAppId), cacheUsed, cacheQuota, getCacheRatio());
+}
+
+void CacheTracker::addDataPath(const std::string& dataPath) {
+ mDataPaths.push_back(dataPath);
+}
+
+void CacheTracker::loadStats() {
+ int cacheGid = multiuser_get_cache_gid(mUserId, mAppId);
+ if (cacheGid != -1 && !mQuotaDevice.empty()) {
+ ATRACE_BEGIN("loadStats quota");
+ struct dqblk dq;
+ if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), mQuotaDevice.c_str(), cacheGid,
+ reinterpret_cast<char*>(&dq)) != 0) {
+ ATRACE_END();
+ if (errno != ESRCH) {
+ PLOG(ERROR) << "Failed to quotactl " << mQuotaDevice << " for GID " << cacheGid;
+ }
+ } else {
+ cacheUsed = dq.dqb_curspace;
+ ATRACE_END();
+ return;
+ }
+ }
+
+ ATRACE_BEGIN("loadStats tree");
+ cacheUsed = 0;
+ for (auto path : mDataPaths) {
+ auto cachePath = read_path_inode(path, "cache", kXattrInodeCache);
+ auto codeCachePath = read_path_inode(path, "code_cache", kXattrInodeCodeCache);
+ calculate_tree_size(cachePath, &cacheUsed);
+ calculate_tree_size(codeCachePath, &cacheUsed);
+ }
+ ATRACE_END();
+}
+
+void CacheTracker::loadItemsFrom(const std::string& path) {
+ FTS *fts;
+ FTSENT *p;
+ char *argv[] = { (char*) path.c_str(), nullptr };
+ if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_XDEV, NULL))) {
+ PLOG(WARNING) << "Failed to fts_open " << path;
+ return;
+ }
+ // TODO: add support for "user.atomic" and "user.tombstone" xattrs
+ while ((p = fts_read(fts)) != NULL) {
+ switch (p->fts_info) {
+ case FTS_D:
+ // Track the newest mtime of anything inside so we consider
+ // deleting the directory last
+ p->fts_number = p->fts_statp->st_mtime;
+ break;
+ case FTS_DP:
+ p->fts_statp->st_mtime = p->fts_number;
+
+ // Ignore the actual top-level cache directories
+ if (p->fts_level == 0) break;
+ case FTS_DEFAULT:
+ case FTS_F:
+ case FTS_SL:
+ case FTS_SLNONE:
+ // TODO: optimize path memory footprint
+ items.push_back(std::shared_ptr<CacheItem>(new CacheItem(nullptr, p)));
+
+ // Track the newest modified item under this tree
+ p->fts_parent->fts_number =
+ std::max(p->fts_parent->fts_number, p->fts_statp->st_mtime);
+ break;
+ }
+ }
+ fts_close(fts);
+}
+
+void CacheTracker::loadItems() {
+ items.clear();
+
+ ATRACE_BEGIN("loadItems");
+ for (auto path : mDataPaths) {
+ loadItemsFrom(read_path_inode(path, "cache", kXattrInodeCache));
+ loadItemsFrom(read_path_inode(path, "code_cache", kXattrInodeCodeCache));
+ }
+ ATRACE_END();
+
+ ATRACE_BEGIN("sortItems");
+ auto cmp = [](std::shared_ptr<CacheItem> left, std::shared_ptr<CacheItem> right) {
+ // TODO: sort dotfiles last
+ // TODO: sort code_cache last
+ if (left->modified != right->modified) {
+ return (left->modified > right->modified);
+ }
+ if (left->level != right->level) {
+ return (left->level < right->level);
+ }
+ return left->directory;
+ };
+ std::sort(items.begin(), items.end(), cmp);
+ ATRACE_END();
+}
+
+void CacheTracker::ensureItems() {
+ if (mItemsLoaded) {
+ return;
+ } else {
+ loadItems();
+ mItemsLoaded = true;
+ }
+}
+
+int CacheTracker::getCacheRatio() {
+ if (cacheQuota == 0) {
+ return 0;
+ } else {
+ return (cacheUsed * 10000) / cacheQuota;
+ }
+}
+
+} // namespace installd
+} // namespace android
diff --git a/cmds/installd/CacheTracker.h b/cmds/installd/CacheTracker.h
new file mode 100644
index 0000000..91692d7
--- /dev/null
+++ b/cmds/installd/CacheTracker.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 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_INSTALLD_CACHE_TRACKER_H
+#define ANDROID_INSTALLD_CACHE_TRACKER_H
+
+#include <memory>
+#include <string>
+#include <queue>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <android-base/macros.h>
+#include <cutils/multiuser.h>
+
+#include "CacheItem.h"
+
+namespace android {
+namespace installd {
+
+/**
+ * Cache tracker for a single UID. Each tracker is used in two modes: first
+ * for loading lightweight "stats", and then by loading detailed "items"
+ * which can then be purged to free up space.
+ */
+class CacheTracker {
+public:
+ CacheTracker(userid_t userId, appid_t appId, const std::string& quotaDevice);
+ ~CacheTracker();
+
+ std::string toString();
+
+ void addDataPath(const std::string& dataPath);
+
+ void loadStats();
+ void loadItems();
+
+ void ensureItems();
+
+ int getCacheRatio();
+
+ int64_t cacheUsed;
+ int64_t cacheQuota;
+
+ std::vector<std::shared_ptr<CacheItem>> items;
+
+private:
+ userid_t mUserId;
+ appid_t mAppId;
+ std::string mQuotaDevice;
+ bool mItemsLoaded;
+
+ std::vector<std::string> mDataPaths;
+
+ void loadItemsFrom(const std::string& path);
+
+ DISALLOW_COPY_AND_ASSIGN(CacheTracker);
+};
+
+} // namespace installd
+} // namespace android
+
+#endif // ANDROID_INSTALLD_CACHE_TRACKER_H
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index a693737..ede31fc 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -16,6 +16,8 @@
#include "InstalldNativeService.h"
+#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
+
#include <errno.h>
#include <inttypes.h>
#include <fstream>
@@ -46,6 +48,7 @@
#include <private/android_filesystem_config.h>
#include <selinux/android.h>
#include <system/thread_defs.h>
+#include <utils/Trace.h>
#include "dexopt.h"
#include "globals.h"
@@ -53,6 +56,7 @@
#include "otapreopt_utils.h"
#include "utils.h"
+#include "CacheTracker.h"
#include "MatchExtensionGen.h"
#ifndef LOG_TAG
@@ -60,6 +64,7 @@
#endif
using android::base::StringPrintf;
+using std::endl;
namespace android {
namespace installd {
@@ -84,6 +89,8 @@
static constexpr int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
static constexpr int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 9;
static constexpr int FLAG_USE_QUOTA = 1 << 12;
+static constexpr int FLAG_FREE_CACHE_V2 = 1 << 13;
+static constexpr int FLAG_FREE_CACHE_NOOP = 1 << 14;
namespace {
@@ -189,15 +196,29 @@
}
status_t InstalldNativeService::dump(int fd, const Vector<String16> & /* args */) {
+ auto out = std::fstream(StringPrintf("/proc/self/fd/%d", fd));
const binder::Status dump_permission = checkPermission(kDump);
if (!dump_permission.isOk()) {
- const String8 msg(dump_permission.toString8());
- write(fd, msg.string(), msg.size());
+ out << dump_permission.toString8() << endl;
return PERMISSION_DENIED;
}
+ std::lock_guard<std::recursive_mutex> lock(mLock);
- std::string msg = "installd is happy\n";
- write(fd, msg.c_str(), strlen(msg.c_str()));
+ out << "installd is happy!" << endl;
+
+ out << endl << "Devices with quota support:" << endl;
+ for (const auto& n : mQuotaDevices) {
+ out << " " << n.first << " = " << n.second << endl;
+ }
+
+ out << endl << "Per-UID cache quotas:" << endl;
+ for (const auto& n : mCacheQuotas) {
+ out << " " << n.first << " = " << n.second << endl;
+ }
+
+ out << endl;
+ out.flush();
+
return NO_ERROR;
}
@@ -288,12 +309,13 @@
}
}
+ mode_t actual_mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID);
if (st.st_uid != uid) {
// Mismatched UID is real trouble; we can't recover
LOG(ERROR) << "Mismatched UID at " << path << ": found " << st.st_uid
<< " but expected " << uid;
return -1;
- } else if (st.st_gid == gid && st.st_mode == target_mode) {
+ } else if (st.st_gid == gid && actual_mode == target_mode) {
// Everything looks good!
return 0;
}
@@ -337,6 +359,7 @@
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
const char* pkgname = packageName.c_str();
@@ -344,10 +367,15 @@
// Assume invalid inode unless filled in below
if (_aidl_return != nullptr) *_aidl_return = -1;
- uid_t uid = multiuser_get_uid(userId, appId);
- gid_t cacheGid = multiuser_get_cache_gid(userId, appId);
+ int32_t uid = multiuser_get_uid(userId, appId);
+ int32_t cacheGid = multiuser_get_cache_gid(userId, appId);
mode_t targetMode = targetSdkVersion >= MIN_RESTRICTED_HOME_SDK_VERSION ? 0700 : 0751;
+ // If UID doesn't have a specific cache GID, use UID value
+ if (cacheGid == -1) {
+ cacheGid = uid;
+ }
+
if (flags & FLAG_STORAGE_CE) {
auto path = create_data_user_ce_package_path(uuid_, userId, pkgname);
bool existing = (access(path.c_str(), F_OK) == 0);
@@ -423,6 +451,7 @@
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
const char* pkgname = packageName.c_str();
@@ -465,6 +494,7 @@
binder::Status InstalldNativeService::clearAppProfiles(const std::string& packageName) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* pkgname = packageName.c_str();
binder::Status res = ok();
@@ -482,6 +512,7 @@
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
const char* pkgname = packageName.c_str();
@@ -541,6 +572,7 @@
binder::Status InstalldNativeService::destroyAppProfiles(const std::string& packageName) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* pkgname = packageName.c_str();
binder::Status res = ok();
@@ -561,6 +593,7 @@
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
const char* pkgname = packageName.c_str();
@@ -594,6 +627,7 @@
CHECK_ARGUMENT_UUID(fromUuid);
CHECK_ARGUMENT_UUID(toUuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* from_uuid = fromUuid ? fromUuid->c_str() : nullptr;
const char* to_uuid = toUuid ? toUuid->c_str() : nullptr;
@@ -728,6 +762,7 @@
int32_t userId, int32_t userSerial ATTRIBUTE_UNUSED, int32_t flags) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
if (flags & FLAG_STORAGE_DE) {
@@ -744,6 +779,7 @@
int32_t userId, int32_t flags) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
binder::Status res = ok();
@@ -784,51 +820,172 @@
* when just reading from the cache, which is pretty awful.
*/
binder::Status InstalldNativeService::freeCache(const std::unique_ptr<std::string>& uuid,
- int64_t freeStorageSize) {
+ int64_t freeStorageSize, int32_t flags) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ // TODO: remove this once framework is more robust
+ invalidateMounts();
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
- cache_t* cache;
- int64_t avail;
-
auto data_path = create_data_path(uuid_);
+ auto device = findQuotaDeviceForUuid(uuid);
+ auto noop = (flags & FLAG_FREE_CACHE_NOOP);
- avail = data_disk_free(data_path);
- if (avail < 0) {
+ int64_t free = data_disk_free(data_path);
+ int64_t needed = freeStorageSize - free;
+ if (free < 0) {
return error("Failed to determine free space for " + data_path);
- }
-
- ALOGI("free_cache(%" PRId64 ") avail %" PRId64 "\n", freeStorageSize, avail);
- if (avail >= freeStorageSize) {
+ } else if (free >= freeStorageSize) {
return ok();
}
- cache = start_cache_collection();
+ LOG(DEBUG) << "Found " << data_path << " with " << free << " free; caller requested "
+ << freeStorageSize;
- auto users = get_known_users(uuid_);
- for (auto user : users) {
- add_cache_files(cache, create_data_user_ce_path(uuid_, user));
- add_cache_files(cache, create_data_user_de_path(uuid_, user));
- add_cache_files(cache,
- StringPrintf("%s/Android/data", create_data_media_path(uuid_, user).c_str()));
+ if (flags & FLAG_FREE_CACHE_V2) {
+ // This new cache strategy fairly removes files from UIDs by deleting
+ // files from the UIDs which are most over their allocated quota
+
+ // 1. Create trackers for every known UID
+ ATRACE_BEGIN("create");
+ std::unordered_map<uid_t, std::shared_ptr<CacheTracker>> trackers;
+ for (auto user : get_known_users(uuid_)) {
+ FTS *fts;
+ FTSENT *p;
+ char *argv[] = {
+ (char*) create_data_user_ce_path(uuid_, user).c_str(),
+ (char*) create_data_user_de_path(uuid_, user).c_str(),
+ nullptr
+ };
+ if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_XDEV, NULL))) {
+ return error("Failed to fts_open");
+ }
+ while ((p = fts_read(fts)) != NULL) {
+ if (p->fts_info == FTS_D && p->fts_level == 1) {
+ uid_t uid = p->fts_statp->st_uid;
+ auto search = trackers.find(uid);
+ if (search != trackers.end()) {
+ search->second->addDataPath(p->fts_path);
+ } else {
+ auto tracker = std::shared_ptr<CacheTracker>(new CacheTracker(
+ multiuser_get_user_id(uid), multiuser_get_app_id(uid), device));
+ tracker->addDataPath(p->fts_path);
+ tracker->cacheQuota = mCacheQuotas[uid];
+ if (tracker->cacheQuota == 0) {
+ LOG(WARNING) << "UID " << uid << " has no cache quota; assuming 64MB";
+ tracker->cacheQuota = 67108864;
+ }
+ trackers[uid] = tracker;
+ }
+ fts_set(fts, p, FTS_SKIP);
+ }
+ }
+ fts_close(fts);
+ }
+ ATRACE_END();
+
+ // 2. Populate tracker stats and insert into priority queue
+ ATRACE_BEGIN("populate");
+ auto cmp = [](std::shared_ptr<CacheTracker> left, std::shared_ptr<CacheTracker> right) {
+ return (left->getCacheRatio() < right->getCacheRatio());
+ };
+ std::priority_queue<std::shared_ptr<CacheTracker>,
+ std::vector<std::shared_ptr<CacheTracker>>, decltype(cmp)> queue(cmp);
+ for (const auto& it : trackers) {
+ it.second->loadStats();
+ queue.push(it.second);
+ }
+ ATRACE_END();
+
+ // 3. Bounce across the queue, freeing items from whichever tracker is
+ // the most over their assigned quota
+ ATRACE_BEGIN("bounce");
+ std::shared_ptr<CacheTracker> active;
+ while (active || !queue.empty()) {
+ // Find the best tracker to work with; this might involve swapping
+ // if the active tracker is no longer the most over quota
+ bool nextBetter = active && !queue.empty()
+ && active->getCacheRatio() < queue.top()->getCacheRatio();
+ if (!active || nextBetter) {
+ if (active) {
+ // Current tracker still has items, so we'll consider it
+ // again later once it bubbles up to surface
+ queue.push(active);
+ }
+ active = queue.top(); queue.pop();
+ active->ensureItems();
+ continue;
+ }
+
+ // If no items remain, go find another tracker
+ if (active->items.empty()) {
+ active = nullptr;
+ continue;
+ } else {
+ auto item = active->items.back();
+ active->items.pop_back();
+
+ LOG(DEBUG) << "Purging " << item->toString() << " from " << active->toString();
+ if (!noop) {
+ item->purge();
+ }
+ active->cacheUsed -= item->size;
+ needed -= item->size;
+ }
+
+ // Verify that we're actually done before bailing, since sneaky
+ // apps might be using hardlinks
+ if (needed <= 0) {
+ free = data_disk_free(data_path);
+ needed = freeStorageSize - free;
+ if (needed <= 0) {
+ break;
+ } else {
+ LOG(WARNING) << "Expected to be done but still need " << needed;
+ }
+ }
+ }
+ ATRACE_END();
+
+ } else {
+ ATRACE_BEGIN("start");
+ cache_t* cache = start_cache_collection();
+ ATRACE_END();
+
+ ATRACE_BEGIN("add");
+ for (auto user : get_known_users(uuid_)) {
+ add_cache_files(cache, create_data_user_ce_path(uuid_, user));
+ add_cache_files(cache, create_data_user_de_path(uuid_, user));
+ add_cache_files(cache,
+ StringPrintf("%s/Android/data", create_data_media_path(uuid_, user).c_str()));
+ }
+ ATRACE_END();
+
+ ATRACE_BEGIN("clear");
+ clear_cache_files(data_path, cache, freeStorageSize);
+ ATRACE_END();
+
+ ATRACE_BEGIN("finish");
+ finish_cache_collection(cache);
+ ATRACE_END();
}
- clear_cache_files(data_path, cache, freeStorageSize);
- finish_cache_collection(cache);
-
- avail = data_disk_free(data_path);
- if (avail >= freeStorageSize) {
+ free = data_disk_free(data_path);
+ if (free >= freeStorageSize) {
return ok();
} else {
return error(StringPrintf("Failed to free up %" PRId64 " on %s; final free space %" PRId64,
- freeStorageSize, data_path.c_str(), avail));
+ freeStorageSize, data_path.c_str(), free));
}
}
binder::Status InstalldNativeService::rmdex(const std::string& codePath,
const std::string& instructionSet) {
ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
char dex_path[PKG_PATH_MAX];
const char* path = codePath.c_str();
@@ -871,30 +1028,8 @@
}
#endif
-static std::string findDeviceForUuid(const std::unique_ptr<std::string>& uuid) {
- auto path = create_data_path(uuid ? uuid->c_str() : nullptr);
- std::ifstream in("/proc/mounts");
- if (!in.is_open()) {
- PLOG(ERROR) << "Failed to read mounts";
- return "";
- }
- std::string source;
- std::string target;
- while (!in.eof()) {
- std::getline(in, source, ' ');
- std::getline(in, target, ' ');
- if (target == path) {
- return source;
- }
- // Skip to next line
- std::getline(in, source);
- }
- PLOG(ERROR) << "Failed to resolve block device for " << path;
- return "";
-}
-
static void collectQuotaStats(const std::string& device, int32_t userId,
- int32_t appId, struct stats* stats, struct stats* extStats ATTRIBUTE_UNUSED) {
+ int32_t appId, struct stats* stats, struct stats* extStats) {
if (device.empty()) return;
struct dqblk dq;
@@ -921,13 +1056,28 @@
}
} else {
#if MEASURE_DEBUG
- LOG(DEBUG) << "quotactl() for GID " << cacheGid << " " << dq.dqb_curspace;
+ LOG(DEBUG) << "quotactl() for GID " << cacheGid << " " << dq.dqb_curspace;
#endif
stats->cacheSize += dq.dqb_curspace;
}
}
- int sharedGid = multiuser_get_shared_app_gid(uid);
+ int extGid = multiuser_get_ext_gid(userId, appId);
+ if (extGid != -1) {
+ if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), extGid,
+ reinterpret_cast<char*>(&dq)) != 0) {
+ if (errno != ESRCH) {
+ PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << extGid;
+ }
+ } else {
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "quotactl() for GID " << extGid << " " << dq.dqb_curspace;
+#endif
+ extStats->dataSize += dq.dqb_curspace;
+ }
+ }
+
+ int sharedGid = multiuser_get_shared_gid(userId, appId);
if (sharedGid != -1) {
if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), sharedGid,
reinterpret_cast<char*>(&dq)) != 0) {
@@ -936,20 +1086,11 @@
}
} else {
#if MEASURE_DEBUG
- LOG(DEBUG) << "quotactl() for GID " << sharedGid << " " << dq.dqb_curspace;
+ LOG(DEBUG) << "quotactl() for GID " << sharedGid << " " << dq.dqb_curspace;
#endif
stats->codeSize += dq.dqb_curspace;
}
}
-
-#if MEASURE_EXTERNAL
- // TODO: measure using external GIDs
-#endif
-}
-
-static void collectQuotaStats(const std::unique_ptr<std::string>& uuid, int32_t userId,
- int32_t appId, struct stats* stats, struct stats* extStats) {
- collectQuotaStats(findDeviceForUuid(uuid), userId, appId, stats, extStats);
}
static void collectManualStats(const std::string& path, struct stats* stats) {
@@ -1035,6 +1176,40 @@
closedir(d);
}
+static void collectManualExternalStatsForUser(const std::string& path, struct stats* stats) {
+ FTS *fts;
+ FTSENT *p;
+ char *argv[] = { (char*) path.c_str(), nullptr };
+ if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_XDEV, NULL))) {
+ PLOG(ERROR) << "Failed to fts_open " << path;
+ return;
+ }
+ while ((p = fts_read(fts)) != NULL) {
+ switch (p->fts_info) {
+ case FTS_D:
+ if (p->fts_level == 4
+ && !strcmp(p->fts_name, "cache")
+ && !strcmp(p->fts_parent->fts_parent->fts_name, "data")
+ && !strcmp(p->fts_parent->fts_parent->fts_parent->fts_name, "Android")) {
+ p->fts_number = 1;
+ }
+ p->fts_number = p->fts_parent->fts_number;
+ // Fall through to count the directory
+ case FTS_DEFAULT:
+ case FTS_F:
+ case FTS_SL:
+ case FTS_SLNONE:
+ int64_t size = (p->fts_statp->st_blocks * 512);
+ if (p->fts_number == 1) {
+ stats->cacheSize += size;
+ }
+ stats->dataSize += size;
+ break;
+ }
+ }
+ fts_close(fts);
+}
+
binder::Status InstalldNativeService::getAppSize(const std::unique_ptr<std::string>& uuid,
const std::vector<std::string>& packageNames, int32_t userId, int32_t flags,
int32_t appId, const std::vector<int64_t>& ceDataInodes,
@@ -1044,6 +1219,7 @@
for (auto packageName : packageNames) {
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
}
+ std::lock_guard<std::recursive_mutex> lock(mLock);
// When modifying this logic, always verify using tests:
// runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java -m testGetAppSize
@@ -1072,56 +1248,71 @@
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+ auto device = findQuotaDeviceForUuid(uuid);
+ if (device.empty()) {
+ flags &= ~FLAG_USE_QUOTA;
+ }
+
+ ATRACE_BEGIN("obb");
for (auto packageName : packageNames) {
auto obbCodePath = create_data_media_obb_path(uuid_, packageName.c_str());
calculate_tree_size(obbCodePath, &extStats.codeSize);
}
+ ATRACE_END();
if (flags & FLAG_USE_QUOTA && appId >= AID_APP_START) {
+ ATRACE_BEGIN("code");
for (auto codePath : codePaths) {
calculate_tree_size(codePath, &stats.codeSize, -1,
multiuser_get_shared_gid(userId, appId));
}
+ ATRACE_END();
- collectQuotaStats(uuid, userId, appId, &stats, &extStats);
+ ATRACE_BEGIN("quota");
+ collectQuotaStats(device, userId, appId, &stats, &extStats);
+ ATRACE_END();
} else {
+ ATRACE_BEGIN("code");
for (auto codePath : codePaths) {
calculate_tree_size(codePath, &stats.codeSize);
}
+ ATRACE_END();
for (size_t i = 0; i < packageNames.size(); i++) {
const char* pkgname = packageNames[i].c_str();
+ ATRACE_BEGIN("data");
auto cePath = create_data_user_ce_package_path(uuid_, userId, pkgname, ceDataInodes[i]);
collectManualStats(cePath, &stats);
-
auto dePath = create_data_user_de_package_path(uuid_, userId, pkgname);
collectManualStats(dePath, &stats);
+ ATRACE_END();
+ ATRACE_BEGIN("profiles");
auto userProfilePath = create_data_user_profile_package_path(userId, pkgname);
calculate_tree_size(userProfilePath, &stats.dataSize);
-
auto refProfilePath = create_data_ref_profile_package_path(pkgname);
calculate_tree_size(refProfilePath, &stats.codeSize);
+ ATRACE_END();
-#if MEASURE_EXTERNAL
+ ATRACE_BEGIN("external");
auto extPath = create_data_media_package_path(uuid_, userId, pkgname, "data");
collectManualStats(extPath, &extStats);
-
auto mediaPath = create_data_media_package_path(uuid_, userId, pkgname, "media");
calculate_tree_size(mediaPath, &extStats.dataSize);
-#endif
+ ATRACE_END();
}
+ ATRACE_BEGIN("dalvik");
int32_t sharedGid = multiuser_get_shared_gid(userId, appId);
if (sharedGid != -1) {
calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize,
sharedGid, -1);
}
-
calculate_tree_size(create_data_misc_foreign_dex_path(userId), &stats.dataSize,
multiuser_get_uid(userId, appId), -1);
+ ATRACE_END();
}
std::vector<int64_t> ret;
@@ -1143,6 +1334,7 @@
std::vector<int64_t>* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
// When modifying this logic, always verify using tests:
// runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java -m testGetUserSize
@@ -1158,35 +1350,69 @@
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
- auto obbPath = create_data_path(uuid_) + "/media/obb";
- calculate_tree_size(obbPath, &extStats.codeSize);
+ auto device = findQuotaDeviceForUuid(uuid);
+ if (device.empty()) {
+ flags &= ~FLAG_USE_QUOTA;
+ }
if (flags & FLAG_USE_QUOTA) {
- calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize, -1, -1, true);
+ struct dqblk dq;
+ ATRACE_BEGIN("obb");
+ if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), AID_MEDIA_OBB,
+ reinterpret_cast<char*>(&dq)) != 0) {
+ if (errno != ESRCH) {
+ PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << AID_MEDIA_OBB;
+ }
+ } else {
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "quotactl() for GID " << AID_MEDIA_OBB << " " << dq.dqb_curspace;
+#endif
+ extStats.codeSize += dq.dqb_curspace;
+ }
+ ATRACE_END();
+
+ ATRACE_BEGIN("code");
+ calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize, -1, -1, true);
+ ATRACE_END();
+
+ ATRACE_BEGIN("data");
auto cePath = create_data_user_ce_path(uuid_, userId);
collectManualStatsForUser(cePath, &stats, true);
-
auto dePath = create_data_user_de_path(uuid_, userId);
collectManualStatsForUser(dePath, &stats, true);
+ ATRACE_END();
+ ATRACE_BEGIN("profile");
auto userProfilePath = create_data_user_profile_path(userId);
calculate_tree_size(userProfilePath, &stats.dataSize, -1, -1, true);
-
auto refProfilePath = create_data_ref_profile_path();
calculate_tree_size(refProfilePath, &stats.codeSize, -1, -1, true);
+ ATRACE_END();
-#if MEASURE_EXTERNAL
- // TODO: measure external storage paths
+ ATRACE_BEGIN("external");
+ uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW);
+ if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
+ reinterpret_cast<char*>(&dq)) != 0) {
+ if (errno != ESRCH) {
+ PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
+ }
+ } else {
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
#endif
+ extStats.dataSize += dq.dqb_curspace;
+ }
+ ATRACE_END();
+ ATRACE_BEGIN("dalvik");
calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize,
-1, -1, true);
-
calculate_tree_size(create_data_misc_foreign_dex_path(userId), &stats.dataSize,
-1, -1, true);
+ ATRACE_END();
- auto device = findDeviceForUuid(uuid);
+ ATRACE_BEGIN("quota");
for (auto appId : appIds) {
if (appId >= AID_APP_START) {
collectQuotaStats(device, userId, appId, &stats, &extStats);
@@ -1196,28 +1422,44 @@
#endif
}
}
+ ATRACE_END();
} else {
- calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize);
+ ATRACE_BEGIN("obb");
+ auto obbPath = create_data_path(uuid_) + "/media/obb";
+ calculate_tree_size(obbPath, &extStats.codeSize);
+ ATRACE_END();
+ ATRACE_BEGIN("code");
+ calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize);
+ ATRACE_END();
+
+ ATRACE_BEGIN("data");
auto cePath = create_data_user_ce_path(uuid_, userId);
collectManualStatsForUser(cePath, &stats);
-
auto dePath = create_data_user_de_path(uuid_, userId);
collectManualStatsForUser(dePath, &stats);
+ ATRACE_END();
+ ATRACE_BEGIN("profile");
auto userProfilePath = create_data_user_profile_path(userId);
calculate_tree_size(userProfilePath, &stats.dataSize);
-
auto refProfilePath = create_data_ref_profile_path();
calculate_tree_size(refProfilePath, &stats.codeSize);
+ ATRACE_END();
-#if MEASURE_EXTERNAL
- // TODO: measure external storage paths
+ ATRACE_BEGIN("external");
+ auto dataMediaPath = create_data_media_path(uuid_, userId);
+ collectManualExternalStatsForUser(dataMediaPath, &extStats);
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "Measured external data " << extStats.dataSize << " cache "
+ << extStats.cacheSize;
#endif
+ ATRACE_END();
+ ATRACE_BEGIN("dalvik");
calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize);
-
calculate_tree_size(create_data_misc_foreign_dex_path(userId), &stats.dataSize);
+ ATRACE_END();
}
std::vector<int64_t> ret;
@@ -1238,6 +1480,7 @@
int32_t userId, int32_t flags, std::vector<int64_t>* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
// When modifying this logic, always verify using tests:
// runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java -m testGetExternalSize
@@ -1253,11 +1496,14 @@
int64_t videoSize = 0;
int64_t imageSize = 0;
+ auto device = findQuotaDeviceForUuid(uuid);
+ if (device.empty()) {
+ flags &= ~FLAG_USE_QUOTA;
+ }
+
if (flags & FLAG_USE_QUOTA) {
struct dqblk dq;
- auto device = findDeviceForUuid(uuid);
-
uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW);
if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
reinterpret_cast<char*>(&dq)) != 0) {
@@ -1343,12 +1589,25 @@
return ok();
}
+binder::Status InstalldNativeService::setAppQuota(const std::unique_ptr<std::string>& uuid,
+ int32_t userId, int32_t appId, int64_t cacheQuota) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ int32_t uid = multiuser_get_uid(userId, appId);
+ mCacheQuotas[uid] = cacheQuota;
+
+ return ok();
+}
+
// Dumps the contents of a profile file, using pkgname's dex files for pretty
// printing the result.
binder::Status InstalldNativeService::dumpProfiles(int32_t uid, const std::string& packageName,
const std::string& codePaths, bool* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* pkgname = packageName.c_str();
const char* code_paths = codePaths.c_str();
@@ -1362,6 +1621,7 @@
bool* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* pkgname = packageName.c_str();
*_aidl_return = analyse_profiles(uid, pkgname);
@@ -1378,6 +1638,7 @@
if (packageName && *packageName != "*") {
CHECK_ARGUMENT_PACKAGE_NAME(*packageName);
}
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* apk_path = apkPath.c_str();
const char* pkgname = packageName ? packageName->c_str() : "*";
@@ -1394,6 +1655,8 @@
binder::Status InstalldNativeService::markBootComplete(const std::string& instructionSet) {
ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
const char* instruction_set = instructionSet.c_str();
char boot_marker_path[PKG_PATH_MAX];
@@ -1437,6 +1700,7 @@
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
const char* pkgname = packageName.c_str();
@@ -1559,6 +1823,8 @@
binder::Status InstalldNativeService::idmap(const std::string& targetApkPath,
const std::string& overlayApkPath, int32_t uid) {
ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
const char* target_apk = targetApkPath.c_str();
const char* overlay_apk = overlayApkPath.c_str();
ALOGV("idmap target_apk=%s overlay_apk=%s uid=%d\n", target_apk, overlay_apk, uid);
@@ -1630,6 +1896,7 @@
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
binder::Status res = ok();
@@ -1658,6 +1925,8 @@
binder::Status InstalldNativeService::createOatDir(const std::string& oatDir,
const std::string& instructionSet) {
ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
const char* oat_dir = oatDir.c_str();
const char* instruction_set = instructionSet.c_str();
char oat_instr_dir[PKG_PATH_MAX];
@@ -1680,6 +1949,8 @@
binder::Status InstalldNativeService::rmPackageDir(const std::string& packageDir) {
ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
if (validate_apk_path(packageDir.c_str())) {
return error("Invalid path " + packageDir);
}
@@ -1692,6 +1963,8 @@
binder::Status InstalldNativeService::linkFile(const std::string& relativePath,
const std::string& fromBase, const std::string& toBase) {
ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
const char* relative_path = relativePath.c_str();
const char* from_base = fromBase.c_str();
const char* to_base = toBase.c_str();
@@ -1718,6 +1991,7 @@
binder::Status InstalldNativeService::moveAb(const std::string& apkPath,
const std::string& instructionSet, const std::string& outputPath) {
ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* apk_path = apkPath.c_str();
const char* instruction_set = instructionSet.c_str();
@@ -1730,6 +2004,7 @@
binder::Status InstalldNativeService::deleteOdex(const std::string& apkPath,
const std::string& instructionSet, const std::string& outputPath) {
ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* apk_path = apkPath.c_str();
const char* instruction_set = instructionSet.c_str();
@@ -1739,5 +2014,42 @@
return res ? ok() : error();
}
+binder::Status InstalldNativeService::invalidateMounts() {
+ ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ mQuotaDevices.clear();
+
+ std::ifstream in("/proc/mounts");
+ if (!in.is_open()) {
+ return error("Failed to read mounts");
+ }
+
+ std::string source;
+ std::string target;
+ std::string ignored;
+ struct dqblk dq;
+ while (!in.eof()) {
+ std::getline(in, source, ' ');
+ std::getline(in, target, ' ');
+ std::getline(in, ignored);
+
+ if (source.compare(0, 11, "/dev/block/") == 0) {
+ if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0,
+ reinterpret_cast<char*>(&dq)) == 0) {
+ LOG(DEBUG) << "Found " << source << " with quota";
+ mQuotaDevices[target] = source;
+ }
+ }
+ }
+ return ok();
+}
+
+std::string InstalldNativeService::findQuotaDeviceForUuid(
+ const std::unique_ptr<std::string>& uuid) {
+ auto path = create_data_path(uuid ? uuid->c_str() : nullptr);
+ return mQuotaDevices[path];
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 5397a74..0a9f12f 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -22,7 +22,9 @@
#include <unistd.h>
#include <vector>
+#include <unordered_map>
+#include <android-base/macros.h>
#include <binder/BinderService.h>
#include <cutils/multiuser.h>
@@ -66,6 +68,9 @@
binder::Status getExternalSize(const std::unique_ptr<std::string>& uuid,
int32_t userId, int32_t flags, std::vector<int64_t>* _aidl_return);
+ binder::Status setAppQuota(const std::unique_ptr<std::string>& uuid,
+ int32_t userId, int32_t appId, int64_t cacheQuota);
+
binder::Status moveCompleteApp(const std::unique_ptr<std::string>& fromUuid,
const std::unique_ptr<std::string>& toUuid, const std::string& packageName,
const std::string& dataAppName, int32_t appId, const std::string& seInfo,
@@ -89,7 +94,8 @@
int32_t uid);
binder::Status rmPackageDir(const std::string& packageDir);
binder::Status markBootComplete(const std::string& instructionSet);
- binder::Status freeCache(const std::unique_ptr<std::string>& uuid, int64_t freeStorageSize);
+ binder::Status freeCache(const std::unique_ptr<std::string>& uuid, int64_t freeStorageSize,
+ int32_t flags);
binder::Status linkNativeLibraryDirectory(const std::unique_ptr<std::string>& uuid,
const std::string& packageName, const std::string& nativeLibPath32, int32_t userId);
binder::Status createOatDir(const std::string& oatDir, const std::string& instructionSet);
@@ -99,6 +105,18 @@
const std::string& outputPath);
binder::Status deleteOdex(const std::string& apkPath, const std::string& instructionSet,
const std::string& outputPath);
+
+ binder::Status invalidateMounts();
+
+private:
+ std::recursive_mutex mLock;
+
+ /* Map from mount point to underlying device node */
+ std::unordered_map<std::string, std::string> mQuotaDevices;
+ /* Map from UID to cache quota size */
+ std::unordered_map<uid_t, int64_t> mCacheQuotas;
+
+ std::string findQuotaDeviceForUuid(const std::unique_ptr<std::string>& uuid);
};
} // namespace installd
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 6e4d7fa..aa5e4f2 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -38,6 +38,8 @@
long[] getUserSize(@nullable @utf8InCpp String uuid, int userId, int flags, in int[] appIds);
long[] getExternalSize(@nullable @utf8InCpp String uuid, int userId, int flags);
+ void setAppQuota(@nullable @utf8InCpp String uuid, int userId, int appId, long cacheQuota);
+
void moveCompleteApp(@nullable @utf8InCpp String fromUuid, @nullable @utf8InCpp String toUuid,
@utf8InCpp String packageName, @utf8InCpp String dataAppName, int appId,
@utf8InCpp String seInfo, int targetSdkVersion);
@@ -58,7 +60,7 @@
void idmap(@utf8InCpp String targetApkPath, @utf8InCpp String overlayApkPath, int uid);
void rmPackageDir(@utf8InCpp String packageDir);
void markBootComplete(@utf8InCpp String instructionSet);
- void freeCache(@nullable @utf8InCpp String uuid, long freeStorageSize);
+ void freeCache(@nullable @utf8InCpp String uuid, long freeStorageSize, int flags);
void linkNativeLibraryDirectory(@nullable @utf8InCpp String uuid,
@utf8InCpp String packageName, @utf8InCpp String nativeLibPath32, int userId);
void createOatDir(@utf8InCpp String oatDir, @utf8InCpp String instructionSet);
@@ -68,4 +70,6 @@
@utf8InCpp String outputPath);
void deleteOdex(@utf8InCpp String apkPath, @utf8InCpp String instructionSet,
@utf8InCpp String outputPath);
+
+ void invalidateMounts();
}
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 76d5695..1565d0d 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -904,7 +904,7 @@
//
// Usage example:
//
-// Dex2oatFileWrapper<std::function<void ()>> file(open(...),
+// Dex2oatFileWrapper file(open(...),
// [name]() {
// unlink(name.c_str());
// });
@@ -927,14 +927,30 @@
// // At this point, when the Dex2oatFileWrapper is destructed, the cleanup function will not run
// // (leaving the file around; after the fd is closed).
//
-template <typename Cleanup>
class Dex2oatFileWrapper {
public:
- Dex2oatFileWrapper() : value_(-1), cleanup_(), do_cleanup_(true) {
+ Dex2oatFileWrapper() : value_(-1), cleanup_(), do_cleanup_(true), auto_close_(true) {
}
- Dex2oatFileWrapper(int value, Cleanup cleanup)
- : value_(value), cleanup_(cleanup), do_cleanup_(true) {}
+ Dex2oatFileWrapper(int value, std::function<void ()> cleanup)
+ : value_(value), cleanup_(cleanup), do_cleanup_(true), auto_close_(true) {}
+
+ Dex2oatFileWrapper(Dex2oatFileWrapper&& other) {
+ value_ = other.value_;
+ cleanup_ = other.cleanup_;
+ do_cleanup_ = other.do_cleanup_;
+ auto_close_ = other.auto_close_;
+ other.release();
+ }
+
+ Dex2oatFileWrapper& operator=(Dex2oatFileWrapper&& other) {
+ value_ = other.value_;
+ cleanup_ = other.cleanup_;
+ do_cleanup_ = other.do_cleanup_;
+ auto_close_ = other.auto_close_;
+ other.release();
+ return *this;
+ }
~Dex2oatFileWrapper() {
reset(-1);
@@ -949,7 +965,7 @@
}
void reset(int new_value) {
- if (value_ >= 0) {
+ if (auto_close_ && value_ >= 0) {
close(value_);
}
if (do_cleanup_ && cleanup_ != nullptr) {
@@ -959,8 +975,8 @@
value_ = new_value;
}
- void reset(int new_value, Cleanup new_cleanup) {
- if (value_ >= 0) {
+ void reset(int new_value, std::function<void ()> new_cleanup) {
+ if (auto_close_ && value_ >= 0) {
close(value_);
}
if (do_cleanup_ && cleanup_ != nullptr) {
@@ -971,77 +987,125 @@
cleanup_ = new_cleanup;
}
+ void DisableAutoClose() {
+ auto_close_ = false;
+ }
+
private:
+ void release() {
+ value_ = -1;
+ do_cleanup_ = false;
+ cleanup_ = nullptr;
+ }
int value_;
- Cleanup cleanup_;
+ std::function<void ()> cleanup_;
bool do_cleanup_;
+ bool auto_close_;
};
-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 ATTRIBUTE_UNUSED, const char* shared_libraries) {
- bool is_public = ((dexopt_flags & DEXOPT_PUBLIC) != 0);
- bool vm_safe_mode = (dexopt_flags & DEXOPT_SAFEMODE) != 0;
- bool debuggable = (dexopt_flags & DEXOPT_DEBUGGABLE) != 0;
- bool boot_complete = (dexopt_flags & DEXOPT_BOOTCOMPLETE) != 0;
- bool profile_guided = (dexopt_flags & DEXOPT_PROFILE_GUIDED) != 0;
+// (re)Creates the app image if needed.
+Dex2oatFileWrapper maybe_open_app_image(const char* out_oat_path, bool profile_guided,
+ bool is_public, int uid) {
+ // Use app images only if it is enabled (by a set image format) and we are compiling
+ // profile-guided (so the app image doesn't conservatively contain all classes).
+ if (!profile_guided) {
+ return Dex2oatFileWrapper();
+ }
- CHECK(pkgname != nullptr);
- CHECK(pkgname[0] != 0);
+ const std::string image_path = create_image_filename(out_oat_path);
+ if (image_path.empty()) {
+ // Happens when the out_oat_path has an unknown extension.
+ return Dex2oatFileWrapper();
+ }
+ char app_image_format[kPropertyValueMax];
+ bool have_app_image_format =
+ get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
+ if (!have_app_image_format) {
+ return Dex2oatFileWrapper();
+ }
+ // Recreate is true since we do not want to modify a mapped image. If the app is
+ // already running and we modify the image file, it can cause crashes (b/27493510).
+ Dex2oatFileWrapper wrapper_fd(
+ open_output_file(image_path.c_str(), true /*recreate*/, 0600 /*permissions*/),
+ [image_path]() { unlink(image_path.c_str()); });
+ if (wrapper_fd.get() < 0) {
+ // Could not create application image file. Go on since we can compile without it.
+ LOG(ERROR) << "installd could not create '" << image_path
+ << "' for image file during dexopt";
+ // If we have a valid image file path but no image fd, explicitly erase the image file.
+ if (unlink(image_path.c_str()) < 0) {
+ if (errno != ENOENT) {
+ PLOG(ERROR) << "Couldn't unlink image file " << image_path;
+ }
+ }
+ } else if (!set_permissions_and_ownership(
+ wrapper_fd.get(), is_public, uid, image_path.c_str())) {
+ ALOGE("installd cannot set owner '%s' for image during dexopt\n", image_path.c_str());
+ wrapper_fd.reset(-1);
+ }
+ return wrapper_fd;
+}
+
+// Creates the dexopt swap file if necessary and return its fd.
+// Returns -1 if there's no need for a swap or in case of errors.
+base::unique_fd maybe_open_dexopt_swap_file(const char* out_oat_path) {
+ if (!ShouldUseSwapFileForDexopt()) {
+ return base::unique_fd();
+ }
+ // Make sure there really is enough space.
+ char swap_file_name[PKG_PATH_MAX];
+ strcpy(swap_file_name, out_oat_path);
+ if (!add_extension_to_file_name(swap_file_name, ".swap")) {
+ return base::unique_fd();
+ }
+ base::unique_fd swap_fd(open_output_file(
+ swap_file_name, /*recreate*/true, /*permissions*/0600));
+ if (swap_fd.get() < 0) {
+ // Could not create swap file. Optimistically go on and hope that we can compile
+ // without it.
+ ALOGE("installd could not create '%s' for swap during dexopt\n", swap_file_name);
+ } else {
+ // Immediately unlink. We don't really want to hit flash.
+ if (unlink(swap_file_name) < 0) {
+ PLOG(ERROR) << "Couldn't unlink swap file " << swap_file_name;
+ }
+ }
+ return swap_fd;
+}
+
+// Opens the reference profiles if needed.
+// Note that the reference profile might not exist so it's OK if the fd will be -1.
+Dex2oatFileWrapper maybe_open_reference_profile(const char* pkgname, bool profile_guided,
+ bool is_public, int uid) {
// Public apps should not be compiled with profile information ever. Same goes for the special
// package '*' used for the system server.
- Dex2oatFileWrapper<std::function<void ()>> reference_profile_fd;
- if (!is_public && pkgname[0] != '*') {
+ if (profile_guided && !is_public && (pkgname[0] != '*')) {
// Open reference profile in read only mode as dex2oat does not get write permissions.
const std::string pkgname_str(pkgname);
- reference_profile_fd.reset(open_reference_profile(uid, pkgname, /*read_write*/ false),
- [pkgname_str]() {
- clear_reference_profile(pkgname_str.c_str());
- });
- // Note: it's OK to not find a profile here.
+ return Dex2oatFileWrapper(
+ open_reference_profile(uid, pkgname, /*read_write*/ false),
+ [pkgname_str]() {
+ clear_reference_profile(pkgname_str.c_str());
+ });
+ } else {
+ return Dex2oatFileWrapper();
}
+}
- if ((dexopt_flags & ~DEXOPT_MASK) != 0) {
- LOG_FATAL("dexopt flags contains unknown fields\n");
- }
-
- char out_oat_path[PKG_PATH_MAX];
- if (!create_oat_out_path(apk_path, instruction_set, oat_dir, out_oat_path)) {
- return false;
- }
-
- const char *input_file = apk_path;
- struct stat input_stat;
- memset(&input_stat, 0, sizeof(input_stat));
- stat(input_file, &input_stat);
-
- // Open the input file.
- base::unique_fd input_fd(open(input_file, O_RDONLY, 0));
- if (input_fd.get() < 0) {
- ALOGE("installd cannot open '%s' for input during dexopt\n", input_file);
- return -1;
- }
-
- // Create the output OAT file.
- const std::string out_oat_path_str(out_oat_path);
- Dex2oatFileWrapper<std::function<void ()>> out_oat_fd(
- open_output_file(out_oat_path, /*recreate*/true, /*permissions*/0644),
- [out_oat_path_str]() { unlink(out_oat_path_str.c_str()); });
- if (out_oat_fd.get() < 0) {
- ALOGE("installd cannot open '%s' for output during dexopt\n", out_oat_path);
- return -1;
- }
- if (!set_permissions_and_ownership(out_oat_fd.get(), is_public, uid, out_oat_path)) {
- return -1;
- }
-
+// Opens the vdex files and assigns the input fd to in_vdex_wrapper_fd and the output fd to
+// out_vdex_wrapper_fd. Returns true for success or false in case of errors.
+bool open_vdex_files(const char* apk_path, const char* out_oat_path, int dexopt_needed,
+ const char* instruction_set, bool is_public, int uid,
+ Dex2oatFileWrapper* in_vdex_wrapper_fd,
+ Dex2oatFileWrapper* out_vdex_wrapper_fd) {
+ CHECK(in_vdex_wrapper_fd != nullptr);
+ CHECK(out_vdex_wrapper_fd != nullptr);
// Open the existing VDEX. We do this before creating the new output VDEX, which will
// unlink the old one.
char in_odex_path[PKG_PATH_MAX];
int dexopt_action = abs(dexopt_needed);
bool is_odex_location = dexopt_needed < 0;
- base::unique_fd in_vdex_fd;
std::string in_vdex_path_str;
if (dexopt_action != DEX2OAT_FROM_SCRATCH) {
// Open the possibly existing vdex. If none exist, we pass -1 to dex2oat for input-vdex-fd.
@@ -1051,7 +1115,7 @@
path = in_odex_path;
} else {
ALOGE("installd cannot compute input vdex location for '%s'\n", apk_path);
- return -1;
+ return false;
}
} else {
path = out_oat_path;
@@ -1059,108 +1123,138 @@
in_vdex_path_str = create_vdex_filename(path);
if (in_vdex_path_str.empty()) {
ALOGE("installd cannot compute input vdex location for '%s'\n", path);
- return -1;
+ return false;
}
if (dexopt_action == DEX2OAT_FOR_BOOT_IMAGE) {
// When we dex2oat because iof boot image change, we are going to update
// in-place the vdex file.
- in_vdex_fd.reset(open(in_vdex_path_str.c_str(), O_RDWR, 0));
+ in_vdex_wrapper_fd->reset(open(in_vdex_path_str.c_str(), O_RDWR, 0));
} else {
- in_vdex_fd.reset(open(in_vdex_path_str.c_str(), O_RDONLY, 0));
+ in_vdex_wrapper_fd->reset(open(in_vdex_path_str.c_str(), O_RDONLY, 0));
}
}
// Infer the name of the output VDEX and create it.
- const std::string out_vdex_path_str = create_vdex_filename(out_oat_path_str);
+ const std::string out_vdex_path_str = create_vdex_filename(out_oat_path);
if (out_vdex_path_str.empty()) {
- return -1;
+ return false;
}
- Dex2oatFileWrapper<std::function<void ()>> out_vdex_wrapper_fd;
- int out_vdex_fd = -1;
// If we are compiling because the boot image is out of date, we do not
// need to recreate a vdex, and can use the same existing one.
if (dexopt_action == DEX2OAT_FOR_BOOT_IMAGE &&
- in_vdex_fd != -1 &&
+ in_vdex_wrapper_fd->get() != -1 &&
in_vdex_path_str == out_vdex_path_str) {
- out_vdex_fd = in_vdex_fd;
+ out_vdex_wrapper_fd->reset(in_vdex_wrapper_fd->get());
+ // Disable auto close for the in wrapper fd (it will be done when destructing the out
+ // wrapper).
+ in_vdex_wrapper_fd->DisableAutoClose();
} else {
- out_vdex_wrapper_fd.reset(
+ out_vdex_wrapper_fd->reset(
open_output_file(out_vdex_path_str.c_str(), /*recreate*/true, /*permissions*/0644),
[out_vdex_path_str]() { unlink(out_vdex_path_str.c_str()); });
- out_vdex_fd = out_vdex_wrapper_fd.get();
- if (out_vdex_fd < 0) {
- ALOGE("installd cannot open '%s' for output during dexopt\n", out_vdex_path_str.c_str());
- return -1;
+ if (out_vdex_wrapper_fd->get() < 0) {
+ ALOGE("installd cannot open vdex'%s' during dexopt\n", out_vdex_path_str.c_str());
+ return false;
}
}
- if (!set_permissions_and_ownership(out_vdex_fd, is_public,
- uid, out_vdex_path_str.c_str())) {
+ if (!set_permissions_and_ownership(out_vdex_wrapper_fd->get(), is_public, uid,
+ out_vdex_path_str.c_str())) {
+ ALOGE("installd cannot set owner '%s' for vdex during dexopt\n", out_vdex_path_str.c_str());
+ return false;
+ }
+
+ // If we got here we successfully opened the vdex files.
+ return true;
+}
+
+// Opens the output oat file for the given apk.
+// If successful it stores the output path into out_oat_path and returns true.
+Dex2oatFileWrapper open_oat_out_file(const char* apk_path, const char* oat_dir,
+ bool is_public, int uid, const char* instruction_set, char* out_oat_path) {
+ if (!create_oat_out_path(apk_path, instruction_set, oat_dir, out_oat_path)) {
+ return Dex2oatFileWrapper();
+ }
+ const std::string out_oat_path_str(out_oat_path);
+ Dex2oatFileWrapper wrapper_fd(
+ open_output_file(out_oat_path, /*recreate*/true, /*permissions*/0644),
+ [out_oat_path_str]() { unlink(out_oat_path_str.c_str()); });
+ if (wrapper_fd.get() < 0) {
+ ALOGE("installd cannot open '%s' for output during dexopt\n", out_oat_path);
+ } else if (!set_permissions_and_ownership(wrapper_fd.get(), is_public, uid, out_oat_path)) {
+ ALOGE("installd cannot set owner '%s' for output during dexopt\n", out_oat_path);
+ wrapper_fd.reset(-1);
+ }
+ return wrapper_fd;
+}
+
+// Updates the access times of out_oat_path based on those from apk_path.
+void update_out_oat_access_times(const char* apk_path, const char* out_oat_path) {
+ struct stat input_stat;
+ memset(&input_stat, 0, sizeof(input_stat));
+ if (stat(apk_path, &input_stat) != 0) {
+ PLOG(ERROR) << "Could not stat " << apk_path << " during dexopt";
+ return;
+ }
+
+ struct utimbuf ut;
+ ut.actime = input_stat.st_atime;
+ ut.modtime = input_stat.st_mtime;
+ if (utime(out_oat_path, &ut) != 0) {
+ PLOG(WARNING) << "Could not update access times for " << apk_path << " during dexopt";
+ }
+}
+
+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 ATTRIBUTE_UNUSED, const char* shared_libraries) {
+ CHECK(pkgname != nullptr);
+ CHECK(pkgname[0] != 0);
+ if ((dexopt_flags & ~DEXOPT_MASK) != 0) {
+ LOG_FATAL("dexopt flags contains unknown fields\n");
+ }
+
+ bool is_public = ((dexopt_flags & DEXOPT_PUBLIC) != 0);
+ bool vm_safe_mode = (dexopt_flags & DEXOPT_SAFEMODE) != 0;
+ bool debuggable = (dexopt_flags & DEXOPT_DEBUGGABLE) != 0;
+ bool boot_complete = (dexopt_flags & DEXOPT_BOOTCOMPLETE) != 0;
+ bool profile_guided = (dexopt_flags & DEXOPT_PROFILE_GUIDED) != 0;
+
+ // Open the input file.
+ base::unique_fd input_fd(open(apk_path, O_RDONLY, 0));
+ if (input_fd.get() < 0) {
+ ALOGE("installd cannot open '%s' for input during dexopt\n", apk_path);
+ return -1;
+ }
+
+ // Create the output OAT file.
+ char out_oat_path[PKG_PATH_MAX];
+ Dex2oatFileWrapper out_oat_fd = open_oat_out_file(apk_path, oat_dir, is_public, uid,
+ instruction_set, out_oat_path);
+ if (out_oat_fd.get() < 0) {
+ return -1;
+ }
+
+ // Open vdex files.
+ Dex2oatFileWrapper in_vdex_fd;
+ Dex2oatFileWrapper out_vdex_fd;
+ if (!open_vdex_files(apk_path, out_oat_path, dexopt_needed, instruction_set, is_public, uid,
+ &in_vdex_fd, &out_vdex_fd)) {
return -1;
}
// Create a swap file if necessary.
- base::unique_fd swap_fd;
- if (ShouldUseSwapFileForDexopt()) {
- // Make sure there really is enough space.
- char swap_file_name[PKG_PATH_MAX];
- strcpy(swap_file_name, out_oat_path);
- if (add_extension_to_file_name(swap_file_name, ".swap")) {
- swap_fd.reset(open_output_file(swap_file_name, /*recreate*/true, /*permissions*/0600));
- }
- if (swap_fd.get() < 0) {
- // Could not create swap file. Optimistically go on and hope that we can compile
- // without it.
- ALOGE("installd could not create '%s' for swap during dexopt\n", swap_file_name);
- } else {
- // Immediately unlink. We don't really want to hit flash.
- if (unlink(swap_file_name) < 0) {
- PLOG(ERROR) << "Couldn't unlink swap file " << swap_file_name;
- }
- }
- }
+ base::unique_fd swap_fd = maybe_open_dexopt_swap_file(out_oat_path);
- // Avoid generating an app image for extract only since it will not contain any classes.
- Dex2oatFileWrapper<std::function<void ()>> image_fd;
- const std::string image_path = create_image_filename(out_oat_path);
- if (!image_path.empty()) {
- char app_image_format[kPropertyValueMax];
- bool have_app_image_format =
- get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
- // Use app images only if it is enabled (by a set image format) and we are compiling
- // profile-guided (so the app image doesn't conservatively contain all classes).
- if (profile_guided && have_app_image_format) {
- // Recreate is true since we do not want to modify a mapped image. If the app is
- // already running and we modify the image file, it can cause crashes (b/27493510).
- image_fd.reset(open_output_file(image_path.c_str(),
- true /*recreate*/,
- 0600 /*permissions*/),
- [image_path]() { unlink(image_path.c_str()); }
- );
- if (image_fd.get() < 0) {
- // Could not create application image file. Go on since we can compile without
- // it.
- LOG(ERROR) << "installd could not create '"
- << image_path
- << "' for image file during dexopt";
- } else if (!set_permissions_and_ownership(image_fd.get(),
- is_public,
- uid,
- image_path.c_str())) {
- image_fd.reset(-1);
- }
- }
- // If we have a valid image file path but no image fd, explicitly erase the image file.
- if (image_fd.get() < 0) {
- if (unlink(image_path.c_str()) < 0) {
- if (errno != ENOENT) {
- PLOG(ERROR) << "Couldn't unlink image file " << image_path;
- }
- }
- }
- }
+ // Create the app image file if needed.
+ Dex2oatFileWrapper image_fd =
+ maybe_open_app_image(out_oat_path, profile_guided, is_public, uid);
- ALOGV("DexInv: --- BEGIN '%s' ---\n", input_file);
+ // Open the reference profile if needed.
+ Dex2oatFileWrapper reference_profile_fd =
+ maybe_open_reference_profile(pkgname, profile_guided, is_public, uid);
+
+ ALOGV("DexInv: --- BEGIN '%s' ---\n", apk_path);
pid_t pid = fork();
if (pid == 0) {
@@ -1174,11 +1268,11 @@
}
// Pass dex2oat the relative path to the input file.
- const char *input_file_name = get_location_from_path(input_file);
+ const char *input_file_name = get_location_from_path(apk_path);
run_dex2oat(input_fd.get(),
out_oat_fd.get(),
in_vdex_fd.get(),
- out_vdex_fd,
+ out_vdex_fd.get(),
image_fd.get(),
input_file_name,
out_oat_path,
@@ -1194,21 +1288,18 @@
} else {
int res = wait_child(pid);
if (res == 0) {
- ALOGV("DexInv: --- END '%s' (success) ---\n", input_file);
+ ALOGV("DexInv: --- END '%s' (success) ---\n", apk_path);
} else {
- ALOGE("DexInv: --- END '%s' --- status=0x%04x, process failed\n", input_file, res);
+ ALOGE("DexInv: --- END '%s' --- status=0x%04x, process failed\n", apk_path, res);
return -1;
}
}
- struct utimbuf ut;
- ut.actime = input_stat.st_atime;
- ut.modtime = input_stat.st_mtime;
- utime(out_oat_path, &ut);
+ update_out_oat_access_times(apk_path, out_oat_path);
// We've been successful, don't delete output.
out_oat_fd.SetCleanup(false);
- out_vdex_wrapper_fd.SetCleanup(false);
+ out_vdex_fd.SetCleanup(false);
image_fd.SetCleanup(false);
reference_profile_fd.SetCleanup(false);
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index f2f0cbb..5e396c7 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -31,7 +31,6 @@
#include <installd_constants.h>
#define MEASURE_DEBUG 0
-#define MEASURE_EXTERNAL 0
namespace android {
namespace installd {
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index a31e3c7..43c4c8b 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -363,6 +363,7 @@
int main()
{
struct binder_state *bs;
+ union selinux_callback cb;
bs = binder_open(128*1024);
if (!bs) {
@@ -375,6 +376,11 @@
return -1;
}
+ cb.func_audit = audit_callback;
+ selinux_set_callback(SELINUX_CB_AUDIT, cb);
+ cb.func_log = selinux_log_callback;
+ selinux_set_callback(SELINUX_CB_LOG, cb);
+
sehandle = selinux_android_service_context_handle();
selinux_status_open(true);
@@ -388,11 +394,6 @@
abort();
}
- union selinux_callback cb;
- cb.func_audit = audit_callback;
- selinux_set_callback(SELINUX_CB_AUDIT, cb);
- cb.func_log = selinux_log_callback;
- selinux_set_callback(SELINUX_CB_LOG, cb);
binder_loop(bs, svcmgr_handler);
diff --git a/data/etc/android.hardware.telephony.carrierlock.xml b/data/etc/android.hardware.telephony.carrierlock.xml
new file mode 100644
index 0000000..50b1fe9
--- /dev/null
+++ b/data/etc/android.hardware.telephony.carrierlock.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+
+<!-- Feature for devices with telephony carrier restriction mechanism. -->
+<permissions>
+ <feature name="android.hardware.telephony.carrierlock" />
+</permissions>
diff --git a/include/android/configuration.h b/include/android/configuration.h
index 8e10f67..c9f63ae 100644
--- a/include/android/configuration.h
+++ b/include/android/configuration.h
@@ -267,6 +267,36 @@
ACONFIGURATION_SCREENROUND_NO = 0x1,
ACONFIGURATION_SCREENROUND_YES = 0x2,
+ /** Wide color gamut: not specified. */
+ ACONFIGURATION_WIDE_COLOR_GAMUT_ANY = 0x00,
+ /**
+ * Wide color gamut: value that corresponds to
+ * <a href="@dacRoot/guide/topics/resources/providing-resources.html#WideColorGamutQualifier">no
+ * nowidecg</a> resource qualifier specified.
+ */
+ ACONFIGURATION_WIDE_COLOR_GAMUT_NO = 0x1,
+ /**
+ * Wide color gamut: value that corresponds to
+ * <a href="@dacRoot/guide/topics/resources/providing-resources.html#WideColorGamutQualifier">
+ * widecg</a> resource qualifier specified.
+ */
+ ACONFIGURATION_WIDE_COLOR_GAMUT_YES = 0x2,
+
+ /** HDR: not specified. */
+ ACONFIGURATION_HDR_ANY = 0x00,
+ /**
+ * HDR: value that corresponds to
+ * <a href="@dacRoot/guide/topics/resources/providing-resources.html#HDRQualifier">
+ * lowdr</a> resource qualifier specified.
+ */
+ ACONFIGURATION_HDR_NO = 0x1,
+ /**
+ * HDR: value that corresponds to
+ * <a href="@dacRoot/guide/topics/resources/providing-resources.html#HDRQualifier">
+ * highdr</a> resource qualifier specified.
+ */
+ ACONFIGURATION_HDR_YES = 0x2,
+
/** UI mode: not specified. */
ACONFIGURATION_UI_MODE_TYPE_ANY = 0x00,
/**
@@ -300,6 +330,11 @@
* <a href="@dacRoot/guide/topics/resources/providing-resources.html#UiModeQualifier">watch</a> resource qualifier specified.
*/
ACONFIGURATION_UI_MODE_TYPE_WATCH = 0x06,
+ /**
+ * UI mode: value that corresponds to
+ * <a href="@dacRoot/guide/topics/resources/providing-resources.html#UiModeQualifier">vr</a> resource qualifier specified.
+ */
+ ACONFIGURATION_UI_MODE_TYPE_VR_HEADSET = 0x07,
/** UI night mode: not specified.*/
ACONFIGURATION_UI_MODE_NIGHT_ANY = 0x00,
@@ -426,6 +461,12 @@
ACONFIGURATION_LAYOUTDIR = 0x4000,
ACONFIGURATION_SCREEN_ROUND = 0x8000,
/**
+ * Bit mask for
+ * <a href="@dacRoot/guide/topics/resources/providing-resources.html#WideColorGamutQualifier">wide color gamut</a>
+ * and <a href="@dacRoot/guide/topics/resources/providing-resources.html#HDRQualifier">HDR</a> configurations.
+ */
+ ACONFIGURATION_COLORIMETRY = 0x10000,
+ /**
* Constant used to to represent MNC (Mobile Network Code) zero.
* 0 cannot be used, since it is used to represent an undefined MNC.
*/
diff --git a/include/android/hardware_buffer.h b/include/android/hardware_buffer.h
new file mode 100644
index 0000000..a6c832f
--- /dev/null
+++ b/include/android/hardware_buffer.h
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2017 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.
+ */
+
+/**
+ * @file hardware_buffer.h
+ */
+
+#ifndef ANDROID_HARDWARE_BUFFER_H
+#define ANDROID_HARDWARE_BUFFER_H
+
+#include <inttypes.h>
+
+#include <sys/cdefs.h>
+
+#include <android/rect.h>
+
+__BEGIN_DECLS
+
+/**
+ * Buffer pixel formats.
+ */
+enum {
+ /**
+ * Corresponding formats:
+ * Vulkan: VK_FORMAT_R8G8B8A8_UNORM
+ * OpenGL ES: GL_RGBA8
+ */
+ AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM = 1,
+
+ /**
+ * Corresponding formats:
+ * Vulkan: VK_FORMAT_R8G8B8A8_UNORM
+ * OpenGL ES: GL_RGBA8
+ */
+ AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM = 2,
+
+ /**
+ * Corresponding formats:
+ * Vulkan: VK_FORMAT_R8G8B8_UNORM
+ * OpenGL ES: GL_RGB8
+ */
+ AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM = 3,
+
+ /**
+ * Corresponding formats:
+ * Vulkan: VK_FORMAT_R5G6B5_UNORM_PACK16
+ * OpenGL ES: GL_RGB565
+ */
+ AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM = 4,
+
+ /**
+ * Corresponding formats:
+ * Vulkan: VK_FORMAT_R16G16B16A16_SFLOAT
+ * OpenGL ES: GL_RGBA16F
+ */
+ AHARDWAREBUFFER_FORMAT_R16G16B16A16_SFLOAT = 5,
+};
+
+enum {
+ /* The buffer will sometimes be read by the CPU */
+ AHARDWAREBUFFER_USAGE0_CPU_READ = 1ULL << 1,
+ /* The buffer will often be read by the CPU*/
+ AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN = 1ULL << 2 |
+ AHARDWAREBUFFER_USAGE0_CPU_READ,
+ /* The buffer will sometimes be written to by the CPU */
+ AHARDWAREBUFFER_USAGE0_CPU_WRITE = 1ULL << 5,
+ /* The buffer will often be written to by the CPU */
+ AHARDWAREBUFFER_USAGE0_CPU_WRITE_OFTEN = 1ULL << 6 |
+ AHARDWAREBUFFER_USAGE0_CPU_WRITE,
+ /* The buffer will be read from by the GPU */
+ AHARDWAREBUFFER_USAGE0_GPU_SAMPLED_IMAGE = 1ULL << 10,
+ /* The buffer will be written to by the GPU */
+ AHARDWAREBUFFER_USAGE0_GPU_COLOR_OUTPUT = 1ULL << 11,
+ /* The buffer will be read from and written to by the GPU */
+ AHARDWAREBUFFER_USAGE0_GPU_STORAGE_IMAGE =
+ AHARDWAREBUFFER_USAGE0_GPU_SAMPLED_IMAGE |
+ AHARDWAREBUFFER_USAGE0_GPU_COLOR_OUTPUT,
+ /* The buffer will be used as a cubemap texture */
+ AHARDWAREBUFFER_USAGE0_GPU_CUBEMAP = 1ULL << 13,
+ /* The buffer will be used as a shader storage or uniform buffer object*/
+ AHARDWAREBUFFER_USAGE0_GPU_DATA_BUFFER = 1ULL << 14,
+ /* The buffer must not be used outside of a protected hardware path */
+ AHARDWAREBUFFER_USAGE0_PROTECTED_CONTENT = 1ULL << 18,
+ /** The buffer will be used for sensor direct data */
+ AHARDWAREBUFFER_USAGE0_SENSOR_DIRECT_DATA = 1ULL << 29,
+ /* The buffer will be read by a hardware video encoder */
+ AHARDWAREBUFFER_USAGE0_VIDEO_ENCODE = 1ULL << 21,
+};
+
+typedef struct AHardwareBuffer_Desc {
+ uint32_t width;
+ uint32_t height;
+ uint32_t layers;
+ uint64_t usage0; // Combination of AHARDWAREBUFFER_USAGE0_*
+ uint64_t usage1; // Initialize to zero, reserved for future use
+ uint32_t format; // One of AHARDWAREBUFFER_FORMAT_*
+} AHardwareBuffer_Desc;
+
+typedef struct AHardwareBuffer AHardwareBuffer;
+
+/**
+ * Allocates a buffer that backs an AHardwareBuffer using the passed
+ * AHardwareBuffer_Desc.
+ *
+ * Returns NO_ERROR on success, or an error number of the allocation fails for
+ * any reason.
+ */
+int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* desc,
+ AHardwareBuffer** outBuffer);
+/**
+ * Acquire a reference on the given AHardwareBuffer object. This prevents the
+ * object from being deleted until the last reference is removed.
+ */
+void AHardwareBuffer_acquire(AHardwareBuffer* buffer);
+
+/**
+ * Remove a reference that was previously acquired with
+ * AHardwareBuffer_acquire().
+ */
+void AHardwareBuffer_release(AHardwareBuffer* buffer);
+
+/**
+ * Return a description of the AHardwareBuffer in the passed
+ * AHardwareBuffer_Desc struct.
+ */
+void AHardwareBuffer_describe(const AHardwareBuffer* buffer,
+ AHardwareBuffer_Desc* outDesc);
+
+/*
+ * Lock the AHardwareBuffer for reading or writing, depending on the usage flags
+ * passed. This call may block if the hardware needs to finish rendering or if
+ * CPU caches need to be synchronized, or possibly for other implementation-
+ * specific reasons. If fence is not negative, then it specifies a fence file
+ * descriptor that will be signaled when the buffer is locked, otherwise the
+ * caller will block until the buffer is available.
+ *
+ * If rect is not NULL, the caller promises to modify only data in the area
+ * specified by rect. If rect is NULL, the caller may modify the contents of the
+ * entire buffer.
+ *
+ * The content of the buffer outside of the specified rect is NOT modified
+ * by this call.
+ *
+ * The buffer usage may only specify AHARDWAREBUFFER_USAGE0_CPU_*. If set, then
+ * outVirtualAddress is filled with the address of the buffer in virtual memory,
+ * otherwise this function will fail.
+ *
+ * THREADING CONSIDERATIONS:
+ *
+ * It is legal for several different threads to lock a buffer for read access;
+ * none of the threads are blocked.
+ *
+ * Locking a buffer simultaneously for write or read/write is undefined, but
+ * will neither terminate the process nor block the caller; AHardwareBuffer_lock
+ * may return an error or leave the buffer's content into an indeterminate
+ * state.
+ *
+ * Returns NO_ERROR on success, BAD_VALUE if the buffer is NULL or if the usage0
+ * flags are not a combination of AHARDWAREBUFFER_USAGE0_CPU_*, or an error
+ * number of the lock fails for any reason.
+ */
+int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage0,
+ int32_t fence, const ARect* rect, void** outVirtualAddress);
+
+/*
+ * Unlock the AHardwareBuffer; must be called after all changes to the buffer
+ * are completed by the caller. If fence is not NULL then it will be set to a
+ * file descriptor that is signaled when all pending work on the buffer is
+ * completed. The caller is responsible for closing the fence when it is no
+ * longer needed.
+ *
+ * Returns NO_ERROR on success, BAD_VALUE if the buffer is NULL, or an error
+ * number of the lock fails for any reason.
+ */
+int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence);
+
+/*
+ * Send the AHardwareBuffer to an AF_UNIX socket.
+ *
+ * Returns NO_ERROR on success, BAD_VALUE if the buffer is NULL, or an error
+ * number of the lock fails for any reason.
+ */
+int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer,
+ int socketFd);
+
+/*
+ * Receive the AHardwareBuffer from an AF_UNIX socket.
+ *
+ * Returns NO_ERROR on success, BAD_VALUE if the buffer is NULL, or an error
+ * number of the lock fails for any reason.
+ */
+int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd,
+ AHardwareBuffer** outBuffer);
+
+// ----------------------------------------------------------------------------
+// Everything below here is part of the public NDK API, but is intended only
+// for use by device-specific graphics drivers.
+struct native_handle;
+const struct native_handle* AHardwareBuffer_getNativeHandle(
+ const AHardwareBuffer* buffer);
+
+__END_DECLS
+
+#endif // ANDROID_HARDWARE_BUFFER_H
diff --git a/include/android/hardware_buffer_jni.h b/include/android/hardware_buffer_jni.h
new file mode 100644
index 0000000..6020870
--- /dev/null
+++ b/include/android/hardware_buffer_jni.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+/**
+ * @file hardware_buffer_jni.h
+ */
+
+#ifndef ANDROID_HARDWARE_BUFFER_JNI_H
+#define ANDROID_HARDWARE_BUFFER_JNI_H
+
+#include <sys/cdefs.h>
+
+#include <android/hardware_buffer.h>
+
+#include <jni.h>
+
+__BEGIN_DECLS
+
+/**
+ * Return the AHardwareBuffer associated with a Java HardwareBuffer object,
+ * for interacting with it through native code. This acquires a reference
+ * on the AHardwareBuffer that is returned; be sure to use
+ * AHardwareBuffer_release() when done with it so that it doesn't leak.
+ */
+AHardwareBuffer* AHardwareBuffer_fromHardwareBuffer(JNIEnv* env,
+ jobject hardwareBufferObj);
+
+/**
+ * Return a new Java HardwareBuffer object that wraps the passed native
+ * AHardwareBuffer object.
+ */
+jobject AHardwareBuffer_toHardwareBuffer(JNIEnv* env,
+ AHardwareBuffer* hardwareBuffer);
+
+__END_DECLS
+
+#endif // ANDROID_HARDWARE_BUFFER_JNI_H
diff --git a/include/android/native_window.h b/include/android/native_window.h
index 021dc42..7d8d657 100644
--- a/include/android/native_window.h
+++ b/include/android/native_window.h
@@ -28,6 +28,7 @@
#include <sys/cdefs.h>
+#include <android/hardware_buffer.h>
#include <android/rect.h>
#ifdef __cplusplus
@@ -35,17 +36,18 @@
#endif
/**
- * Pixel formats that a window can use.
+ * Legacy window pixel format names, kept for backwards compatibility.
+ * New code and APIs should use AHARDWAREBUFFER_FORMAT_*.
*/
enum {
// NOTE: these values must match the values from graphics/common/x.x/types.hal
/** Red: 8 bits, Green: 8 bits, Blue: 8 bits, Alpha: 8 bits. **/
- WINDOW_FORMAT_RGBA_8888 = 1,
+ WINDOW_FORMAT_RGBA_8888 = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
/** Red: 8 bits, Green: 8 bits, Blue: 8 bits, Unused: 8 bits. **/
- WINDOW_FORMAT_RGBX_8888 = 2,
+ WINDOW_FORMAT_RGBX_8888 = AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM,
/** Red: 5 bits, Green: 6 bits, Blue: 5 bits. **/
- WINDOW_FORMAT_RGB_565 = 4,
+ WINDOW_FORMAT_RGB_565 = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM,
/** Red: 16 bits, Green: 16 bits, Blue: 16 bits, Alpha: 16 bits. **/
WINDOW_FORMAT_RGBA_FP16 = 0x16,
};
diff --git a/include/audiomanager/AudioManager.h b/include/audiomanager/AudioManager.h
index d561594..834dcbd 100644
--- a/include/audiomanager/AudioManager.h
+++ b/include/audiomanager/AudioManager.h
@@ -23,19 +23,19 @@
#define PLAYER_PIID_INVALID -1
-enum {
+typedef enum {
PLAYER_TYPE_SLES_AUDIOPLAYER_BUFFERQUEUE = 11,
PLAYER_TYPE_SLES_AUDIOPLAYER_URI_FD = 12,
-};
+} player_type_t;
-enum {
+typedef enum {
PLAYER_STATE_UNKNOWN = -1,
PLAYER_STATE_RELEASED = 0,
PLAYER_STATE_IDLE = 1,
PLAYER_STATE_STARTED = 2,
PLAYER_STATE_PAUSED = 3,
PLAYER_STATE_STOPPED = 4,
-};
+} player_state_t;
}; // namespace android
diff --git a/include/audiomanager/IAudioManager.h b/include/audiomanager/IAudioManager.h
index f5ea259..909318a 100644
--- a/include/audiomanager/IAudioManager.h
+++ b/include/audiomanager/IAudioManager.h
@@ -114,10 +114,12 @@
// The parcels created by these methods must be kept in sync with the
// corresponding methods from IAudioService.aidl and objects it imports.
- virtual audio_unique_id_t trackPlayer(int playerType, int usage, int content) = 0;
- /*oneway*/ virtual status_t playerAttributes(audio_unique_id_t piid, int usage, int content)= 0;
- /*oneway*/ virtual status_t playerEvent(int piid, int event) = 0;
- /*oneway*/ virtual status_t releasePlayer(int piid) = 0;
+ virtual audio_unique_id_t trackPlayer(player_type_t playerType, audio_usage_t usage,
+ audio_content_type_t content, const sp<IBinder>& player) = 0;
+ /*oneway*/ virtual status_t playerAttributes(audio_unique_id_t piid, audio_usage_t usage,
+ audio_content_type_t content)= 0;
+ /*oneway*/ virtual status_t playerEvent(audio_unique_id_t piid, player_state_t event) = 0;
+ /*oneway*/ virtual status_t releasePlayer(audio_unique_id_t piid) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/audiomanager/IPlayer.h b/include/audiomanager/IPlayer.h
new file mode 100644
index 0000000..efcac74
--- /dev/null
+++ b/include/audiomanager/IPlayer.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2017 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_IPLAYER_H
+#define ANDROID_IPLAYER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <binder/IInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class IPlayer : public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(Player);
+
+ virtual void start() = 0;
+
+ virtual void pause() = 0;
+
+ virtual void stop() = 0;
+
+ virtual void setVolume(float vol) = 0;
+
+};
+
+// ----------------------------------------------------------------------------
+
+class BnPlayer : public BnInterface<IPlayer>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IPLAYER_H
diff --git a/include/binder/Status.h b/include/binder/Status.h
index dd61616..c3738f8 100644
--- a/include/binder/Status.h
+++ b/include/binder/Status.h
@@ -62,6 +62,7 @@
EX_NETWORK_MAIN_THREAD = -6,
EX_UNSUPPORTED_OPERATION = -7,
EX_SERVICE_SPECIFIC = -8,
+ EX_PARCELABLE = -9,
// This is special and Java specific; see Parcel.java.
EX_HAS_REPLY_HEADER = -128,
diff --git a/include/gfx/SafeLog.h b/include/gfx/SafeLog.h
new file mode 100644
index 0000000..e45e541
--- /dev/null
+++ b/include/gfx/SafeLog.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Weverything"
+#include <fmt/format.h>
+#include <log/log.h>
+#pragma clang diagnostic pop
+
+#include <type_traits>
+
+namespace android {
+namespace gfx {
+
+/* SafeLog is a mix-in that can be used to easily add typesafe logging using fmtlib to any class.
+ * To use it, inherit from it using CRTP and implement the getLogTag method.
+ *
+ * For example:
+ *
+ * class Frobnicator : private SafeLog<Frobnicator> {
+ * friend class SafeLog<Frobnicator>; // Allows getLogTag to be private
+ *
+ * public:
+ * void frobnicate(int32_t i);
+ *
+ * private:
+ * // SafeLog does member access on the object calling alog*, so this tag can theoretically vary
+ * // by instance unless getLogTag is made static
+ * const char* getLogTag() { return "Frobnicator"; }
+ * };
+ *
+ * void Frobnicator::frobnicate(int32_t i) {
+ * // Logs something like "04-16 21:35:46.811 3513 3513 I Frobnicator: frobnicating 42"
+ * alogi("frobnicating {}", i);
+ * }
+ *
+ * See http://fmtlib.net for more information on the formatting API.
+ */
+
+template <typename T>
+class SafeLog {
+ protected:
+ template <typename... Args>
+#if LOG_NDEBUG
+ void alogv(Args&&... /*unused*/) const {
+ }
+#else
+ void alogv(Args&&... args) const {
+ alog<ANDROID_LOG_VERBOSE>(std::forward<Args>(args)...);
+ }
+#endif
+
+ template <typename... Args>
+ void alogd(Args&&... args) const {
+ alog<ANDROID_LOG_DEBUG>(std::forward<Args>(args)...);
+ }
+
+ template <typename... Args>
+ void alogi(Args&&... args) const {
+ alog<ANDROID_LOG_INFO>(std::forward<Args>(args)...);
+ }
+
+ template <typename... Args>
+ void alogw(Args&&... args) const {
+ alog<ANDROID_LOG_WARN>(std::forward<Args>(args)...);
+ }
+
+ template <typename... Args>
+ void aloge(Args&&... args) const {
+ alog<ANDROID_LOG_ERROR>(std::forward<Args>(args)...);
+ }
+
+ private:
+ // Suppresses clang-tidy check cppcoreguidelines-pro-bounds-array-to-pointer-decay
+ template <size_t strlen, typename... Args>
+ void write(fmt::MemoryWriter* writer, const char (&str)[strlen], Args&&... args) const {
+ writer->write(static_cast<const char*>(str), std::forward<Args>(args)...);
+ }
+
+ template <int priority, typename... Args>
+ void alog(Args&&... args) const {
+ static_assert(std::is_base_of<SafeLog<T>, T>::value, "Can't convert to SafeLog pointer");
+ fmt::MemoryWriter writer;
+ write(&writer, std::forward<Args>(args)...);
+ auto derivedThis = static_cast<const T*>(this);
+ android_writeLog(priority, derivedThis->getLogTag(), writer.c_str());
+ }
+};
+
+} // namespace gfx
+} // namespace android
diff --git a/include/gui/BufferQueueConsumer.h b/include/gui/BufferQueueConsumer.h
index e2bafec..da574ec 100644
--- a/include/gui/BufferQueueConsumer.h
+++ b/include/gui/BufferQueueConsumer.h
@@ -22,6 +22,7 @@
#include <gui/BufferQueueDefs.h>
#include <gui/IGraphicBufferConsumer.h>
+#include <utils/String8.h>
namespace android {
diff --git a/include/gui/FrameTimestamps.h b/include/gui/FrameTimestamps.h
index 8a3fa39..46ca2c2 100644
--- a/include/gui/FrameTimestamps.h
+++ b/include/gui/FrameTimestamps.h
@@ -44,6 +44,7 @@
GL_COMPOSITION_DONE,
DISPLAY_PRESENT,
DISPLAY_RETIRE,
+ DEQUEUE_READY,
RELEASE,
EVENT_COUNT, // Not an actual event.
};
@@ -61,6 +62,7 @@
bool hasDisplayPresentInfo() const;
bool hasDisplayRetireInfo() const;
bool hasReleaseInfo() const;
+ bool hasDequeueReadyInfo() const;
void checkFencesForCompletion();
void dump(String8& outString) const;
@@ -84,6 +86,7 @@
nsecs_t latchTime{-1};
nsecs_t firstRefreshStartTime{-1};
nsecs_t lastRefreshStartTime{-1};
+ nsecs_t dequeueReadyTime{-1};
std::shared_ptr<FenceTime> acquireFence{FenceTime::NO_FENCE};
std::shared_ptr<FenceTime> gpuCompositionDoneFence{FenceTime::NO_FENCE};
@@ -116,13 +119,22 @@
public:
~ProducerFrameEventHistory() override;
- void updateAcquireFence(
+ // virtual for testing.
+ virtual void updateAcquireFence(
uint64_t frameNumber, std::shared_ptr<FenceTime>&& acquire);
void applyDelta(const FrameEventHistoryDelta& delta);
void updateSignalTimes();
-private:
+protected:
+ void applyFenceDelta(FenceTimeline* timeline,
+ std::shared_ptr<FenceTime>* dst,
+ const FenceTime::Snapshot& src) const;
+
+ // virtual for testing.
+ virtual std::shared_ptr<FenceTime> createFenceTime(
+ const sp<Fence>& fence) const;
+
size_t mAcquireOffset{0};
// The consumer updates it's timelines in Layer and SurfaceFlinger since
@@ -185,7 +197,7 @@
const std::shared_ptr<FenceTime>& displayPresent);
void addRetire(uint64_t frameNumber,
const std::shared_ptr<FenceTime>& displayRetire);
- void addRelease(uint64_t frameNumber,
+ void addRelease(uint64_t frameNumber, nsecs_t dequeueReadyTime,
std::shared_ptr<FenceTime>&& release);
void getAndResetDelta(FrameEventHistoryDelta* delta);
@@ -246,6 +258,7 @@
nsecs_t mLatchTime{0};
nsecs_t mFirstRefreshStartTime{0};
nsecs_t mLastRefreshStartTime{0};
+ nsecs_t mDequeueReadyTime{0};
FenceTime::Snapshot mGpuCompositionDoneFence;
FenceTime::Snapshot mDisplayPresentFence;
diff --git a/include/gui/GraphicsEnv.h b/include/gui/GraphicsEnv.h
new file mode 100644
index 0000000..4c7366f
--- /dev/null
+++ b/include/gui/GraphicsEnv.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2017 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_GRAPHICS_ENV_H
+#define ANDROID_GUI_GRAPHICS_ENV_H 1
+
+#include <string>
+
+struct android_namespace_t;
+
+namespace android {
+
+class GraphicsEnv {
+public:
+ static GraphicsEnv& getInstance();
+
+ // Set a search path for loading graphics drivers. The path is a list of
+ // directories separated by ':'. A directory can be contained in a zip file
+ // (drivers must be stored uncompressed and page aligned); such elements
+ // in the search path must have a '!' after the zip filename, e.g.
+ // /data/app/com.example.driver/base.apk!/lib/arm64-v8a
+ void setDriverPath(const std::string path);
+ android_namespace_t* getDriverNamespace();
+
+private:
+ GraphicsEnv() = default;
+ std::string mDriverPath;
+ android_namespace_t* mDriverNamespace = nullptr;
+};
+
+} // namespace android
+
+/* FIXME
+ * Export an un-mangled function that just does
+ * return android::GraphicsEnv::getInstance().getDriverNamespace();
+ * This allows libEGL to get the function pointer via dlsym, since it can't
+ * directly link against libgui. In a future release, we'll fix this so that
+ * libgui does not depend on graphics API libraries, and libEGL can link
+ * against it. The current dependencies from libgui -> libEGL are:
+ * - the GLConsumer class, which should be moved to its own library
+ * - the EGLsyncKHR synchronization in BufferQueue, which is deprecated and
+ * will be removed soon.
+ */
+extern "C" android_namespace_t* android_getDriverNamespace();
+
+#endif // ANDROID_GUI_GRAPHICS_ENV_H
diff --git a/include/gui/ISensorEventConnection.h b/include/gui/ISensorEventConnection.h
index 857444b..2ccd832 100644
--- a/include/gui/ISensorEventConnection.h
+++ b/include/gui/ISensorEventConnection.h
@@ -40,6 +40,7 @@
nsecs_t maxBatchReportLatencyNs, int reservedFlags) = 0;
virtual status_t setEventRate(int handle, nsecs_t ns) = 0;
virtual status_t flush() = 0;
+ virtual int32_t configureChannel(int32_t handle, int32_t rateLevel) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/gui/ISensorServer.h b/include/gui/ISensorServer.h
index 737c430..0c36c99 100644
--- a/include/gui/ISensorServer.h
+++ b/include/gui/ISensorServer.h
@@ -25,6 +25,8 @@
#include <binder/IInterface.h>
+struct native_handle;
+typedef struct native_handle native_handle_t;
namespace android {
// ----------------------------------------------------------------------------
@@ -43,6 +45,9 @@
virtual sp<ISensorEventConnection> createSensorEventConnection(const String8& packageName,
int mode, const String16& opPackageName) = 0;
virtual int32_t isDataInjectionEnabled() = 0;
+
+ virtual sp<ISensorEventConnection> createSensorDirectConnection(const String16& opPackageName,
+ uint32_t size, int32_t type, int32_t format, const native_handle_t *resource) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/gui/Sensor.h b/include/gui/Sensor.h
index 7506835..d886b2b 100644
--- a/include/gui/Sensor.h
+++ b/include/gui/Sensor.h
@@ -91,6 +91,8 @@
bool isWakeUpSensor() const;
bool isDynamicSensor() const;
bool hasAdditionalInfo() const;
+ int32_t getHighestDirectReportRateLevel() const;
+ bool isDirectChannelTypeSupported(int32_t sharedMemType) const;
int32_t getReportingMode() const;
// Note that after setId() has been called, getUuid() no longer
diff --git a/include/gui/SensorManager.h b/include/gui/SensorManager.h
index 6c6230f..5b34ff4 100644
--- a/include/gui/SensorManager.h
+++ b/include/gui/SensorManager.h
@@ -34,10 +34,15 @@
#include <gui/SensorEventQueue.h>
+#include <unordered_map>
+
// ----------------------------------------------------------------------------
// Concrete types for the NDK
struct ASensorManager { };
+struct native_handle;
+typedef struct native_handle native_handle_t;
+
// ----------------------------------------------------------------------------
namespace android {
// ----------------------------------------------------------------------------
@@ -59,6 +64,9 @@
Sensor const* getDefaultSensor(int type);
sp<SensorEventQueue> createEventQueue(String8 packageName = String8(""), int mode = 0);
bool isDataInjectionEnabled();
+ int createDirectChannel(size_t size, int channelType, const native_handle_t *channelData);
+ void destroyDirectChannel(int channelNativeHandle);
+ int configureDirectChannel(int channelNativeHandle, int sensorHandle, int rateLevel);
private:
// DeathRecipient interface
@@ -77,6 +85,8 @@
Vector<Sensor> mSensors;
sp<IBinder::DeathRecipient> mDeathObserver;
const String16 mOpPackageName;
+ std::unordered_map<int, sp<ISensorEventConnection>> mDirectConnection;
+ int32_t mDirectConnectionHandle;
};
// ----------------------------------------------------------------------------
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index a10dad1..0b6a8f7 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -33,6 +33,8 @@
namespace android {
+class ISurfaceComposer;
+
/*
* An implementation of ANativeWindow that feeds graphics buffers into a
* BufferQueue.
@@ -66,7 +68,8 @@
* the controlledByApp flag indicates that this Surface (producer) is
* controlled by the application. This flag is used at connect time.
*/
- explicit Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp = false);
+ explicit Surface(const sp<IGraphicBufferProducer>& bufferProducer,
+ bool controlledByApp = false);
/* getIGraphicBufferProducer() returns the IGraphicBufferProducer this
* Surface was created with. Usually it's an error to use the
@@ -143,15 +146,19 @@
// See IGraphicBufferProducer::getFrameTimestamps
status_t getFrameTimestamps(uint64_t frameNumber,
nsecs_t* outRequestedPresentTime, nsecs_t* outAcquireTime,
- nsecs_t* outRefreshStartTime, nsecs_t* outGlCompositionDoneTime,
+ nsecs_t* outLatchTime, nsecs_t* outFirstRefreshStartTime,
+ nsecs_t* outLastRefreshStartTime, nsecs_t* outGlCompositionDoneTime,
nsecs_t* outDisplayPresentTime, nsecs_t* outDisplayRetireTime,
- nsecs_t* outReleaseTime);
+ nsecs_t* outDequeueReadyTime, nsecs_t* outReleaseTime);
status_t getUniqueId(uint64_t* outId) const;
protected:
virtual ~Surface();
+ // Virtual for testing.
+ virtual sp<ISurfaceComposer> composerService() const;
+
private:
// can't be copied
Surface& operator = (const Surface& rhs);
@@ -245,7 +252,6 @@
enum { NUM_BUFFER_SLOTS = BufferQueue::NUM_BUFFER_SLOTS };
enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
-private:
void querySupportedTimestampsLocked() const;
void freeAllBuffers();
@@ -389,7 +395,8 @@
Condition mQueueBufferCondition;
- uint64_t mNextFrameNumber;
+ uint64_t mNextFrameNumber = 1;
+ uint64_t mLastFrameNumber = 0;
// Mutable because ANativeWindow::query needs this class const.
mutable bool mQueriedSupportedTimestamps;
@@ -398,7 +405,7 @@
// A cached copy of the FrameEventHistory maintained by the consumer.
bool mEnableFrameTimestamps = false;
- ProducerFrameEventHistory mFrameEventHistory;
+ std::unique_ptr<ProducerFrameEventHistory> mFrameEventHistory;
};
namespace view {
diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h
index 9352c57..b86c72c 100644
--- a/include/gui/SurfaceComposerClient.h
+++ b/include/gui/SurfaceComposerClient.h
@@ -214,7 +214,13 @@
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
bool useIdentityTransform);
-
+ static status_t captureToBuffer(
+ const sp<IBinder>& display,
+ Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ,
+ bool useIdentityTransform,
+ uint32_t rotation,
+ sp<GraphicBuffer>* outbuffer);
private:
mutable sp<CpuConsumer> mCpuConsumer;
mutable sp<IGraphicBufferProducer> mProducer;
diff --git a/include/ui/Fence.h b/include/ui/Fence.h
index 99b39d8..58df24c 100644
--- a/include/ui/Fence.h
+++ b/include/ui/Fence.h
@@ -18,21 +18,17 @@
#define ANDROID_FENCE_H
#include <stdint.h>
-#include <sys/types.h>
-#include <ui/ANativeObjectBase.h>
-#include <ui/PixelFormat.h>
-#include <ui/Rect.h>
#include <utils/Flattenable.h>
-#include <utils/String8.h>
+#include <utils/RefBase.h>
#include <utils/Timers.h>
#include <experimental/optional>
-struct ANativeWindowBuffer;
-
namespace android {
+class String8;
+
// ===========================================================================
// Fence
// ===========================================================================
@@ -62,6 +58,12 @@
// closed.
explicit Fence(int fenceFd);
+ // Not copyable or movable.
+ Fence(const Fence& rhs) = delete;
+ Fence& operator=(const Fence& rhs) = delete;
+ Fence(Fence&& rhs) = delete;
+ Fence& operator=(Fence&& rhs) = delete;
+
// Check whether the Fence has an open fence file descriptor. Most Fence
// methods treat an invalid file descriptor just like a valid fence that
// is already signalled, so using this is usually not necessary.
@@ -135,11 +137,6 @@
friend class LightRefBase<Fence>;
~Fence();
- // Disallow copying
- Fence(const Fence& rhs);
- Fence& operator = (const Fence& rhs);
- const Fence& operator = (const Fence& rhs) const;
-
int mFenceFd;
};
diff --git a/include/ui/FenceTime.h b/include/ui/FenceTime.h
index 27cc720..871fcf2 100644
--- a/include/ui/FenceTime.h
+++ b/include/ui/FenceTime.h
@@ -24,13 +24,17 @@
#include <atomic>
#include <mutex>
#include <queue>
+#include <unordered_map>
namespace android {
+class FenceToFenceTimeMap;
+
// A wrapper around fence that only implements isValid and getSignalTime.
// It automatically closes the fence in a thread-safe manner once the signal
// time is known.
class FenceTime {
+friend class FenceToFenceTimeMap;
public:
// An atomic snapshot of the FenceTime that is flattenable.
//
@@ -107,15 +111,22 @@
// Returns a snapshot of the FenceTime in its current state.
Snapshot getSnapshot() const;
+ void signalForTest(nsecs_t signalTime);
+
// Override new and delete since this needs 8-byte alignment, which
// is not guaranteed on x86.
static void* operator new(size_t nbytes) noexcept;
static void operator delete(void *p);
private:
+ // For tests only. If forceValidForTest is true, then getSignalTime will
+ // never return SIGNAL_TIME_INVALID and isValid will always return true.
+ FenceTime(const sp<Fence>& fence, bool forceValidForTest);
+
enum class State {
VALID,
INVALID,
+ FORCED_VALID_FOR_TEST,
};
const State mState{State::INVALID};
@@ -156,6 +167,42 @@
std::queue<std::weak_ptr<FenceTime>> mQueue;
};
+// Used by test code to create or get FenceTimes for a given Fence.
+//
+// By design, Fences cannot be signaled from user space. However, this class
+// allows test code to set the apparent signalTime of a Fence and
+// have it be visible to all FenceTimes. Release code should not use
+// FenceToFenceTimeMap.
+//
+// FenceToFenceTimeMap keeps a weak reference to the FenceTime and automatically
+// garbage collects entries every time a new FenceTime is created to avoid
+// leaks. This prevents us from having to make the Fence destructor
+// automatically notify that the underlying fence has been destroyed, which
+// would affect release code paths. Garbage collecting so often is inefficient,
+// but acceptable for testing.
+//
+// Since FenceTimes maintain a strong reference to underlying Fences, there
+// should not be any aliasing issues where a new Fence happens to have the same
+// address as a previous Fence; the previous entry will be garbage collected
+// before the new one is added.
+class FenceToFenceTimeMap {
+public:
+ // Create a new FenceTime with that wraps the provided Fence.
+ std::shared_ptr<FenceTime> createFenceTimeForTest(const sp<Fence>& fence);
+
+ // Signals all FenceTimes created through this class that are wrappers
+ // around |fence|.
+ void signalAllForTest(const sp<Fence>& fence, nsecs_t signalTime);
+
+private:
+ // Cleans up the entries that no longer have a strong reference.
+ void garbageCollectLocked();
+
+ mutable std::mutex mMutex;
+ std::unordered_map<Fence*, std::vector<std::weak_ptr<FenceTime>>> mMap;
+};
+
+
}; // namespace android
#endif // ANDROID_FENCE_TIME_H
diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp
index 8466863..006f7f9 100644
--- a/libs/binder/Status.cpp
+++ b/libs/binder/Status.cpp
@@ -104,6 +104,16 @@
if (mException == EX_SERVICE_SPECIFIC) {
status = parcel.readInt32(&mErrorCode);
+ } else if (mException == EX_PARCELABLE) {
+ // Skip over the blob of Parcelable data
+ const int32_t header_start = parcel.dataPosition();
+ int32_t header_size;
+ status = parcel.readInt32(&header_size);
+ if (status != OK) {
+ setFromStatusT(status);
+ return status;
+ }
+ parcel.setDataPosition(header_start + header_size);
}
if (status != OK) {
setFromStatusT(status);
@@ -127,11 +137,12 @@
return status;
}
status = parcel->writeString16(String16(mMessage));
- if (mException != EX_SERVICE_SPECIFIC) {
- // We have no more information to write.
- return status;
+ if (mException == EX_SERVICE_SPECIFIC) {
+ status = parcel->writeInt32(mErrorCode);
+ } else if (mException == EX_PARCELABLE) {
+ // Sending Parcelable blobs currently not supported
+ status = parcel->writeInt32(0);
}
- status = parcel->writeInt32(mErrorCode);
return status;
}
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index cb17da4..3815bdc 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -77,6 +77,7 @@
"FrameTimestamps.cpp",
"GLConsumer.cpp",
"GraphicBufferAlloc.cpp",
+ "GraphicsEnv.cpp",
"GuiConfig.cpp",
"IDisplayEventConnection.cpp",
"IGraphicBufferAlloc.cpp",
@@ -99,6 +100,7 @@
],
shared_libs: [
+ "libnativeloader",
"libsync",
"libbinder",
"libcutils",
diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp
index c9b8948..73537bf 100644
--- a/libs/gui/FrameTimestamps.cpp
+++ b/libs/gui/FrameTimestamps.cpp
@@ -18,6 +18,7 @@
#include <cutils/compiler.h> // For CC_[UN]LIKELY
#include <inttypes.h>
+#include <utils/Log.h>
#include <utils/String8.h>
#include <algorithm>
@@ -54,6 +55,10 @@
return addRetireCalled || addReleaseCalled;
}
+bool FrameEvents::hasDequeueReadyInfo() const {
+ return Fence::isValidTimestamp(dequeueReadyTime);
+}
+
bool FrameEvents::hasAcquireInfo() const {
return acquireFence->isValid();
}
@@ -140,6 +145,14 @@
!addPostCompositeCalled, *displayPresentFence);
dumpFenceTime(outString, "Display Retire \t",
!addRetireCalled, *displayRetireFence);
+
+ outString.appendFormat("--- DequeueReady \t");
+ if (Fence::isValidTimestamp(dequeueReadyTime)) {
+ outString.appendFormat("%" PRId64 "\n", dequeueReadyTime);
+ } else {
+ outString.appendFormat("Pending\n");
+ }
+
dumpFenceTime(outString, "Release \t",
true, *releaseFence);
}
@@ -241,33 +254,6 @@
}
}
-static void applyFenceDelta(FenceTimeline* timeline,
- std::shared_ptr<FenceTime>* dst, const FenceTime::Snapshot& src) {
- if (CC_UNLIKELY(dst == nullptr)) {
- ALOGE("applyFenceDelta: dst is null.");
- return;
- }
-
- switch (src.state) {
- case FenceTime::Snapshot::State::EMPTY:
- return;
- case FenceTime::Snapshot::State::FENCE:
- if (CC_UNLIKELY((*dst)->isValid())) {
- ALOGE("applyFenceDelta: Unexpected fence.");
- }
- *dst = std::make_shared<FenceTime>(src.fence);
- timeline->push(*dst);
- return;
- case FenceTime::Snapshot::State::SIGNAL_TIME:
- if ((*dst)->isValid()) {
- (*dst)->applyTrustedSnapshot(src);
- } else {
- *dst = std::make_shared<FenceTime>(src.signalTime);
- }
- return;
- }
-}
-
void ProducerFrameEventHistory::applyDelta(
const FrameEventHistoryDelta& delta) {
for (auto& d : delta.mDeltas) {
@@ -288,6 +274,7 @@
frame.latchTime = d.mLatchTime;
frame.firstRefreshStartTime = d.mFirstRefreshStartTime;
frame.lastRefreshStartTime = d.mLastRefreshStartTime;
+ frame.dequeueReadyTime = d.mDequeueReadyTime;
if (frame.frameNumber != d.mFrameNumber) {
// We got a new frame. Initialize some of the fields.
@@ -320,6 +307,38 @@
mReleaseTimeline.updateSignalTimes();
}
+void ProducerFrameEventHistory::applyFenceDelta(FenceTimeline* timeline,
+ std::shared_ptr<FenceTime>* dst, const FenceTime::Snapshot& src) const {
+ if (CC_UNLIKELY(dst == nullptr)) {
+ ALOGE("applyFenceDelta: dst is null.");
+ return;
+ }
+
+ switch (src.state) {
+ case FenceTime::Snapshot::State::EMPTY:
+ return;
+ case FenceTime::Snapshot::State::FENCE:
+ if (CC_UNLIKELY((*dst)->isValid())) {
+ ALOGE("applyFenceDelta: Unexpected fence.");
+ }
+ *dst = createFenceTime(src.fence);
+ timeline->push(*dst);
+ return;
+ case FenceTime::Snapshot::State::SIGNAL_TIME:
+ if ((*dst)->isValid()) {
+ (*dst)->applyTrustedSnapshot(src);
+ } else {
+ *dst = std::make_shared<FenceTime>(src.signalTime);
+ }
+ return;
+ }
+}
+
+std::shared_ptr<FenceTime> ProducerFrameEventHistory::createFenceTime(
+ const sp<Fence>& fence) const {
+ return std::make_shared<FenceTime>(fence);
+}
+
// ============================================================================
// ConsumerFrameEventHistory
@@ -405,14 +424,15 @@
mFramesDirty[mRetireOffset].setDirty<FrameEvent::DISPLAY_RETIRE>();
}
-void ConsumerFrameEventHistory::addRelease(
- uint64_t frameNumber, std::shared_ptr<FenceTime>&& release) {
+void ConsumerFrameEventHistory::addRelease(uint64_t frameNumber,
+ nsecs_t dequeueReadyTime, std::shared_ptr<FenceTime>&& release) {
FrameEvents* frame = getFrame(frameNumber, &mReleaseOffset);
if (frame == nullptr) {
ALOGE("ConsumerFrameEventHistory::addRelease: Did not find frame.");
return;
}
frame->addReleaseCalled = true;
+ frame->dequeueReadyTime = dequeueReadyTime;
frame->releaseFence = std::move(release);
mFramesDirty[mReleaseOffset].setDirty<FrameEvent::RELEASE>();
}
@@ -461,7 +481,8 @@
mRequestedPresentTime(frameTimestamps.requestedPresentTime),
mLatchTime(frameTimestamps.latchTime),
mFirstRefreshStartTime(frameTimestamps.firstRefreshStartTime),
- mLastRefreshStartTime(frameTimestamps.lastRefreshStartTime) {
+ mLastRefreshStartTime(frameTimestamps.lastRefreshStartTime),
+ mDequeueReadyTime(frameTimestamps.dequeueReadyTime) {
if (dirtyFields.isDirty<FrameEvent::GL_COMPOSITION_DONE>()) {
mGpuCompositionDoneFence =
frameTimestamps.gpuCompositionDoneFence->getSnapshot();
@@ -489,7 +510,8 @@
sizeof(FrameEventsDelta::mRequestedPresentTime) +
sizeof(FrameEventsDelta::mLatchTime) +
sizeof(FrameEventsDelta::mFirstRefreshStartTime) +
- sizeof(FrameEventsDelta::mLastRefreshStartTime);
+ sizeof(FrameEventsDelta::mLastRefreshStartTime) +
+ sizeof(FrameEventsDelta::mDequeueReadyTime);
return min;
}
@@ -538,6 +560,7 @@
FlattenableUtils::write(buffer, size, mLatchTime);
FlattenableUtils::write(buffer, size, mFirstRefreshStartTime);
FlattenableUtils::write(buffer, size, mLastRefreshStartTime);
+ FlattenableUtils::write(buffer, size, mDequeueReadyTime);
// Fences
for (auto fence : allFences(this)) {
@@ -576,6 +599,7 @@
FlattenableUtils::read(buffer, size, mLatchTime);
FlattenableUtils::read(buffer, size, mFirstRefreshStartTime);
FlattenableUtils::read(buffer, size, mLastRefreshStartTime);
+ FlattenableUtils::read(buffer, size, mDequeueReadyTime);
// Fences
for (auto fence : allFences(this)) {
diff --git a/libs/gui/GraphicsEnv.cpp b/libs/gui/GraphicsEnv.cpp
new file mode 100644
index 0000000..68f0f98
--- /dev/null
+++ b/libs/gui/GraphicsEnv.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2017 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.
+ */
+
+//#define LOG_NDEBUG 1
+#define LOG_TAG "GraphicsEnv"
+#include <gui/GraphicsEnv.h>
+
+#include <mutex>
+
+#include <log/log.h>
+#include <nativeloader/dlext_namespaces.h>
+
+namespace android {
+
+/*static*/ GraphicsEnv& GraphicsEnv::getInstance() {
+ static GraphicsEnv env;
+ return env;
+}
+
+void GraphicsEnv::setDriverPath(const std::string path) {
+ if (!mDriverPath.empty()) {
+ ALOGV("ignoring attempt to change driver path from '%s' to '%s'",
+ mDriverPath.c_str(), path.c_str());
+ return;
+ }
+ ALOGV("setting driver path to '%s'", path.c_str());
+ mDriverPath = path;
+}
+
+android_namespace_t* GraphicsEnv::getDriverNamespace() {
+ static std::once_flag once;
+ std::call_once(once, [this]() {
+ // TODO; In the next version of Android, all graphics drivers will be
+ // loaded into a custom namespace. To minimize risk for this release,
+ // only updated drivers use a custom namespace.
+ //
+ // Additionally, the custom namespace will be
+ // ANDROID_NAMESPACE_TYPE_ISOLATED, and will only have access to a
+ // subset of the system.
+ if (mDriverPath.empty())
+ return;
+
+ char defaultPath[PATH_MAX];
+ android_get_LD_LIBRARY_PATH(defaultPath, sizeof(defaultPath));
+ size_t defaultPathLen = strlen(defaultPath);
+
+ std::string path;
+ path.reserve(mDriverPath.size() + 1 + defaultPathLen);
+ path.append(mDriverPath);
+ path.push_back(':');
+ path.append(defaultPath, defaultPathLen);
+
+ mDriverNamespace = android_create_namespace(
+ "gfx driver",
+ nullptr, // ld_library_path
+ path.c_str(), // default_library_path
+ ANDROID_NAMESPACE_TYPE_SHARED,
+ nullptr, // permitted_when_isolated_path
+ nullptr); // parent
+ });
+ return mDriverNamespace;
+}
+
+} // namespace android
+
+extern "C" android_namespace_t* android_getDriverNamespace() {
+ return android::GraphicsEnv::getInstance().getDriverNamespace();
+}
diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp
index 2401464..ef770e8 100644
--- a/libs/gui/IGraphicBufferConsumer.cpp
+++ b/libs/gui/IGraphicBufferConsumer.cpp
@@ -19,6 +19,7 @@
#include <utils/Errors.h>
#include <utils/NativeHandle.h>
+#include <utils/String8.h>
#include <binder/Parcel.h>
#include <binder/IInterface.h>
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index e37b65b..18a80e8 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -20,6 +20,7 @@
#include <utils/Errors.h>
#include <utils/NativeHandle.h>
#include <utils/RefBase.h>
+#include <utils/String8.h>
#include <utils/Timers.h>
#include <utils/Vector.h>
diff --git a/libs/gui/ISensorEventConnection.cpp b/libs/gui/ISensorEventConnection.cpp
index 59ecee7..8af51c5 100644
--- a/libs/gui/ISensorEventConnection.cpp
+++ b/libs/gui/ISensorEventConnection.cpp
@@ -34,7 +34,8 @@
GET_SENSOR_CHANNEL = IBinder::FIRST_CALL_TRANSACTION,
ENABLE_DISABLE,
SET_EVENT_RATE,
- FLUSH_SENSOR
+ FLUSH_SENSOR,
+ CONFIGURE_CHANNEL
};
class BpSensorEventConnection : public BpInterface<ISensorEventConnection>
@@ -85,6 +86,15 @@
remote()->transact(FLUSH_SENSOR, data, &reply);
return reply.readInt32();
}
+
+ virtual int32_t configureChannel(int32_t handle, int32_t rateLevel) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISensorEventConnection::getInterfaceDescriptor());
+ data.writeInt32(handle);
+ data.writeInt32(rateLevel);
+ remote()->transact(CONFIGURE_CHANNEL, data, &reply);
+ return reply.readInt32();
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -131,6 +141,15 @@
reply->writeInt32(result);
return NO_ERROR;
}
+ case CONFIGURE_CHANNEL: {
+ CHECK_INTERFACE(ISensorEventConnection, data, reply);
+ int handle = data.readInt32();
+ int rateLevel = data.readInt32();
+ status_t result = configureChannel(handle, rateLevel);
+ reply->writeInt32(result);
+ return NO_ERROR;
+ }
+
}
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/ISensorServer.cpp b/libs/gui/ISensorServer.cpp
index 07c507a..aea7403 100644
--- a/libs/gui/ISensorServer.cpp
+++ b/libs/gui/ISensorServer.cpp
@@ -17,6 +17,7 @@
#include <stdint.h>
#include <sys/types.h>
+#include <cutils/native_handle.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
#include <utils/Vector.h>
@@ -37,6 +38,7 @@
CREATE_SENSOR_EVENT_CONNECTION,
ENABLE_DATA_INJECTION,
GET_DYNAMIC_SENSOR_LIST,
+ CREATE_SENSOR_DIRECT_CONNECTION,
};
class BpSensorServer : public BpInterface<ISensorServer>
@@ -101,6 +103,19 @@
remote()->transact(ENABLE_DATA_INJECTION, data, &reply);
return reply.readInt32();
}
+
+ virtual sp<ISensorEventConnection> createSensorDirectConnection(const String16& opPackageName,
+ uint32_t size, int32_t type, int32_t format, const native_handle_t *resource) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor());
+ data.writeString16(opPackageName);
+ data.writeUint32(size);
+ data.writeInt32(type);
+ data.writeInt32(format);
+ data.writeNativeHandle(resource);
+ remote()->transact(CREATE_SENSOR_DIRECT_CONNECTION, data, &reply);
+ return interface_cast<ISensorEventConnection>(reply.readStrongBinder());
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -153,6 +168,20 @@
}
return NO_ERROR;
}
+ case CREATE_SENSOR_DIRECT_CONNECTION: {
+ CHECK_INTERFACE(ISensorServer, data, reply);
+ const String16& opPackageName = data.readString16();
+ uint32_t size = data.readUint32();
+ int32_t type = data.readInt32();
+ int32_t format = data.readInt32();
+ native_handle_t *resource = data.readNativeHandle();
+ sp<ISensorEventConnection> ch =
+ createSensorDirectConnection(opPackageName, size, type, format, resource);
+ native_handle_close(resource);
+ native_handle_delete(resource);
+ reply->writeStrongBinder(IInterface::asBinder(ch));
+ return NO_ERROR;
+ }
}
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp
index 7510429..2fd29d5 100644
--- a/libs/gui/Sensor.cpp
+++ b/libs/gui/Sensor.cpp
@@ -219,7 +219,10 @@
break;
case SENSOR_TYPE_DYNAMIC_SENSOR_META:
mStringType = SENSOR_STRING_TYPE_DYNAMIC_SENSOR_META;
- mFlags = SENSOR_FLAG_SPECIAL_REPORTING_MODE; // special trigger and non-wake up
+ mFlags |= SENSOR_FLAG_SPECIAL_REPORTING_MODE; // special trigger
+ if (halVersion < SENSORS_DEVICE_API_VERSION_1_3) {
+ mFlags |= SENSOR_FLAG_WAKE_UP;
+ }
break;
case SENSOR_TYPE_POSE_6DOF:
mStringType = SENSOR_STRING_TYPE_POSE_6DOF;
@@ -243,6 +246,14 @@
mStringType = SENSOR_STRING_TYPE_HEART_BEAT;
mFlags |= SENSOR_FLAG_SPECIAL_REPORTING_MODE;
break;
+
+ // TODO: Placeholder for LLOB sensor type
+
+
+ case SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED:
+ mStringType = SENSOR_STRING_TYPE_ACCELEROMETER_UNCALIBRATED;
+ mFlags |= SENSOR_FLAG_CONTINUOUS_MODE;
+ break;
default:
// Only pipe the stringType, requiredPermission and flags for custom sensors.
if (halVersion > SENSORS_DEVICE_API_VERSION_1_0 && hwSensor.stringType) {
@@ -289,7 +300,15 @@
// Feature flags
// Set DYNAMIC_SENSOR_MASK and ADDITIONAL_INFO_MASK flag here. Compatible with HAL 1_3.
if (halVersion >= SENSORS_DEVICE_API_VERSION_1_3) {
- mFlags |= (hwSensor.flags & (DYNAMIC_SENSOR_MASK | ADDITIONAL_INFO_MASK));
+ mFlags |= hwSensor.flags & (DYNAMIC_SENSOR_MASK | ADDITIONAL_INFO_MASK);
+ }
+ // Set DIRECT_REPORT_MASK and DIRECT_CHANNEL_MASK flags. Compatible with HAL 1_3.
+ if (halVersion >= SENSORS_DEVICE_API_VERSION_1_3) {
+ // only on continuous sensors direct report mode is defined
+ if ((mFlags & REPORTING_MODE_MASK) == SENSOR_FLAG_CONTINUOUS_MODE) {
+ mFlags |= hwSensor.flags
+ & (SENSOR_FLAG_MASK_DIRECT_REPORT | SENSOR_FLAG_MASK_DIRECT_CHANNEL);
+ }
}
// Set DATA_INJECTION flag here. Defined in HAL 1_4.
if (halVersion >= SENSORS_DEVICE_API_VERSION_1_4) {
@@ -399,6 +418,21 @@
return (mFlags & SENSOR_FLAG_ADDITIONAL_INFO) != 0;
}
+int32_t Sensor::getHighestDirectReportRateLevel() const {
+ return ((mFlags & SENSOR_FLAG_MASK_DIRECT_REPORT) >> SENSOR_FLAG_SHIFT_DIRECT_REPORT);
+}
+
+bool Sensor::isDirectChannelTypeSupported(int32_t sharedMemType) const {
+ switch (sharedMemType) {
+ case SENSOR_DIRECT_MEM_TYPE_ASHMEM:
+ return mFlags & SENSOR_FLAG_DIRECT_CHANNEL_ASHMEM;
+ case SENSOR_DIRECT_MEM_TYPE_GRALLOC:
+ return mFlags & SENSOR_FLAG_DIRECT_CHANNEL_GRALLOC;
+ default:
+ return false;
+ }
+}
+
int32_t Sensor::getReportingMode() const {
return ((mFlags & REPORTING_MODE_MASK) >> REPORTING_MODE_SHIFT);
}
diff --git a/libs/gui/SensorManager.cpp b/libs/gui/SensorManager.cpp
index 57c3073..46eaf28 100644
--- a/libs/gui/SensorManager.cpp
+++ b/libs/gui/SensorManager.cpp
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <sys/types.h>
+#include <cutils/native_handle.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
#include <utils/Singleton.h>
@@ -89,7 +90,7 @@
}
SensorManager::SensorManager(const String16& opPackageName)
- : mSensorList(0), mOpPackageName(opPackageName) {
+ : mSensorList(0), mOpPackageName(opPackageName), mDirectConnectionHandle(1) {
// okay we're not locked here, but it's not needed during construction
assertStateLocked();
}
@@ -237,5 +238,62 @@
return false;
}
+int SensorManager::createDirectChannel(
+ size_t size, int channelType, const native_handle_t *resourceHandle) {
+ Mutex::Autolock _l(mLock);
+ if (assertStateLocked() != NO_ERROR) {
+ return NO_INIT;
+ }
+
+ switch (channelType) {
+ case SENSOR_DIRECT_MEM_TYPE_ASHMEM: {
+ sp<ISensorEventConnection> conn =
+ mSensorServer->createSensorDirectConnection(mOpPackageName,
+ static_cast<uint32_t>(size),
+ static_cast<int32_t>(channelType),
+ SENSOR_DIRECT_FMT_SENSORS_EVENT, resourceHandle);
+ if (conn == nullptr) {
+ return NO_MEMORY;
+ }
+ int nativeHandle = mDirectConnectionHandle++;
+ mDirectConnection.emplace(nativeHandle, conn);
+ return nativeHandle;
+ }
+ case SENSOR_DIRECT_MEM_TYPE_GRALLOC:
+ LOG_FATAL("%s: Finish implementation of ION and GRALLOC or remove", __FUNCTION__);
+ return BAD_VALUE;
+ default:
+ ALOGE("Bad channel shared memory type %d", channelType);
+ return BAD_VALUE;
+ }
+}
+
+void SensorManager::destroyDirectChannel(int channelNativeHandle) {
+ Mutex::Autolock _l(mLock);
+ if (assertStateLocked() == NO_ERROR) {
+ mDirectConnection.erase(channelNativeHandle);
+ }
+}
+
+int SensorManager::configureDirectChannel(int channelNativeHandle, int sensorHandle, int rateLevel) {
+ Mutex::Autolock _l(mLock);
+ if (assertStateLocked() != NO_ERROR) {
+ return NO_INIT;
+ }
+
+ auto i = mDirectConnection.find(channelNativeHandle);
+ if (i == mDirectConnection.end()) {
+ ALOGE("Cannot find the handle in client direct connection table");
+ return BAD_VALUE;
+ }
+
+ int ret;
+ ret = i->second->configureChannel(sensorHandle, rateLevel);
+ ALOGE_IF(ret < 0, "SensorManager::configureChannel (%d, %d) returns %d",
+ static_cast<int>(sensorHandle), static_cast<int>(rateLevel),
+ static_cast<int>(ret));
+ return ret;
+}
+
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 1e79e06..c859828 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -49,11 +49,11 @@
mAutoRefresh(false),
mSharedBufferSlot(BufferItem::INVALID_BUFFER_SLOT),
mSharedBufferHasBeenQueued(false),
- mNextFrameNumber(1),
mQueriedSupportedTimestamps(false),
mFrameTimestampsSupportsPresent(false),
mFrameTimestampsSupportsRetire(false),
- mEnableFrameTimestamps(false)
+ mEnableFrameTimestamps(false),
+ mFrameEventHistory(std::make_unique<ProducerFrameEventHistory>())
{
// Initialize the ANativeWindow function pointers.
ANativeWindow::setSwapInterval = hook_setSwapInterval;
@@ -97,6 +97,10 @@
}
}
+sp<ISurfaceComposer> Surface::composerService() const {
+ return ComposerService::getComposerService();
+}
+
sp<IGraphicBufferProducer> Surface::getIGraphicBufferProducer() const {
return mGraphicBufferProducer;
}
@@ -144,6 +148,43 @@
mEnableFrameTimestamps = enable;
}
+static bool checkConsumerForUpdates(
+ const FrameEvents* e, const uint64_t lastFrameNumber,
+ const nsecs_t* outLatchTime,
+ const nsecs_t* outFirstRefreshStartTime,
+ const nsecs_t* outLastRefreshStartTime,
+ const nsecs_t* outGlCompositionDoneTime,
+ const nsecs_t* outDisplayPresentTime,
+ const nsecs_t* outDisplayRetireTime,
+ const nsecs_t* outDequeueReadyTime,
+ const nsecs_t* outReleaseTime) {
+ bool checkForLatch = (outLatchTime != nullptr) && !e->hasLatchInfo();
+ bool checkForFirstRefreshStart = (outFirstRefreshStartTime != nullptr) &&
+ !e->hasFirstRefreshStartInfo();
+ bool checkForGlCompositionDone = (outGlCompositionDoneTime != nullptr) &&
+ !e->hasGpuCompositionDoneInfo();
+ bool checkForDisplayPresent = (outDisplayPresentTime != nullptr) &&
+ !e->hasDisplayPresentInfo();
+
+ // LastRefreshStart, DisplayRetire, DequeueReady, and Release are never
+ // available for the last frame.
+ bool checkForLastRefreshStart = (outLastRefreshStartTime != nullptr) &&
+ !e->hasLastRefreshStartInfo() &&
+ (e->frameNumber != lastFrameNumber);
+ bool checkForDisplayRetire = (outDisplayRetireTime != nullptr) &&
+ !e->hasDisplayRetireInfo() && (e->frameNumber != lastFrameNumber);
+ bool checkForDequeueReady = (outDequeueReadyTime != nullptr) &&
+ !e->hasDequeueReadyInfo() && (e->frameNumber != lastFrameNumber);
+ bool checkForRelease = (outReleaseTime != nullptr) &&
+ !e->hasReleaseInfo() && (e->frameNumber != lastFrameNumber);
+
+ // RequestedPresent and Acquire info are always available producer-side.
+ return checkForLatch || checkForFirstRefreshStart ||
+ checkForLastRefreshStart || checkForGlCompositionDone ||
+ checkForDisplayPresent || checkForDisplayRetire ||
+ checkForDequeueReady || checkForRelease;
+}
+
static void getFrameTimestamp(nsecs_t *dst, const nsecs_t& src) {
if (dst != nullptr) {
*dst = Fence::isValidTimestamp(src) ? src : 0;
@@ -159,9 +200,10 @@
status_t Surface::getFrameTimestamps(uint64_t frameNumber,
nsecs_t* outRequestedPresentTime, nsecs_t* outAcquireTime,
- nsecs_t* outRefreshStartTime, nsecs_t* outGlCompositionDoneTime,
+ nsecs_t* outLatchTime, nsecs_t* outFirstRefreshStartTime,
+ nsecs_t* outLastRefreshStartTime, nsecs_t* outGlCompositionDoneTime,
nsecs_t* outDisplayPresentTime, nsecs_t* outDisplayRetireTime,
- nsecs_t* outReleaseTime) {
+ nsecs_t* outDequeueReadyTime, nsecs_t* outReleaseTime) {
ATRACE_CALL();
Mutex::Autolock lock(mMutex);
@@ -179,30 +221,35 @@
return BAD_VALUE;
}
- FrameEvents* events = mFrameEventHistory.getFrame(frameNumber);
-
- // Update our cache of events if the requested events are not available.
- if (events == nullptr ||
- (outRequestedPresentTime && !events->hasRequestedPresentInfo()) ||
- (outAcquireTime && !events->hasAcquireInfo()) ||
- (outRefreshStartTime && !events->hasFirstRefreshStartInfo()) ||
- (outGlCompositionDoneTime && !events->hasGpuCompositionDoneInfo()) ||
- (outDisplayPresentTime && !events->hasDisplayPresentInfo()) ||
- (outDisplayRetireTime && !events->hasDisplayRetireInfo()) ||
- (outReleaseTime && !events->hasReleaseInfo())) {
- FrameEventHistoryDelta delta;
- mGraphicBufferProducer->getFrameTimestamps(&delta);
- mFrameEventHistory.applyDelta(delta);
- events = mFrameEventHistory.getFrame(frameNumber);
+ FrameEvents* events = mFrameEventHistory->getFrame(frameNumber);
+ if (events == nullptr) {
+ // If the entry isn't available in the producer, it's definitely not
+ // available in the consumer.
+ return NAME_NOT_FOUND;
}
- // A record for the requested frame does not exist.
+ // Update our cache of events if the requested events are not available.
+ if (checkConsumerForUpdates(events, mLastFrameNumber,
+ outLatchTime, outFirstRefreshStartTime, outLastRefreshStartTime,
+ outGlCompositionDoneTime, outDisplayPresentTime,
+ outDisplayRetireTime, outDequeueReadyTime, outReleaseTime)) {
+ FrameEventHistoryDelta delta;
+ mGraphicBufferProducer->getFrameTimestamps(&delta);
+ mFrameEventHistory->applyDelta(delta);
+ events = mFrameEventHistory->getFrame(frameNumber);
+ }
+
if (events == nullptr) {
+ // The entry was available before the update, but was overwritten
+ // after the update. Make sure not to send the wrong frame's data.
return NAME_NOT_FOUND;
}
getFrameTimestamp(outRequestedPresentTime, events->requestedPresentTime);
- getFrameTimestamp(outRefreshStartTime, events->firstRefreshStartTime);
+ getFrameTimestamp(outLatchTime, events->latchTime);
+ getFrameTimestamp(outFirstRefreshStartTime, events->firstRefreshStartTime);
+ getFrameTimestamp(outLastRefreshStartTime, events->lastRefreshStartTime);
+ getFrameTimestamp(outDequeueReadyTime, events->dequeueReadyTime);
getFrameTimestampFence(outAcquireTime, events->acquireFence);
getFrameTimestampFence(
@@ -347,11 +394,9 @@
nsecs_t now = systemTime();
FrameEventHistoryDelta frameTimestamps;
- FrameEventHistoryDelta* frameTimestampsOrNull =
- enableFrameTimestamps ? &frameTimestamps : nullptr;
-
status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence,
- reqWidth, reqHeight, reqFormat, reqUsage, frameTimestampsOrNull);
+ reqWidth, reqHeight, reqFormat, reqUsage,
+ enableFrameTimestamps ? &frameTimestamps : nullptr);
mLastDequeueDuration = systemTime() - now;
if (result < 0) {
@@ -373,7 +418,7 @@
}
if (enableFrameTimestamps) {
- mFrameEventHistory.applyDelta(frameTimestamps);
+ mFrameEventHistory->applyDelta(frameTimestamps);
}
if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
@@ -567,18 +612,20 @@
}
if (mEnableFrameTimestamps) {
- mFrameEventHistory.applyDelta(output.frameTimestamps);
+ mFrameEventHistory->applyDelta(output.frameTimestamps);
// Update timestamps with the local acquire fence.
// The consumer doesn't send it back to prevent us from having two
// file descriptors of the same fence.
- mFrameEventHistory.updateAcquireFence(mNextFrameNumber,
+ mFrameEventHistory->updateAcquireFence(mNextFrameNumber,
std::make_shared<FenceTime>(std::move(fence)));
// Cache timestamps of signaled fences so we can close their file
// descriptors.
- mFrameEventHistory.updateSignalTimes();
+ mFrameEventHistory->updateSignalTimes();
}
+ mLastFrameNumber = mNextFrameNumber;
+
mDefaultWidth = output.width;
mDefaultHeight = output.height;
mNextFrameNumber = output.nextFrameNumber;
@@ -613,8 +660,7 @@
mQueriedSupportedTimestamps = true;
std::vector<FrameEvent> supportedFrameTimestamps;
- sp<ISurfaceComposer> composer(ComposerService::getComposerService());
- status_t err = composer->getSupportedFrameTimestamps(
+ status_t err = composerService()->getSupportedFrameTimestamps(
&supportedFrameTimestamps);
if (err != NO_ERROR) {
@@ -643,9 +689,8 @@
}
break;
case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: {
- sp<ISurfaceComposer> composer(
- ComposerService::getComposerService());
- if (composer->authenticateSurfaceTexture(mGraphicBufferProducer)) {
+ if (composerService()->authenticateSurfaceTexture(
+ mGraphicBufferProducer)) {
*value = 1;
} else {
*value = 0;
@@ -913,15 +958,19 @@
uint32_t framesAgo = va_arg(args, uint32_t);
nsecs_t* outRequestedPresentTime = va_arg(args, int64_t*);
nsecs_t* outAcquireTime = va_arg(args, int64_t*);
- nsecs_t* outRefreshStartTime = va_arg(args, int64_t*);
+ nsecs_t* outLatchTime = va_arg(args, int64_t*);
+ nsecs_t* outFirstRefreshStartTime = va_arg(args, int64_t*);
+ nsecs_t* outLastRefreshStartTime = va_arg(args, int64_t*);
nsecs_t* outGlCompositionDoneTime = va_arg(args, int64_t*);
nsecs_t* outDisplayPresentTime = va_arg(args, int64_t*);
nsecs_t* outDisplayRetireTime = va_arg(args, int64_t*);
+ nsecs_t* outDequeueReadyTime = va_arg(args, int64_t*);
nsecs_t* outReleaseTime = va_arg(args, int64_t*);
return getFrameTimestamps(getNextFrameNumber() - 1 - framesAgo,
- outRequestedPresentTime, outAcquireTime, outRefreshStartTime,
+ outRequestedPresentTime, outAcquireTime, outLatchTime,
+ outFirstRefreshStartTime, outLastRefreshStartTime,
outGlCompositionDoneTime, outDisplayPresentTime,
- outDisplayRetireTime, outReleaseTime);
+ outDisplayRetireTime, outDequeueReadyTime, outReleaseTime);
}
int Surface::connect(int api) {
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 78afc76..58b2a87 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -33,6 +33,7 @@
#include <ui/DisplayInfo.h>
+#include <gui/BufferItemConsumer.h>
#include <gui/CpuConsumer.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/ISurfaceComposer.h>
@@ -859,6 +860,33 @@
reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform);
}
+status_t ScreenshotClient::captureToBuffer(const sp<IBinder>& display,
+ Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ, bool useIdentityTransform,
+ uint32_t rotation,
+ sp<GraphicBuffer>* outBuffer) {
+ sp<ISurfaceComposer> s(ComposerService::getComposerService());
+ if (s == NULL) return NO_INIT;
+
+ sp<IGraphicBufferConsumer> gbpConsumer;
+ sp<IGraphicBufferProducer> producer;
+ BufferQueue::createBufferQueue(&producer, &gbpConsumer);
+ sp<BufferItemConsumer> consumer(new BufferItemConsumer(gbpConsumer,
+ GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_NEVER,
+ 1, true));
+
+ status_t ret = s->captureScreen(display, producer, sourceCrop, reqWidth, reqHeight,
+ minLayerZ, maxLayerZ, useIdentityTransform,
+ static_cast<ISurfaceComposer::Rotation>(rotation));
+ if (ret != NO_ERROR) {
+ return ret;
+ }
+ BufferItem b;
+ consumer->acquireBuffer(&b, 0, true);
+ *outBuffer = b.mGraphicBuffer;
+ return ret;
+}
+
ScreenshotClient::ScreenshotClient()
: mHaveBuffer(false) {
memset(&mBuffer, 0, sizeof(mBuffer));
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 66e1bb6..e40b4eb 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -19,22 +19,28 @@
#include <gtest/gtest.h>
#include <binder/IMemory.h>
+#include <binder/ProcessState.h>
+#include <gui/IDisplayEventConnection.h>
#include <gui/ISurfaceComposer.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/BufferItemConsumer.h>
+#include <private/gui/ComposerService.h>
#include <ui/Rect.h>
#include <utils/String8.h>
-#include <private/gui/ComposerService.h>
-#include <binder/ProcessState.h>
-
+#include <limits>
#include <thread>
namespace android {
using namespace std::chrono_literals;
+class FakeSurfaceComposer;
+class FakeProducerFrameEventHistory;
+
+static constexpr uint64_t NO_FRAME_INDEX = std::numeric_limits<uint64_t>::max();
+
class SurfaceTest : public ::testing::Test {
protected:
@@ -102,7 +108,8 @@
BufferQueue::createBufferQueue(&producer, &consumer);
sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1);
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- sp<IBinder> display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ sp<IBinder> display(sf->getBuiltInDisplay(
+ ISurfaceComposer::eDisplayIdMain));
ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(),
64, 64, 0, 0x7fffffff, false));
@@ -272,4 +279,947 @@
ASSERT_EQ(NO_ERROR, window->queueBuffer(window.get(), buffer, fence));
}
+
+class FakeConsumer : public BnConsumerListener {
+public:
+ void onFrameAvailable(const BufferItem& /*item*/) override {}
+ void onBuffersReleased() override {}
+ void onSidebandStreamChanged() override {}
+
+ void addAndGetFrameTimestamps(
+ const NewFrameEventsEntry* newTimestamps,
+ FrameEventHistoryDelta* outDelta) override {
+ if (newTimestamps) {
+ if (mGetFrameTimestampsEnabled) {
+ EXPECT_GT(mNewFrameEntryOverride.frameNumber, 0u) <<
+ "Test should set mNewFrameEntryOverride before queuing "
+ "a frame.";
+ EXPECT_EQ(newTimestamps->frameNumber,
+ mNewFrameEntryOverride.frameNumber) <<
+ "Test attempting to add NewFrameEntryOverride with "
+ "incorrect frame number.";
+ mFrameEventHistory.addQueue(mNewFrameEntryOverride);
+ mNewFrameEntryOverride.frameNumber = 0;
+ }
+ mAddFrameTimestampsCount++;
+ mLastAddedFrameNumber = newTimestamps->frameNumber;
+ }
+ if (outDelta) {
+ mFrameEventHistory.getAndResetDelta(outDelta);
+ mGetFrameTimestampsCount++;
+ }
+ mAddAndGetFrameTimestampsCallCount++;
+ }
+
+ bool mGetFrameTimestampsEnabled = false;
+
+ ConsumerFrameEventHistory mFrameEventHistory;
+ int mAddAndGetFrameTimestampsCallCount = 0;
+ int mAddFrameTimestampsCount = 0;
+ int mGetFrameTimestampsCount = 0;
+ uint64_t mLastAddedFrameNumber = NO_FRAME_INDEX;
+
+ NewFrameEventsEntry mNewFrameEntryOverride = { 0, 0, 0, nullptr };
+};
+
+
+class FakeSurfaceComposer : public ISurfaceComposer{
+public:
+ ~FakeSurfaceComposer() override {}
+
+ void setSupportedTimestamps(bool supportsPresent, bool supportsRetire) {
+ mSupportsPresent = supportsPresent;
+ mSupportsRetire = supportsRetire;
+ }
+
+ sp<ISurfaceComposerClient> createConnection() override { return nullptr; }
+ sp<IGraphicBufferAlloc> createGraphicBufferAlloc() override {
+ return nullptr;
+ }
+ sp<IDisplayEventConnection> createDisplayEventConnection() override {
+ return nullptr;
+ }
+ sp<IBinder> createDisplay(const String8& /*displayName*/,
+ bool /*secure*/) override { return nullptr; }
+ void destroyDisplay(const sp<IBinder>& /*display */) override {}
+ sp<IBinder> getBuiltInDisplay(int32_t /*id*/) override { return nullptr; }
+ void setTransactionState(const Vector<ComposerState>& /*state*/,
+ const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/)
+ override {}
+ void bootFinished() override {}
+ bool authenticateSurfaceTexture(
+ const sp<IGraphicBufferProducer>& /*surface*/) const override {
+ return false;
+ }
+
+ status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported)
+ const override {
+ *outSupported = {
+ FrameEvent::REQUESTED_PRESENT,
+ FrameEvent::ACQUIRE,
+ FrameEvent::LATCH,
+ FrameEvent::FIRST_REFRESH_START,
+ FrameEvent::LAST_REFRESH_START,
+ FrameEvent::GL_COMPOSITION_DONE,
+ FrameEvent::DEQUEUE_READY,
+ FrameEvent::RELEASE
+ };
+ if (mSupportsPresent) {
+ outSupported->push_back(
+ FrameEvent::DISPLAY_PRESENT);
+ }
+ if (mSupportsRetire) {
+ outSupported->push_back(
+ FrameEvent::DISPLAY_RETIRE);
+ }
+ return NO_ERROR;
+ }
+
+ void setPowerMode(const sp<IBinder>& /*display*/, int /*mode*/) override {}
+ status_t getDisplayConfigs(const sp<IBinder>& /*display*/,
+ Vector<DisplayInfo>* /*configs*/) override { return NO_ERROR; }
+ status_t getDisplayStats(const sp<IBinder>& /*display*/,
+ DisplayStatInfo* /*stats*/) override { return NO_ERROR; }
+ int getActiveConfig(const sp<IBinder>& /*display*/) override { return 0; }
+ status_t setActiveConfig(const sp<IBinder>& /*display*/, int /*id*/)
+ override {
+ return NO_ERROR;
+ }
+ status_t getDisplayColorModes(const sp<IBinder>& /*display*/,
+ Vector<android_color_mode_t>* /*outColorModes*/) override {
+ return NO_ERROR;
+ }
+ android_color_mode_t getActiveColorMode(const sp<IBinder>& /*display*/)
+ override {
+ return HAL_COLOR_MODE_NATIVE;
+ }
+ status_t setActiveColorMode(const sp<IBinder>& /*display*/,
+ android_color_mode_t /*colorMode*/) override { return NO_ERROR; }
+ status_t captureScreen(const sp<IBinder>& /*display*/,
+ const sp<IGraphicBufferProducer>& /*producer*/,
+ Rect /*sourceCrop*/, uint32_t /*reqWidth*/, uint32_t /*reqHeight*/,
+ uint32_t /*minLayerZ*/, uint32_t /*maxLayerZ*/,
+ bool /*useIdentityTransform*/,
+ Rotation /*rotation*/) override { return NO_ERROR; }
+ status_t clearAnimationFrameStats() override { return NO_ERROR; }
+ status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override {
+ return NO_ERROR;
+ }
+ status_t getHdrCapabilities(const sp<IBinder>& /*display*/,
+ HdrCapabilities* /*outCapabilities*/) const override {
+ return NO_ERROR;
+ }
+ status_t enableVSyncInjections(bool /*enable*/) override {
+ return NO_ERROR;
+ }
+ status_t injectVSync(nsecs_t /*when*/) override { return NO_ERROR; }
+
+protected:
+ IBinder* onAsBinder() override { return nullptr; }
+
+private:
+ bool mSupportsPresent{true};
+ bool mSupportsRetire{true};
+};
+
+class FakeProducerFrameEventHistory : public ProducerFrameEventHistory {
+public:
+ FakeProducerFrameEventHistory(FenceToFenceTimeMap* fenceMap)
+ : mFenceMap(fenceMap) {}
+
+ ~FakeProducerFrameEventHistory() {}
+
+ void updateAcquireFence(uint64_t frameNumber,
+ std::shared_ptr<FenceTime>&& acquire) override {
+ // Verify the acquire fence being added isn't the one from the consumer.
+ EXPECT_NE(mConsumerAcquireFence, acquire);
+ // Override the fence, so we can verify this was called by the
+ // producer after the frame is queued.
+ ProducerFrameEventHistory::updateAcquireFence(frameNumber,
+ std::shared_ptr<FenceTime>(mAcquireFenceOverride));
+ }
+
+ void setAcquireFenceOverride(
+ const std::shared_ptr<FenceTime>& acquireFenceOverride,
+ const std::shared_ptr<FenceTime>& consumerAcquireFence) {
+ mAcquireFenceOverride = acquireFenceOverride;
+ mConsumerAcquireFence = consumerAcquireFence;
+ }
+
+protected:
+ std::shared_ptr<FenceTime> createFenceTime(const sp<Fence>& fence)
+ const override {
+ return mFenceMap->createFenceTimeForTest(fence);
+ }
+
+ FenceToFenceTimeMap* mFenceMap{nullptr};
+
+ std::shared_ptr<FenceTime> mAcquireFenceOverride{FenceTime::NO_FENCE};
+ std::shared_ptr<FenceTime> mConsumerAcquireFence{FenceTime::NO_FENCE};
+};
+
+
+class TestSurface : public Surface {
+public:
+ TestSurface(const sp<IGraphicBufferProducer>& bufferProducer,
+ FenceToFenceTimeMap* fenceMap)
+ : Surface(bufferProducer),
+ mFakeSurfaceComposer(new FakeSurfaceComposer) {
+ mFakeFrameEventHistory = new FakeProducerFrameEventHistory(fenceMap);
+ mFrameEventHistory.reset(mFakeFrameEventHistory);
+ }
+
+ ~TestSurface() override {}
+
+ sp<ISurfaceComposer> composerService() const override {
+ return mFakeSurfaceComposer;
+ }
+
+public:
+ sp<FakeSurfaceComposer> mFakeSurfaceComposer;
+
+ // mFrameEventHistory owns the instance of FakeProducerFrameEventHistory,
+ // but this raw pointer gives access to test functionality.
+ FakeProducerFrameEventHistory* mFakeFrameEventHistory;
+};
+
+
+class GetFrameTimestampsTest : public SurfaceTest {
+protected:
+ struct FenceAndFenceTime {
+ explicit FenceAndFenceTime(FenceToFenceTimeMap& fenceMap)
+ : mFence(new Fence),
+ mFenceTime(fenceMap.createFenceTimeForTest(mFence)) {}
+ sp<Fence> mFence { nullptr };
+ std::shared_ptr<FenceTime> mFenceTime { nullptr };
+ };
+
+ struct RefreshEvents {
+ RefreshEvents(FenceToFenceTimeMap& fenceMap, nsecs_t refreshStart)
+ : mFenceMap(fenceMap),
+ kStartTime(refreshStart + 1),
+ kGpuCompositionDoneTime(refreshStart + 2),
+ kPresentTime(refreshStart + 3) {}
+
+ void signalPostCompositeFences() {
+ mFenceMap.signalAllForTest(
+ mGpuCompositionDone.mFence, kGpuCompositionDoneTime);
+ mFenceMap.signalAllForTest(mPresent.mFence, kPresentTime);
+ }
+
+ FenceToFenceTimeMap& mFenceMap;
+
+ FenceAndFenceTime mGpuCompositionDone { mFenceMap };
+ FenceAndFenceTime mPresent { mFenceMap };
+
+ const nsecs_t kStartTime;
+ const nsecs_t kGpuCompositionDoneTime;
+ const nsecs_t kPresentTime;
+ };
+
+ struct FrameEvents {
+ FrameEvents(FenceToFenceTimeMap& fenceMap, nsecs_t frameStartTime)
+ : mFenceMap(fenceMap),
+ kPostedTime(frameStartTime + 100),
+ kRequestedPresentTime(frameStartTime + 200),
+ kProducerAcquireTime(frameStartTime + 300),
+ kConsumerAcquireTime(frameStartTime + 301),
+ kLatchTime(frameStartTime + 500),
+ kDequeueReadyTime(frameStartTime + 600),
+ kRetireTime(frameStartTime + 700),
+ kReleaseTime(frameStartTime + 800),
+ mRefreshes {
+ { mFenceMap, frameStartTime + 410 },
+ { mFenceMap, frameStartTime + 420 },
+ { mFenceMap, frameStartTime + 430 } } {}
+
+ void signalQueueFences() {
+ mFenceMap.signalAllForTest(
+ mAcquireConsumer.mFence, kConsumerAcquireTime);
+ mFenceMap.signalAllForTest(
+ mAcquireProducer.mFence, kProducerAcquireTime);
+ }
+
+ void signalRefreshFences() {
+ for (auto& re : mRefreshes) {
+ re.signalPostCompositeFences();
+ }
+ }
+
+ void signalReleaseFences() {
+ mFenceMap.signalAllForTest(mRetire.mFence, kRetireTime);
+ mFenceMap.signalAllForTest(mRelease.mFence, kReleaseTime);
+ }
+
+ FenceToFenceTimeMap& mFenceMap;
+
+ FenceAndFenceTime mAcquireConsumer { mFenceMap };
+ FenceAndFenceTime mAcquireProducer { mFenceMap };
+ FenceAndFenceTime mRetire { mFenceMap };
+ FenceAndFenceTime mRelease { mFenceMap };
+
+ const nsecs_t kPostedTime;
+ const nsecs_t kRequestedPresentTime;
+ const nsecs_t kProducerAcquireTime;
+ const nsecs_t kConsumerAcquireTime;
+ const nsecs_t kLatchTime;
+ const nsecs_t kDequeueReadyTime;
+ const nsecs_t kRetireTime;
+ const nsecs_t kReleaseTime;
+
+ RefreshEvents mRefreshes[3];
+ };
+
+ GetFrameTimestampsTest() : SurfaceTest() {}
+
+ virtual void SetUp() {
+ SurfaceTest::SetUp();
+
+ BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+ mFakeConsumer = new FakeConsumer;
+ mCfeh = &mFakeConsumer->mFrameEventHistory;
+ mConsumer->consumerConnect(mFakeConsumer, false);
+ mConsumer->setConsumerName(String8("TestConsumer"));
+ mSurface = new TestSurface(mProducer, &mFenceMap);
+ mWindow = mSurface;
+
+ ASSERT_EQ(NO_ERROR, native_window_api_connect(mWindow.get(),
+ NATIVE_WINDOW_API_CPU));
+ native_window_set_buffer_count(mWindow.get(), 4);
+ }
+
+ void enableFrameTimestamps() {
+ mFakeConsumer->mGetFrameTimestampsEnabled = true;
+ native_window_enable_frame_timestamps(mWindow.get(), 1);
+ mFrameTimestampsEnabled = true;
+ }
+
+ int getAllFrameTimestamps(uint32_t framesAgo) {
+ return native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+ &outRequestedPresentTime, &outAcquireTime, &outLatchTime,
+ &outFirstRefreshStartTime, &outLastRefreshStartTime,
+ &outGpuCompositionDoneTime, &outDisplayPresentTime,
+ &outDisplayRetireTime, &outDequeueReadyTime, &outReleaseTime);
+ }
+
+ void resetTimestamps() {
+ outRequestedPresentTime = -1;
+ outAcquireTime = -1;
+ outLatchTime = -1;
+ outFirstRefreshStartTime = -1;
+ outLastRefreshStartTime = -1;
+ outGpuCompositionDoneTime = -1;
+ outDisplayPresentTime = -1;
+ outDisplayRetireTime = -1;
+ outDequeueReadyTime = -1;
+ outReleaseTime = -1;
+ }
+
+ void dequeueAndQueue(uint64_t frameIndex) {
+ int fence = -1;
+ ANativeWindowBuffer* buffer = nullptr;
+ ASSERT_EQ(NO_ERROR,
+ mWindow->dequeueBuffer(mWindow.get(), &buffer, &fence));
+
+ int oldAddFrameTimestampsCount =
+ mFakeConsumer->mAddFrameTimestampsCount;
+
+ FrameEvents* frame = &mFrames[frameIndex];
+ uint64_t frameNumber = frameIndex + 1;
+
+ NewFrameEventsEntry fe;
+ fe.frameNumber = frameNumber;
+ fe.postedTime = frame->kPostedTime;
+ fe.requestedPresentTime = frame->kRequestedPresentTime;
+ fe.acquireFence = frame->mAcquireConsumer.mFenceTime;
+ mFakeConsumer->mNewFrameEntryOverride = fe;
+
+ mSurface->mFakeFrameEventHistory->setAcquireFenceOverride(
+ frame->mAcquireProducer.mFenceTime,
+ frame->mAcquireConsumer.mFenceTime);
+
+ ASSERT_EQ(NO_ERROR, mWindow->queueBuffer(mWindow.get(), buffer, fence));
+
+ EXPECT_EQ(frameNumber, mFakeConsumer->mLastAddedFrameNumber);
+
+ EXPECT_EQ(
+ oldAddFrameTimestampsCount + (mFrameTimestampsEnabled ? 1 : 0),
+ mFakeConsumer->mAddFrameTimestampsCount);
+ }
+
+ void addFrameEvents(
+ bool gpuComposited, uint64_t iOldFrame, int64_t iNewFrame) {
+ FrameEvents* oldFrame =
+ (iOldFrame == NO_FRAME_INDEX) ? nullptr : &mFrames[iOldFrame];
+ FrameEvents* newFrame = &mFrames[iNewFrame];
+
+ uint64_t nOldFrame = iOldFrame + 1;
+ uint64_t nNewFrame = iNewFrame + 1;
+
+ // Latch, Composite, Retire, and Release the frames in a plausible
+ // order. Note: The timestamps won't necessarily match the order, but
+ // that's okay for the purposes of this test.
+ std::shared_ptr<FenceTime> gpuDoneFenceTime = FenceTime::NO_FENCE;
+
+ // Composite the previous frame one more time, which helps verify
+ // LastRefresh is updated properly.
+ if (oldFrame != nullptr) {
+ mCfeh->addPreComposition(nOldFrame,
+ oldFrame->mRefreshes[2].kStartTime);
+ gpuDoneFenceTime = gpuComposited ?
+ oldFrame->mRefreshes[2].mGpuCompositionDone.mFenceTime :
+ FenceTime::NO_FENCE;
+ mCfeh->addPostComposition(nOldFrame, gpuDoneFenceTime,
+ oldFrame->mRefreshes[2].mPresent.mFenceTime);
+ }
+
+ // Latch the new frame.
+ mCfeh->addLatch(nNewFrame, newFrame->kLatchTime);
+
+ mCfeh->addPreComposition(nNewFrame, newFrame->mRefreshes[0].kStartTime);
+ gpuDoneFenceTime = gpuComposited ?
+ newFrame->mRefreshes[0].mGpuCompositionDone.mFenceTime :
+ FenceTime::NO_FENCE;
+ // HWC2 releases the previous buffer after a new latch just before
+ // calling postComposition.
+ if (oldFrame != nullptr) {
+ mCfeh->addRelease(nOldFrame, oldFrame->kDequeueReadyTime,
+ std::shared_ptr<FenceTime>(oldFrame->mRelease.mFenceTime));
+ }
+ mCfeh->addPostComposition(nNewFrame, gpuDoneFenceTime,
+ newFrame->mRefreshes[0].mPresent.mFenceTime);
+
+ // Retire the previous buffer just after compositing the new buffer.
+ if (oldFrame != nullptr) {
+ mCfeh->addRetire(nOldFrame, oldFrame->mRetire.mFenceTime);
+ }
+
+ mCfeh->addPreComposition(nNewFrame, newFrame->mRefreshes[1].kStartTime);
+ gpuDoneFenceTime = gpuComposited ?
+ newFrame->mRefreshes[1].mGpuCompositionDone.mFenceTime :
+ FenceTime::NO_FENCE;
+ mCfeh->addPostComposition(nNewFrame, gpuDoneFenceTime,
+ newFrame->mRefreshes[1].mPresent.mFenceTime);
+ }
+
+ void QueryPresentRetireSupported(
+ bool displayPresentSupported, bool displayRetireSupported);
+ void PresentOrRetireUnsupportedNoSyncTest(
+ bool displayPresentSupported, bool displayRetireSupported);
+
+ sp<IGraphicBufferProducer> mProducer;
+ sp<IGraphicBufferConsumer> mConsumer;
+ sp<FakeConsumer> mFakeConsumer;
+ ConsumerFrameEventHistory* mCfeh;
+ sp<TestSurface> mSurface;
+ sp<ANativeWindow> mWindow;
+
+ FenceToFenceTimeMap mFenceMap;
+
+ bool mFrameTimestampsEnabled = false;
+
+ int64_t outRequestedPresentTime = -1;
+ int64_t outAcquireTime = -1;
+ int64_t outLatchTime = -1;
+ int64_t outFirstRefreshStartTime = -1;
+ int64_t outLastRefreshStartTime = -1;
+ int64_t outGpuCompositionDoneTime = -1;
+ int64_t outDisplayPresentTime = -1;
+ int64_t outDisplayRetireTime = -1;
+ int64_t outDequeueReadyTime = -1;
+ int64_t outReleaseTime = -1;
+
+ FrameEvents mFrames[2] { { mFenceMap, 1000 }, { mFenceMap, 2000 } };
+};
+
+
+// This test verifies that the frame timestamps are not retrieved when not
+// explicitly enabled via native_window_enable_frame_timestamps.
+// We want to check this to make sure there's no overhead for users
+// that don't need the timestamp information.
+TEST_F(GetFrameTimestampsTest, DefaultDisabled) {
+ int fence;
+ ANativeWindowBuffer* buffer;
+
+ EXPECT_EQ(0, mFakeConsumer->mAddFrameTimestampsCount);
+ EXPECT_EQ(0, mFakeConsumer->mGetFrameTimestampsCount);
+
+ // Verify the producer doesn't get frame timestamps piggybacked on dequeue.
+ ASSERT_EQ(NO_ERROR, mWindow->dequeueBuffer(mWindow.get(), &buffer, &fence));
+ EXPECT_EQ(0, mFakeConsumer->mAddFrameTimestampsCount);
+ EXPECT_EQ(0, mFakeConsumer->mGetFrameTimestampsCount);
+
+ // Verify the producer doesn't get frame timestamps piggybacked on queue.
+ // It is okay that frame timestamps are added in the consumer since it is
+ // still needed for SurfaceFlinger dumps.
+ ASSERT_EQ(NO_ERROR, mWindow->queueBuffer(mWindow.get(), buffer, fence));
+ EXPECT_EQ(1, mFakeConsumer->mAddFrameTimestampsCount);
+ EXPECT_EQ(0, mFakeConsumer->mGetFrameTimestampsCount);
+
+ // Verify attempts to get frame timestamps fail.
+ const uint32_t framesAgo = 0;
+ int result = getAllFrameTimestamps(framesAgo);
+ EXPECT_EQ(INVALID_OPERATION, result);
+ EXPECT_EQ(0, mFakeConsumer->mGetFrameTimestampsCount);
+}
+
+// This test verifies that the frame timestamps are retrieved if explicitly
+// enabled via native_window_enable_frame_timestamps.
+TEST_F(GetFrameTimestampsTest, EnabledSimple) {
+ enableFrameTimestamps();
+
+ int fence;
+ ANativeWindowBuffer* buffer;
+
+ EXPECT_EQ(0, mFakeConsumer->mAddFrameTimestampsCount);
+ EXPECT_EQ(0, mFakeConsumer->mGetFrameTimestampsCount);
+
+ // Verify getFrameTimestamps is piggybacked on dequeue.
+ ASSERT_EQ(NO_ERROR, mWindow->dequeueBuffer(mWindow.get(), &buffer, &fence));
+ EXPECT_EQ(0, mFakeConsumer->mAddFrameTimestampsCount);
+ EXPECT_EQ(1, mFakeConsumer->mGetFrameTimestampsCount);
+
+ NewFrameEventsEntry f1;
+ f1.frameNumber = 1;
+ f1.postedTime = mFrames[0].kPostedTime;
+ f1.requestedPresentTime = mFrames[0].kRequestedPresentTime;
+ f1.acquireFence = mFrames[0].mAcquireConsumer.mFenceTime;
+ mSurface->mFakeFrameEventHistory->setAcquireFenceOverride(
+ mFrames[0].mAcquireProducer.mFenceTime,
+ mFrames[0].mAcquireConsumer.mFenceTime);
+ mFakeConsumer->mNewFrameEntryOverride = f1;
+ mFrames[0].signalQueueFences();
+
+ // Verify getFrameTimestamps is piggybacked on queue.
+ ASSERT_EQ(NO_ERROR, mWindow->queueBuffer(mWindow.get(), buffer, fence));
+ EXPECT_EQ(1, mFakeConsumer->mAddFrameTimestampsCount);
+ EXPECT_EQ(1u, mFakeConsumer->mLastAddedFrameNumber);
+ EXPECT_EQ(2, mFakeConsumer->mGetFrameTimestampsCount);
+
+ // Verify queries for timestamps that the producer doesn't know about
+ // triggers a call to see if the consumer has any new timestamps.
+ const uint32_t framesAgo = 0;
+ int result = getAllFrameTimestamps(framesAgo);
+ EXPECT_EQ(NO_ERROR, result);
+ EXPECT_EQ(3, mFakeConsumer->mGetFrameTimestampsCount);
+}
+
+void GetFrameTimestampsTest::QueryPresentRetireSupported(
+ bool displayPresentSupported, bool displayRetireSupported) {
+ mSurface->mFakeSurfaceComposer->setSupportedTimestamps(
+ displayPresentSupported, displayRetireSupported);
+
+ // Verify supported bits are forwarded.
+ int supportsPresent = -1;
+ mWindow.get()->query(mWindow.get(),
+ NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT, &supportsPresent);
+ EXPECT_EQ(displayPresentSupported, supportsPresent);
+
+ int supportsRetire = -1;
+ mWindow.get()->query(mWindow.get(),
+ NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_RETIRE, &supportsRetire);
+ EXPECT_EQ(displayRetireSupported, supportsRetire);
+}
+
+TEST_F(GetFrameTimestampsTest, QueryPresentSupported) {
+ QueryPresentRetireSupported(true, false);
+}
+
+TEST_F(GetFrameTimestampsTest, QueryRetireSupported) {
+ QueryPresentRetireSupported(false, true);
+}
+
+// This test verifies that:
+// 1) The timestamps recorded in the consumer's FrameTimestampsHistory are
+// properly retrieved by the producer for the correct frames.
+// 2) When framesAgo is 0, it is querying for the most recently queued frame.
+TEST_F(GetFrameTimestampsTest, TimestampsAssociatedWithCorrectFrame) {
+ enableFrameTimestamps();
+
+ dequeueAndQueue(0);
+ mFrames[0].signalQueueFences();
+
+ dequeueAndQueue(1);
+ mFrames[1].signalQueueFences();
+
+ addFrameEvents(true, NO_FRAME_INDEX, 0);
+ mFrames[0].signalRefreshFences();
+ addFrameEvents(true, 0, 1);
+ mFrames[0].signalReleaseFences();
+ mFrames[1].signalRefreshFences();
+
+ // Verify timestamps are correct for frame 1.
+ uint32_t framesAgo = 1;
+ resetTimestamps();
+ int result = getAllFrameTimestamps(framesAgo);
+ EXPECT_EQ(NO_ERROR, result);
+ EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
+ EXPECT_EQ(mFrames[0].kProducerAcquireTime, outAcquireTime);
+ EXPECT_EQ(mFrames[0].kLatchTime, outLatchTime);
+ EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
+ EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
+ EXPECT_EQ(mFrames[0].mRefreshes[0].kGpuCompositionDoneTime,
+ outGpuCompositionDoneTime);
+ EXPECT_EQ(mFrames[0].mRefreshes[0].kPresentTime, outDisplayPresentTime);
+ EXPECT_EQ(mFrames[0].kRetireTime, outDisplayRetireTime);
+ EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
+ EXPECT_EQ(mFrames[0].kReleaseTime, outReleaseTime);
+
+ // Verify timestamps are correct for frame 2.
+ framesAgo = 0;
+ resetTimestamps();
+ result = getAllFrameTimestamps(framesAgo);
+ EXPECT_EQ(NO_ERROR, result);
+ EXPECT_EQ(mFrames[1].kRequestedPresentTime, outRequestedPresentTime);
+ EXPECT_EQ(mFrames[1].kProducerAcquireTime, outAcquireTime);
+ EXPECT_EQ(mFrames[1].kLatchTime, outLatchTime);
+ EXPECT_EQ(mFrames[1].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
+ EXPECT_EQ(mFrames[1].mRefreshes[1].kStartTime, outLastRefreshStartTime);
+ EXPECT_EQ(mFrames[1].mRefreshes[0].kGpuCompositionDoneTime,
+ outGpuCompositionDoneTime);
+ EXPECT_EQ(mFrames[1].mRefreshes[0].kPresentTime, outDisplayPresentTime);
+ EXPECT_EQ(0, outDisplayRetireTime);
+ EXPECT_EQ(0, outDequeueReadyTime);
+ EXPECT_EQ(0, outReleaseTime);
+}
+
+// This test verifies the acquire fence recorded by the consumer is not sent
+// back to the producer and the producer saves its own fence.
+TEST_F(GetFrameTimestampsTest, QueueTimestampsNoSync) {
+ enableFrameTimestamps();
+ mSurface->mFakeSurfaceComposer->setSupportedTimestamps(true, true);
+
+ const uint32_t framesAgo = 0;
+
+ // Dequeue and queue frame 1.
+ dequeueAndQueue(0);
+
+ // Verify queue-related timestamps for f1 are available immediately in the
+ // producer without asking the consumer again, even before signaling the
+ // acquire fence.
+ resetTimestamps();
+ int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+ int result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+ &outRequestedPresentTime, &outAcquireTime, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
+ EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+ EXPECT_EQ(NO_ERROR, result);
+ EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
+ EXPECT_EQ(0, outAcquireTime);
+
+ // Signal acquire fences. Verify a sync call still isn't necessary.
+ mFrames[0].signalQueueFences();
+
+ oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+ result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+ &outRequestedPresentTime, &outAcquireTime, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
+ EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+ EXPECT_EQ(NO_ERROR, result);
+ EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
+ EXPECT_EQ(mFrames[0].kProducerAcquireTime, outAcquireTime);
+
+ // Dequeue and queue frame 2.
+ dequeueAndQueue(1);
+
+ // Verify queue-related timestamps for f2 are available immediately in the
+ // producer without asking the consumer again, even before signaling the
+ // acquire fence.
+ resetTimestamps();
+ oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+ result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+ &outRequestedPresentTime, &outAcquireTime, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
+ EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+ EXPECT_EQ(NO_ERROR, result);
+ EXPECT_EQ(mFrames[1].kRequestedPresentTime, outRequestedPresentTime);
+ EXPECT_EQ(0, outAcquireTime);
+
+ // Signal acquire fences. Verify a sync call still isn't necessary.
+ mFrames[1].signalQueueFences();
+
+ oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+ result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+ &outRequestedPresentTime, &outAcquireTime, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
+ EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+ EXPECT_EQ(NO_ERROR, result);
+ EXPECT_EQ(mFrames[1].kRequestedPresentTime, outRequestedPresentTime);
+ EXPECT_EQ(mFrames[1].kProducerAcquireTime, outAcquireTime);
+}
+
+TEST_F(GetFrameTimestampsTest, ZeroRequestedTimestampsNoSync) {
+ enableFrameTimestamps();
+ mSurface->mFakeSurfaceComposer->setSupportedTimestamps(true, true);
+
+ // Dequeue and queue frame 1.
+ dequeueAndQueue(0);
+ mFrames[0].signalQueueFences();
+
+ // Dequeue and queue frame 2.
+ dequeueAndQueue(1);
+ mFrames[1].signalQueueFences();
+
+ addFrameEvents(true, NO_FRAME_INDEX, 0);
+ mFrames[0].signalRefreshFences();
+ addFrameEvents(true, 0, 1);
+ mFrames[0].signalReleaseFences();
+ mFrames[1].signalRefreshFences();
+
+ // Verify a request for no timestamps doesn't result in a sync call.
+ const uint32_t framesAgo = 0;
+ int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+ int result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr);
+ EXPECT_EQ(NO_ERROR, result);
+ EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+}
+
+// This test verifies that fences can signal and update timestamps producer
+// side without an additional sync call to the consumer.
+TEST_F(GetFrameTimestampsTest, FencesInProducerNoSync) {
+ enableFrameTimestamps();
+ mSurface->mFakeSurfaceComposer->setSupportedTimestamps(true, true);
+
+ // Dequeue and queue frame 1.
+ dequeueAndQueue(0);
+ mFrames[0].signalQueueFences();
+
+ // Dequeue and queue frame 2.
+ dequeueAndQueue(1);
+ mFrames[1].signalQueueFences();
+
+ addFrameEvents(true, NO_FRAME_INDEX, 0);
+ addFrameEvents(true, 0, 1);
+
+ // Verify available timestamps are correct for frame 1, before any
+ // fence has been signaled.
+ // Note: A sync call is necessary here since the events triggered by
+ // addFrameEvents didn't get to piggyback on the earlier queues/dequeues.
+ uint32_t framesAgo = 1;
+ resetTimestamps();
+ int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+ int result = getAllFrameTimestamps(framesAgo);
+ EXPECT_EQ(oldCount + 1, mFakeConsumer->mGetFrameTimestampsCount);
+ EXPECT_EQ(NO_ERROR, result);
+ EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
+ EXPECT_EQ(mFrames[0].kProducerAcquireTime, outAcquireTime);
+ EXPECT_EQ(mFrames[0].kLatchTime, outLatchTime);
+ EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
+ EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
+ EXPECT_EQ(0, outGpuCompositionDoneTime);
+ EXPECT_EQ(0, outDisplayPresentTime);
+ EXPECT_EQ(0, outDisplayRetireTime);
+ EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
+ EXPECT_EQ(0, outReleaseTime);
+
+ // Verify available timestamps are correct for frame 1 again, before any
+ // fence has been signaled.
+ // This time a sync call should not be necessary.
+ framesAgo = 1;
+ resetTimestamps();
+ oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+ result = getAllFrameTimestamps(framesAgo);
+ EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+ EXPECT_EQ(NO_ERROR, result);
+ EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
+ EXPECT_EQ(mFrames[0].kProducerAcquireTime, outAcquireTime);
+ EXPECT_EQ(mFrames[0].kLatchTime, outLatchTime);
+ EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
+ EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
+ EXPECT_EQ(0, outGpuCompositionDoneTime);
+ EXPECT_EQ(0, outDisplayPresentTime);
+ EXPECT_EQ(0, outDisplayRetireTime);
+ EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
+ EXPECT_EQ(0, outReleaseTime);
+
+ // Signal the fences for frame 1.
+ mFrames[0].signalRefreshFences();
+ mFrames[0].signalReleaseFences();
+
+ // Verify all timestamps are available without a sync call.
+ framesAgo = 1;
+ resetTimestamps();
+ oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+ result = getAllFrameTimestamps(framesAgo);
+ EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+ EXPECT_EQ(NO_ERROR, result);
+ EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
+ EXPECT_EQ(mFrames[0].kProducerAcquireTime, outAcquireTime);
+ EXPECT_EQ(mFrames[0].kLatchTime, outLatchTime);
+ EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
+ EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
+ EXPECT_EQ(mFrames[0].mRefreshes[0].kGpuCompositionDoneTime,
+ outGpuCompositionDoneTime);
+ EXPECT_EQ(mFrames[0].mRefreshes[0].kPresentTime, outDisplayPresentTime);
+ EXPECT_EQ(mFrames[0].kRetireTime, outDisplayRetireTime);
+ EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
+ EXPECT_EQ(mFrames[0].kReleaseTime, outReleaseTime);
+}
+
+// This test verifies that if the frame wasn't GPU composited but has a refresh
+// event a sync call isn't made to get the GPU composite done time since it will
+// never exist.
+TEST_F(GetFrameTimestampsTest, NoGpuNoSync) {
+ enableFrameTimestamps();
+ mSurface->mFakeSurfaceComposer->setSupportedTimestamps(true, true);
+
+ const uint32_t framesAgo = 1;
+
+ // Dequeue and queue frame 1.
+ dequeueAndQueue(0);
+ mFrames[0].signalQueueFences();
+
+ // Dequeue and queue frame 2.
+ dequeueAndQueue(1);
+ mFrames[1].signalQueueFences();
+
+ addFrameEvents(false, NO_FRAME_INDEX, 0);
+ addFrameEvents(false, 0, 1);
+
+ // Verify available timestamps are correct for frame 1, before any
+ // fence has been signaled.
+ // Note: A sync call is necessary here since the events triggered by
+ // addFrameEvents didn't get to piggyback on the earlier queues/dequeues.
+ resetTimestamps();
+ int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+ int result = getAllFrameTimestamps(framesAgo);
+ EXPECT_EQ(oldCount + 1, mFakeConsumer->mGetFrameTimestampsCount);
+ EXPECT_EQ(NO_ERROR, result);
+ EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
+ EXPECT_EQ(mFrames[0].kProducerAcquireTime, outAcquireTime);
+ EXPECT_EQ(mFrames[0].kLatchTime, outLatchTime);
+ EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
+ EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
+ EXPECT_EQ(0, outGpuCompositionDoneTime);
+ EXPECT_EQ(0, outDisplayPresentTime);
+ EXPECT_EQ(0, outDisplayRetireTime);
+ EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
+ EXPECT_EQ(0, outReleaseTime);
+
+ // Signal the fences for frame 1.
+ mFrames[0].signalRefreshFences();
+ mFrames[0].signalReleaseFences();
+
+ // Verify all timestamps, except GPU composition, are available without a
+ // sync call.
+ resetTimestamps();
+ oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+ result = getAllFrameTimestamps(framesAgo);
+ EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+ EXPECT_EQ(NO_ERROR, result);
+ EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
+ EXPECT_EQ(mFrames[0].kProducerAcquireTime, outAcquireTime);
+ EXPECT_EQ(mFrames[0].kLatchTime, outLatchTime);
+ EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
+ EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
+ EXPECT_EQ(0, outGpuCompositionDoneTime);
+ EXPECT_EQ(mFrames[0].mRefreshes[0].kPresentTime, outDisplayPresentTime);
+ EXPECT_EQ(mFrames[0].kRetireTime, outDisplayRetireTime);
+ EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
+ EXPECT_EQ(mFrames[0].kReleaseTime, outReleaseTime);
+}
+
+// This test verifies that if the certain timestamps can't possibly exist for
+// the most recent frame, then a sync call is not done.
+TEST_F(GetFrameTimestampsTest, NoRetireOrReleaseNoSync) {
+ enableFrameTimestamps();
+ mSurface->mFakeSurfaceComposer->setSupportedTimestamps(true, true);
+
+ // Dequeue and queue frame 1.
+ dequeueAndQueue(0);
+ mFrames[0].signalQueueFences();
+
+ // Dequeue and queue frame 2.
+ dequeueAndQueue(1);
+ mFrames[1].signalQueueFences();
+
+ addFrameEvents(false, NO_FRAME_INDEX, 0);
+ addFrameEvents(false, 0, 1);
+
+ // Verify available timestamps are correct for frame 1, before any
+ // fence has been signaled.
+ // Note: A sync call is necessary here since the events triggered by
+ // addFrameEvents didn't get to piggyback on the earlier queues/dequeues.
+ uint32_t framesAgo = 1;
+ resetTimestamps();
+ int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+ int result = getAllFrameTimestamps(framesAgo);
+ EXPECT_EQ(oldCount + 1, mFakeConsumer->mGetFrameTimestampsCount);
+ EXPECT_EQ(NO_ERROR, result);
+ EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
+ EXPECT_EQ(mFrames[0].kProducerAcquireTime, outAcquireTime);
+ EXPECT_EQ(mFrames[0].kLatchTime, outLatchTime);
+ EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
+ EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
+ EXPECT_EQ(0, outGpuCompositionDoneTime);
+ EXPECT_EQ(0, outDisplayPresentTime);
+ EXPECT_EQ(0, outDisplayRetireTime);
+ EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
+ EXPECT_EQ(0, outReleaseTime);
+
+ mFrames[0].signalRefreshFences();
+ mFrames[0].signalReleaseFences();
+ mFrames[1].signalRefreshFences();
+
+ // Verify querying for all timestmaps of f2 does not do a sync call.
+ // Even though the lastRefresh, retire, dequeueReady, and release times aren't
+ // available, a sync call should not occur because it's not possible for f2
+ // to encounter the final value for those events until another frame is
+ // queued.
+ framesAgo = 0;
+ resetTimestamps();
+ oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+ result = getAllFrameTimestamps(framesAgo);
+ EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+ EXPECT_EQ(NO_ERROR, result);
+ EXPECT_EQ(mFrames[1].kRequestedPresentTime, outRequestedPresentTime);
+ EXPECT_EQ(mFrames[1].kProducerAcquireTime, outAcquireTime);
+ EXPECT_EQ(mFrames[1].kLatchTime, outLatchTime);
+ EXPECT_EQ(mFrames[1].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
+ EXPECT_EQ(mFrames[1].mRefreshes[1].kStartTime, outLastRefreshStartTime);
+ EXPECT_EQ(0, outGpuCompositionDoneTime);
+ EXPECT_EQ(mFrames[1].mRefreshes[0].kPresentTime, outDisplayPresentTime);
+ EXPECT_EQ(0, outDisplayRetireTime);
+ EXPECT_EQ(0, outDequeueReadyTime);
+ EXPECT_EQ(0, outReleaseTime);
+}
+
+// This test verifies there are no sync calls for present or retire times
+// when they aren't supported and that an error is returned.
+void GetFrameTimestampsTest::PresentOrRetireUnsupportedNoSyncTest(
+ bool displayPresentSupported, bool displayRetireSupported) {
+
+ enableFrameTimestamps();
+ mSurface->mFakeSurfaceComposer->setSupportedTimestamps(
+ displayPresentSupported, displayRetireSupported);
+
+ // Dequeue and queue frame 1.
+ dequeueAndQueue(0);
+
+ // Verify a query for the Present and Retire times do not trigger
+ // a sync call if they are not supported.
+ const uint32_t framesAgo = 0;
+ resetTimestamps();
+ int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+ int result = native_window_get_frame_timestamps(mWindow.get(), framesAgo,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ displayPresentSupported ? nullptr : &outDisplayPresentTime,
+ displayRetireSupported ? nullptr : &outDisplayRetireTime,
+ nullptr, nullptr);
+ EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+ EXPECT_EQ(BAD_VALUE, result);
+ EXPECT_EQ(-1, outDisplayRetireTime);
+ EXPECT_EQ(-1, outDisplayPresentTime);
+}
+
+TEST_F(GetFrameTimestampsTest, PresentUnsupportedNoSync) {
+ PresentOrRetireUnsupportedNoSyncTest(false, true);
+}
+
+TEST_F(GetFrameTimestampsTest, RetireUnsupportedNoSync) {
+ PresentOrRetireUnsupportedNoSyncTest(true, false);
+}
+
}
diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp
index a1dda3a..02d4137 100644
--- a/libs/ui/Fence.cpp
+++ b/libs/ui/Fence.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <ui/Fence.h>
+
#define LOG_TAG "Fence"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
//#define LOG_NDEBUG 0
@@ -25,9 +27,10 @@
#include <sync/sync.h>
#pragma clang diagnostic pop
-#include <ui/Fence.h>
+#include <sys/types.h>
#include <unistd.h>
#include <utils/Log.h>
+#include <utils/String8.h>
#include <utils/Trace.h>
namespace android {
diff --git a/libs/ui/FenceTime.cpp b/libs/ui/FenceTime.cpp
index c0245eb..8106b16 100644
--- a/libs/ui/FenceTime.cpp
+++ b/libs/ui/FenceTime.cpp
@@ -17,6 +17,7 @@
#include <ui/FenceTime.h>
#include <cutils/compiler.h> // For CC_[UN]LIKELY
+#include <utils/Log.h>
#include <inttypes.h>
#include <stdlib.h>
@@ -130,6 +131,14 @@
// Make the system call without the lock held.
signalTime = fence->getSignalTime();
+ // Allow tests to override SIGNAL_TIME_INVALID behavior, since tests
+ // use invalid underlying Fences without real file descriptors.
+ if (CC_UNLIKELY(mState == State::FORCED_VALID_FOR_TEST)) {
+ if (signalTime == Fence::SIGNAL_TIME_INVALID) {
+ signalTime = Fence::SIGNAL_TIME_PENDING;
+ }
+ }
+
// Make the signal time visible to everyone if it is no longer pending
// and remove the class' reference to the fence.
if (signalTime != Fence::SIGNAL_TIME_PENDING) {
@@ -163,10 +172,28 @@
return Snapshot(mFence);
}
+// For tests only. If forceValidForTest is true, then getSignalTime will
+// never return SIGNAL_TIME_INVALID and isValid will always return true.
+FenceTime::FenceTime(const sp<Fence>& fence, bool forceValidForTest)
+ : mState(forceValidForTest ?
+ State::FORCED_VALID_FOR_TEST : State::INVALID),
+ mFence(fence),
+ mSignalTime(mState == State::INVALID ?
+ Fence::SIGNAL_TIME_INVALID : Fence::SIGNAL_TIME_PENDING) {
+}
+
+void FenceTime::signalForTest(nsecs_t signalTime) {
+ // To be realistic, this should really set a hidden value that
+ // gets picked up in the next call to getSignalTime, but this should
+ // be good enough.
+ std::lock_guard<std::mutex> lock(mMutex);
+ mFence.clear();
+ mSignalTime.store(signalTime, std::memory_order_relaxed);
+}
+
// ============================================================================
// FenceTime::Snapshot
// ============================================================================
-
FenceTime::Snapshot::Snapshot(const sp<Fence>& srcFence)
: state(State::FENCE), fence(srcFence) {
}
@@ -279,4 +306,60 @@
}
}
+// ============================================================================
+// FenceToFenceTimeMap
+// ============================================================================
+std::shared_ptr<FenceTime> FenceToFenceTimeMap::createFenceTimeForTest(
+ const sp<Fence>& fence) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ // Always garbage collecting isn't efficient, but this is only for testing.
+ garbageCollectLocked();
+ std::shared_ptr<FenceTime> fenceTime(new FenceTime(fence, true));
+ mMap[fence.get()].push_back(fenceTime);
+ return fenceTime;
+}
+
+void FenceToFenceTimeMap::signalAllForTest(
+ const sp<Fence>& fence, nsecs_t signalTime) {
+ bool signaled = false;
+
+ std::lock_guard<std::mutex> lock(mMutex);
+ auto it = mMap.find(fence.get());
+ if (it != mMap.end()) {
+ for (auto& weakFenceTime : it->second) {
+ std::shared_ptr<FenceTime> fenceTime = weakFenceTime.lock();
+ if (!fenceTime) {
+ continue;
+ }
+ ALOGE_IF(!fenceTime->isValid(),
+ "FenceToFenceTimeMap::signalAllForTest: "
+ "Signaling invalid fence.");
+ fenceTime->signalForTest(signalTime);
+ signaled = true;
+ }
+ }
+
+ if (!signaled) {
+ ALOGE("FenceToFenceTimeMap::signalAllForTest: Nothing to signal.");
+ }
+}
+
+void FenceToFenceTimeMap::garbageCollectLocked() {
+ for (auto& it : mMap) {
+ // Erase all expired weak pointers from the vector.
+ auto& vect = it.second;
+ vect.erase(
+ std::remove_if(vect.begin(), vect.end(),
+ [](const std::weak_ptr<FenceTime>& ft) {
+ return ft.expired();
+ }),
+ vect.end());
+
+ // Also erase the map entry if the vector is now empty.
+ if (vect.empty()) {
+ mMap.erase(it.first);
+ }
+ }
+}
+
} // namespace android
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 874e712..8b754d5 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -634,11 +634,14 @@
#define EGL_TIMESTAMPS_ANDROID 0x314D
#define EGL_REQUESTED_PRESENT_TIME_ANDROID 0x314E
#define EGL_RENDERING_COMPLETE_TIME_ANDROID 0x314F
-#define EGL_COMPOSITION_START_TIME_ANDROID 0x3430
-#define EGL_COMPOSITION_FINISHED_TIME_ANDROID 0x3431
-#define EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3432
-#define EGL_DISPLAY_RETIRE_TIME_ANDROID 0x3433
-#define EGL_READS_DONE_TIME_ANDROID 0x3434
+#define EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3150
+#define EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3151
+#define EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3152
+#define EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID 0x3153
+#define EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3154
+#define EGL_DISPLAY_RETIRE_TIME_ANDROID 0x3155
+#define EGL_DEQUEUE_READY_TIME_ANDROID 0x3156
+#define EGL_READS_DONE_TIME_ANDROID 0x3157
#ifdef EGL_EGLEXT_PROTOTYPES
EGLAPI EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface, EGLint framesAgo, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values);
EGLAPI EGLBoolean eglQueryTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface surface, EGLint timestamp);
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 493c0b8..48bf676 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -740,6 +740,7 @@
case GGL_PIXEL_FORMAT_RGB_565: size *= 2; break;
case GGL_PIXEL_FORMAT_RGBA_8888: size *= 4; break;
case GGL_PIXEL_FORMAT_RGBX_8888: size *= 4; break;
+ case GGL_PIXEL_FORMAT_BGRA_8888: size *= 4; break;
default:
ALOGE("incompatible pixel format for pbuffer (format=%d)", f);
pbuffer.data = 0;
@@ -1027,6 +1028,19 @@
{ EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
};
+// BGRA 8888 config
+static config_pair_t const config_8_attribute_list[] = {
+ { EGL_BUFFER_SIZE, 32 },
+ { EGL_ALPHA_SIZE, 8 },
+ { EGL_BLUE_SIZE, 8 },
+ { EGL_GREEN_SIZE, 8 },
+ { EGL_RED_SIZE, 8 },
+ { EGL_DEPTH_SIZE, 0 },
+ { EGL_CONFIG_ID, 8 },
+ { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_BGRA_8888 },
+ { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+};
+
static configs_t const gConfigs[] = {
{ config_0_attribute_list, NELEM(config_0_attribute_list) },
{ config_1_attribute_list, NELEM(config_1_attribute_list) },
@@ -1036,6 +1050,7 @@
{ config_5_attribute_list, NELEM(config_5_attribute_list) },
{ config_6_attribute_list, NELEM(config_6_attribute_list) },
{ config_7_attribute_list, NELEM(config_7_attribute_list) },
+ { config_8_attribute_list, NELEM(config_8_attribute_list) },
};
static config_management_t const gConfigManagement[] = {
@@ -1118,6 +1133,10 @@
pixelFormat = GGL_PIXEL_FORMAT_A_8;
depthFormat = GGL_PIXEL_FORMAT_Z_16;
break;
+ case 8:
+ pixelFormat = GGL_PIXEL_FORMAT_BGRA_8888;
+ depthFormat = 0;
+ break;
default:
return NAME_NOT_FOUND;
}
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index ac455cd..01d7bbb 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -14,6 +14,10 @@
** limitations under the License.
*/
+//#define LOG_NDEBUG 0
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include <array>
#include <ctype.h>
#include <dirent.h>
#include <dlfcn.h>
@@ -23,8 +27,10 @@
#include <stdlib.h>
#include <string.h>
+#include <android/dlext.h>
#include <cutils/properties.h>
#include <log/log.h>
+#include <utils/Trace.h>
#include <EGL/egl.h>
@@ -96,6 +102,11 @@
return atoi(prop);
}
+static void* do_dlopen(const char* path, int mode) {
+ ATRACE_CALL();
+ return dlopen(path, mode);
+}
+
// ----------------------------------------------------------------------------
Loader::driver_t::driver_t(void* gles)
@@ -136,14 +147,30 @@
// ----------------------------------------------------------------------------
Loader::Loader()
- : getProcAddress(NULL) {
+ : getProcAddress(NULL),
+ mLibGui(nullptr),
+ mGetDriverNamespace(nullptr)
+{
+ // FIXME: See note in GraphicsEnv.h about android_getDriverNamespace().
+ // libgui should already be loaded in any process that uses libEGL, but
+ // if for some reason it isn't, then we're not going to get a driver
+ // namespace anyway, so don't force it to be loaded.
+ mLibGui = dlopen("libgui.so", RTLD_NOLOAD | RTLD_LOCAL | RTLD_LAZY);
+ if (!mLibGui) {
+ ALOGD("failed to load libgui: %s", dlerror());
+ return;
+ }
+ mGetDriverNamespace = reinterpret_cast<decltype(mGetDriverNamespace)>(
+ dlsym(mLibGui, "android_getDriverNamespace"));
}
Loader::~Loader() {
+ if (mLibGui)
+ dlclose(mLibGui);
}
static void* load_wrapper(const char* path) {
- void* so = dlopen(path, RTLD_NOW | RTLD_LOCAL);
+ void* so = do_dlopen(path, RTLD_NOW | RTLD_LOCAL);
ALOGE_IF(!so, "dlopen(\"%s\") failed: %s", path, dlerror());
return so;
}
@@ -190,6 +217,8 @@
void* Loader::open(egl_connection_t* cnx)
{
+ ATRACE_CALL();
+
void* dso;
driver_t* hnd = 0;
@@ -235,6 +264,8 @@
__eglMustCastToProperFunctionPointerType* curr,
getProcAddressType getProcAddress)
{
+ ATRACE_CALL();
+
const ssize_t SIZE = 256;
char scrap[SIZE];
while (*api) {
@@ -286,9 +317,8 @@
}
}
-void *Loader::load_driver(const char* kind,
- egl_connection_t* cnx, uint32_t mask)
-{
+static void* load_system_driver(const char* kind) {
+ ATRACE_CALL();
class MatchFile {
public:
static String8 find(const char* kind) {
@@ -404,7 +434,7 @@
}
const char* const driver_absolute_path = absolutePath.string();
- void* dso = dlopen(driver_absolute_path, RTLD_NOW | RTLD_LOCAL);
+ void* dso = do_dlopen(driver_absolute_path, RTLD_NOW | RTLD_LOCAL);
if (dso == 0) {
const char* err = dlerror();
ALOGE("load_driver(%s): %s", driver_absolute_path, err?err:"unknown");
@@ -413,11 +443,63 @@
ALOGD("loaded %s", driver_absolute_path);
+ return dso;
+}
+
+static void* do_android_dlopen_ext(const char* path, int mode, const android_dlextinfo* info) {
+ ATRACE_CALL();
+ return android_dlopen_ext(path, mode, info);
+}
+
+static const std::array<const char*, 2> HAL_SUBNAME_KEY_PROPERTIES = {{
+ "ro.hardware.egl",
+ "ro.board.platform",
+}};
+
+static void* load_updated_driver(const char* kind, android_namespace_t* ns) {
+ ATRACE_CALL();
+ const android_dlextinfo dlextinfo = {
+ .flags = ANDROID_DLEXT_USE_NAMESPACE,
+ .library_namespace = ns,
+ };
+ void* so = nullptr;
+ char prop[PROPERTY_VALUE_MAX + 1];
+ for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
+ if (property_get(key, prop, nullptr) > 0) {
+ String8 name;
+ name.appendFormat("lib%s_%s.so", kind, prop);
+ so = do_android_dlopen_ext(name.string(), RTLD_LOCAL | RTLD_NOW,
+ &dlextinfo);
+ if (so)
+ return so;
+ }
+ }
+ return nullptr;
+}
+
+void *Loader::load_driver(const char* kind,
+ egl_connection_t* cnx, uint32_t mask)
+{
+ ATRACE_CALL();
+
+ void* dso = nullptr;
+ if (mGetDriverNamespace) {
+ android_namespace_t* ns = mGetDriverNamespace();
+ if (ns) {
+ dso = load_updated_driver(kind, ns);
+ }
+ }
+ if (!dso) {
+ dso = load_system_driver(kind);
+ if (!dso)
+ return NULL;
+ }
+
if (mask & EGL) {
getProcAddress = (getProcAddressType)dlsym(dso, "eglGetProcAddress");
ALOGE_IF(!getProcAddress,
- "can't find eglGetProcAddress() in %s", driver_absolute_path);
+ "can't find eglGetProcAddress() in EGL driver library");
egl_t* egl = &cnx->egl;
__eglMustCastToProperFunctionPointerType* curr =
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index 94f680e..d0435e7 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -25,6 +25,8 @@
#include <utils/Singleton.h>
#include <utils/String8.h>
+#include <gui/GraphicsEnv.h>
+
#include <EGL/egl.h>
// ----------------------------------------------------------------------------
@@ -53,7 +55,10 @@
};
getProcAddressType getProcAddress;
-
+
+ void* mLibGui;
+ decltype(android_getDriverNamespace)* mGetDriverNamespace;
+
public:
~Loader();
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index c4541a2..b38b4c2 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -267,6 +267,7 @@
EGLDisplay eglGetDisplay(EGLNativeDisplayType display)
{
+ ATRACE_CALL();
clearError();
uintptr_t index = reinterpret_cast<uintptr_t>(display);
@@ -2041,10 +2042,13 @@
nsecs_t* requestedPresentTime = nullptr;
nsecs_t* acquireTime = nullptr;
- nsecs_t* refreshStartTime = nullptr;
+ nsecs_t* latchTime = nullptr;
+ nsecs_t* firstRefreshStartTime = nullptr;
nsecs_t* GLCompositionDoneTime = nullptr;
+ nsecs_t* lastRefreshStartTime = nullptr;
nsecs_t* displayPresentTime = nullptr;
nsecs_t* displayRetireTime = nullptr;
+ nsecs_t* dequeueReadyTime = nullptr;
nsecs_t* releaseTime = nullptr;
for (int i = 0; i < numTimestamps; i++) {
@@ -2055,10 +2059,16 @@
case EGL_RENDERING_COMPLETE_TIME_ANDROID:
acquireTime = &values[i];
break;
- case EGL_COMPOSITION_START_TIME_ANDROID:
- refreshStartTime = &values[i];
+ case EGL_COMPOSITION_LATCH_TIME_ANDROID:
+ latchTime = &values[i];
break;
- case EGL_COMPOSITION_FINISHED_TIME_ANDROID:
+ case EGL_FIRST_COMPOSITION_START_TIME_ANDROID:
+ firstRefreshStartTime = &values[i];
+ break;
+ case EGL_LAST_COMPOSITION_START_TIME_ANDROID:
+ lastRefreshStartTime = &values[i];
+ break;
+ case EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID:
GLCompositionDoneTime = &values[i];
break;
case EGL_DISPLAY_PRESENT_TIME_ANDROID:
@@ -2067,6 +2077,9 @@
case EGL_DISPLAY_RETIRE_TIME_ANDROID:
displayRetireTime = &values[i];
break;
+ case EGL_DEQUEUE_READY_TIME_ANDROID:
+ dequeueReadyTime = &values[i];
+ break;
case EGL_READS_DONE_TIME_ANDROID:
releaseTime = &values[i];
break;
@@ -2076,9 +2089,9 @@
}
status_t ret = native_window_get_frame_timestamps(s->win.get(), framesAgo,
- requestedPresentTime, acquireTime, refreshStartTime,
- GLCompositionDoneTime, displayPresentTime, displayRetireTime,
- releaseTime);
+ requestedPresentTime, acquireTime, latchTime, firstRefreshStartTime,
+ lastRefreshStartTime, GLCompositionDoneTime, displayPresentTime,
+ displayRetireTime, dequeueReadyTime, releaseTime);
switch (ret) {
case NO_ERROR:
@@ -2122,8 +2135,11 @@
#if ENABLE_EGL_ANDROID_GET_FRAME_TIMESTAMPS
case EGL_REQUESTED_PRESENT_TIME_ANDROID:
case EGL_RENDERING_COMPLETE_TIME_ANDROID:
- case EGL_COMPOSITION_START_TIME_ANDROID:
- case EGL_COMPOSITION_FINISHED_TIME_ANDROID:
+ case EGL_COMPOSITION_LATCH_TIME_ANDROID:
+ case EGL_FIRST_COMPOSITION_START_TIME_ANDROID:
+ case EGL_LAST_COMPOSITION_START_TIME_ANDROID:
+ case EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID:
+ case EGL_DEQUEUE_READY_TIME_ANDROID:
case EGL_READS_DONE_TIME_ANDROID:
return EGL_TRUE;
case EGL_DISPLAY_PRESENT_TIME_ANDROID: {
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index a32f037..d7df40c 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -15,6 +15,7 @@
*/
#define __STDC_LIMIT_MACROS 1
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <string.h>
@@ -26,6 +27,7 @@
#include "egl_tls.h"
#include "Loader.h"
#include <cutils/properties.h>
+#include <utils/Trace.h>
// ----------------------------------------------------------------------------
namespace android {
@@ -103,6 +105,7 @@
EGLDisplay egl_display_t::getDisplay(EGLNativeDisplayType display) {
Mutex::Autolock _l(lock);
+ ATRACE_CALL();
// get our driver loader
Loader& loader(Loader::getInstance());
diff --git a/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
index b5b6eb5..7aa0d30 100644
--- a/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
+++ b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
@@ -69,11 +69,14 @@
EGL_TIMESTAMPS_ANDROID 0x314D
EGL_REQUESTED_PRESENT_TIME_ANDROID 0x314E
EGL_RENDERING_COMPLETE_TIME_ANDROID 0x314F
- EGL_COMPOSITION_START_TIME_ANDROID 0x3430
- EGL_COMPOSITION_FINISHED_TIME_ANDROID 0x3431
- EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3432
- EGL_DISPLAY_RETIRE_TIME_ANDROID 0x3433
- EGL_READS_DONE_TIME_ANDROID 0x3434
+ EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3150
+ EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3151
+ EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3152
+ EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID 0x3153
+ EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3154
+ EGL_DISPLAY_RETIRE_TIME_ANDROID 0x3155
+ EGL_DEQUEUE_READY_TIME_ANDROID 0x3156
+ EGL_READS_DONE_TIME_ANDROID 0x3157
Add to the list of supported tokens for eglSurfaceAttrib in section 3.5.6
"Surface Attributes", page 43:
@@ -119,16 +122,31 @@
this will correspond to buffer's queue time.
- EGL_RENDERING_COMPLETE_TIME_ANDROID - The time when all of the
application's rendering to the surface was completed.
- - EGL_COMPOSITION_START_TIME_ANDROID - The time at which the compositor
- began preparing composition for this frame.
- - EGL_COMPOSITION_FINISHED_TIME_ANDROID - The time at which the
+ - EGL_COMPOSITION_LATCH_TIME_ANDROID - The time when the compositor
+ selected this frame as the one to use for the next composition. The
+ latch is the earliest indication that the frame was submitted in time
+ to be composited.
+ - EGL_FIRST_COMPOSITION_START_TIME_ANDROID - The first time at which
+ the compositor began preparing composition for this frame.
+ - EGL_LAST_COMPOSITION_START_TIME_ANDROID - The last time at which the
+ compositor began preparing composition for this frame. If this frame
+ is composited only once, it will have the same value as
+ EGL_FIRST_COMPOSITION_START_TIME_ANDROID. If the value is not equal,
+ that indicates the subsequent frame was not submitted in time to be
+ latched by the compositor. Note: The value may not be updated for
+ every display refresh if the compositor becomes idle.
+ - EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID - The time at which the
compositor's rendering work for this frame finished. This will be zero
if composition was handled by the display and the compositor didn't do
any rendering.
- EGL_DISPLAY_PRESENT_TIME_ANDROID - The time at which this frame
- started to scan out on the physical display.
+ started to scan out to the physical display.
- EGL_DISPLAY_RETIRE_TIME_ANDROID - The time at which this frame was
replaced by the next frame on-screen.
+ - EGL_DEQUEUE_READY_TIME_ANDROID - The time when the buffer became
+ available for reuse as a buffer the client can target without
+ blocking. This is generally the point when all read commands of the
+ buffer have been submitted, but not necessarily completed.
- EGL_READS_DONE_TIME_ANDROID - The time at which all reads for the
purpose of display/composition were completed for this frame.
@@ -152,3 +170,8 @@
#2 (Brian Anderson, July 22, 2016)
- Replace EGL_QUEUE_TIME_ANDROID with EGL_REQUESTED_PRESENT_TIME_ANDROID.
- Add DISPLAY_PRESENT_TIME_ANDROID.
+
+#3 (Brian Anderson, November 30, 2016)
+ - Add EGL_COMPOSITION_LATCH_TIME_ANDROID,
+ EGL_LAST_COMPOSITION_START_TIME_ANDROID, and
+ EGL_DEQUEUE_READY_TIME_ANDROID.
diff --git a/opengl/specs/README b/opengl/specs/README
index 1ee99fb..8a3a7aa 100644
--- a/opengl/specs/README
+++ b/opengl/specs/README
@@ -22,9 +22,12 @@
0x314D EGL_TIMESTAMPS_ANDROID (EGL_ANDROID_get_frame_timestamps)
0x314E EGL_REQUESTED_PRESENT_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
0x314F EGL_RENDERING_COMPLETE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3430 EGL_COMPOSITION_START_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3431 EGL_COMPOSITION_FINISHED_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3432 EGL_DISPLAY_PRESENT_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3433 EGL_DISPLAY_RETIRE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3434 EGL_READS_DONE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3435 - 0x343F (unused)
+0x3150 EGL_COMPOSITION_LATCH_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3151 EGL_FIRST_COMPOSITION_START_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3152 EGL_LAST_COMPOSITION_START_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3153 EGL_FIRST_COMPOSITION_FINISHED_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3154 EGL_DISPLAY_PRESENT_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3155 EGL_DISPLAY_RETIRE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3156 EGL_DEQUEUE_READY_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3157 EGL_READS_DONE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3158 - 0x315F (unused)
diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp
index d69a275..2b9c38e 100644
--- a/opengl/tests/EGLTest/EGL_test.cpp
+++ b/opengl/tests/EGLTest/EGL_test.cpp
@@ -24,6 +24,8 @@
namespace android {
+#define EGL_UNSIGNED_TRUE static_cast<EGLBoolean>(EGL_TRUE)
+
class EGLTest : public ::testing::Test {
protected:
EGLDisplay mEglDisplay;
@@ -48,7 +50,7 @@
virtual void TearDown() {
EGLBoolean success = eglTerminate(mEglDisplay);
- ASSERT_EQ(EGL_TRUE, success);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
}
};
@@ -65,20 +67,20 @@
};
success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs);
- ASSERT_EQ(EGL_TRUE, success);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
ASSERT_GE(numConfigs, 1);
EGLint components[3];
success = eglGetConfigAttrib(mEglDisplay, config, EGL_RED_SIZE, &components[0]);
- ASSERT_EQ(EGL_TRUE, success);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
success = eglGetConfigAttrib(mEglDisplay, config, EGL_GREEN_SIZE, &components[1]);
- ASSERT_EQ(EGL_TRUE, success);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
success = eglGetConfigAttrib(mEglDisplay, config, EGL_BLUE_SIZE, &components[2]);
- ASSERT_EQ(EGL_TRUE, success);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
EXPECT_GE(components[0], 8);
@@ -139,23 +141,23 @@
};
success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs);
- ASSERT_EQ(EGL_TRUE, success);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
ASSERT_GE(numConfigs, 1);
EGLint components[4];
success = eglGetConfigAttrib(mEglDisplay, config, EGL_RED_SIZE, &components[0]);
- ASSERT_EQ(EGL_TRUE, success);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
success = eglGetConfigAttrib(mEglDisplay, config, EGL_GREEN_SIZE, &components[1]);
- ASSERT_EQ(EGL_TRUE, success);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
success = eglGetConfigAttrib(mEglDisplay, config, EGL_BLUE_SIZE, &components[2]);
- ASSERT_EQ(EGL_TRUE, success);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
success = eglGetConfigAttrib(mEglDisplay, config, EGL_ALPHA_SIZE, &components[3]);
- ASSERT_EQ(EGL_TRUE, success);
+ ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
EXPECT_GE(components[0], 8);
diff --git a/opengl/tools/glgen/stubs/egl/EGLExtHeader.java-if b/opengl/tools/glgen/stubs/egl/EGLExtHeader.java-if
index a5a8968..523bc57 100644
--- a/opengl/tools/glgen/stubs/egl/EGLExtHeader.java-if
+++ b/opengl/tools/glgen/stubs/egl/EGLExtHeader.java-if
@@ -28,6 +28,7 @@
public static final int EGL_CONTEXT_MINOR_VERSION_KHR = 0x30FB;
public static final int EGL_CONTEXT_FLAGS_KHR = 0x30FC;
public static final int EGL_OPENGL_ES3_BIT_KHR = 0x0040;
+ public static final int EGL_RECORDABLE_ANDROID = 0x3142;
native private static void _nativeClassInit();
static {
diff --git a/services/audiomanager/Android.bp b/services/audiomanager/Android.bp
index 04dd967..22b084a 100644
--- a/services/audiomanager/Android.bp
+++ b/services/audiomanager/Android.bp
@@ -1,7 +1,10 @@
cc_library_shared {
name: "libaudiomanager",
- srcs: ["IAudioManager.cpp"],
+ srcs: [
+ "IAudioManager.cpp",
+ "IPlayer.cpp",
+ ],
shared_libs: [
"libutils",
diff --git a/services/audiomanager/IAudioManager.cpp b/services/audiomanager/IAudioManager.cpp
index a41804f..b9b0706 100644
--- a/services/audiomanager/IAudioManager.cpp
+++ b/services/audiomanager/IAudioManager.cpp
@@ -35,15 +35,16 @@
{
}
- virtual audio_unique_id_t trackPlayer(int playerType, int usage, int content) {
+ virtual audio_unique_id_t trackPlayer(player_type_t playerType, audio_usage_t usage,
+ audio_content_type_t content, const sp<IBinder>& player) {
Parcel data, reply;
data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
data.writeInt32(1); // non-null PlayerIdCard parcelable
// marshall PlayerIdCard data
data.writeInt32((int32_t) playerType);
// write attributes of PlayerIdCard
- data.writeInt32(usage);
- data.writeInt32(content);
+ data.writeInt32((int32_t) usage);
+ data.writeInt32((int32_t) content);
data.writeInt32(0 /*source: none here, this is a player*/);
data.writeInt32(0 /*flags*/);
// write attributes' tags
@@ -51,6 +52,8 @@
data.writeString16(String16("")); // no tags
// write attributes' bundle
data.writeInt32(-1977 /*ATTR_PARCEL_IS_NULL_BUNDLE*/); // no bundle
+ // write IPlayer
+ data.writeStrongBinder(player);
// get new PIId in reply
const status_t res = remote()->transact(TRACK_PLAYER, data, &reply, 0);
if (res != OK || reply.readExceptionCode() != 0) {
@@ -63,13 +66,14 @@
}
}
- virtual status_t playerAttributes(audio_unique_id_t piid, int usage, int content) {
+ virtual status_t playerAttributes(audio_unique_id_t piid, audio_usage_t usage,
+ audio_content_type_t content) {
Parcel data, reply;
data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
- data.writeInt32(piid);
+ data.writeInt32((int32_t) piid);
data.writeInt32(1); // non-null AudioAttributes parcelable
- data.writeInt32(usage);
- data.writeInt32(content);
+ data.writeInt32((int32_t) usage);
+ data.writeInt32((int32_t) content);
data.writeInt32(0 /*source: none here, this is a player*/);
data.writeInt32(0 /*flags*/);
// write attributes' tags
@@ -80,18 +84,18 @@
return remote()->transact(PLAYER_ATTRIBUTES, data, &reply, IBinder::FLAG_ONEWAY);
}
- virtual status_t playerEvent(int piid, int event) {
+ virtual status_t playerEvent(audio_unique_id_t piid, player_state_t event) {
Parcel data, reply;
data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
- data.writeInt32(piid);
- data.writeInt32(event);
+ data.writeInt32((int32_t) piid);
+ data.writeInt32((int32_t) event);
return remote()->transact(PLAYER_EVENT, data, &reply, IBinder::FLAG_ONEWAY);
}
- virtual status_t releasePlayer(int piid) {
+ virtual status_t releasePlayer(audio_unique_id_t piid) {
Parcel data, reply;
data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
- data.writeInt32(piid);
+ data.writeInt32((int32_t) piid);
return remote()->transact(RELEASE_PLAYER, data, &reply, IBinder::FLAG_ONEWAY);
}
};
diff --git a/services/audiomanager/IPlayer.cpp b/services/audiomanager/IPlayer.cpp
new file mode 100644
index 0000000..3b0b4e9
--- /dev/null
+++ b/services/audiomanager/IPlayer.cpp
@@ -0,0 +1,109 @@
+/*
+**
+** Copyright 2017, 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.
+*/
+
+#define LOG_TAG "IPlayer"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+
+#include <audiomanager/IPlayer.h>
+
+namespace android {
+
+enum {
+ START = IBinder::FIRST_CALL_TRANSACTION,
+ PAUSE = IBinder::FIRST_CALL_TRANSACTION + 1,
+ STOP = IBinder::FIRST_CALL_TRANSACTION + 2,
+ SET_VOLUME = IBinder::FIRST_CALL_TRANSACTION + 3,
+};
+
+class BpPlayer : public BpInterface<IPlayer>
+{
+public:
+ explicit BpPlayer(const sp<IBinder>& impl)
+ : BpInterface<IPlayer>(impl)
+ {
+ }
+
+ virtual void start()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IPlayer::getInterfaceDescriptor());
+ remote()->transact(START, data, &reply);
+ }
+
+ virtual void pause()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IPlayer::getInterfaceDescriptor());
+ remote()->transact(PAUSE, data, &reply);
+ }
+
+ virtual void stop()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IPlayer::getInterfaceDescriptor());
+ remote()->transact(STOP, data, &reply);
+ }
+
+ virtual void setVolume(float vol)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IPlayer::getInterfaceDescriptor());
+ data.writeFloat(vol);
+ remote()->transact(SET_VOLUME, data, &reply);
+ }
+};
+
+IMPLEMENT_META_INTERFACE(Player, "android.media.IPlayer");
+
+// ----------------------------------------------------------------------
+
+status_t BnPlayer::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch (code) {
+ case START: {
+ CHECK_INTERFACE(IPlayer, data, reply);
+ start();
+ return NO_ERROR;
+ } break;
+ case PAUSE: {
+ CHECK_INTERFACE(IPlayer, data, reply);
+ pause();
+ return NO_ERROR;
+ }
+ case STOP: {
+ CHECK_INTERFACE(IPlayer, data, reply);
+ stop();
+ return NO_ERROR;
+ } break;
+ case SET_VOLUME: {
+ CHECK_INTERFACE(IPlayer, data, reply);
+ setVolume(data.readFloat());
+ return NO_ERROR;
+ }
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+} // namespace android
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 89475e9..8771d45 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -1224,15 +1224,8 @@
if (maskedAction == AMOTION_EVENT_ACTION_DOWN
&& (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) {
- int32_t outsideTargetFlags = InputTarget::FLAG_DISPATCH_AS_OUTSIDE;
- if (isWindowObscuredAtPointLocked(windowHandle, x, y)) {
- outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
- } else if (isWindowObscuredLocked(windowHandle)) {
- outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
- }
-
mTempTouchState.addOrUpdateWindow(
- windowHandle, outsideTargetFlags, BitSet32(0));
+ windowHandle, InputTarget::FLAG_DISPATCH_AS_OUTSIDE, BitSet32(0));
}
}
}
diff --git a/services/sensorservice/Android.mk b/services/sensorservice/Android.mk
index 86af0ef..c41630a 100644
--- a/services/sensorservice/Android.mk
+++ b/services/sensorservice/Android.mk
@@ -10,6 +10,7 @@
OrientationSensor.cpp \
RecentEventLogger.cpp \
RotationVectorSensor.cpp \
+ SensorDirectConnection.cpp \
SensorEventConnection.cpp \
SensorFusion.cpp \
SensorInterface.cpp \
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 0245b26..41ad918 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -14,23 +14,27 @@
* limitations under the License.
*/
-#include <inttypes.h>
-#include <math.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <utils/Atomic.h>
-#include <utils/Errors.h>
-#include <utils/Singleton.h>
+#include "SensorDevice.h"
+#include "SensorService.h"
+
#include <binder/BinderService.h>
#include <binder/Parcel.h>
#include <binder/IServiceManager.h>
-
+#include <cutils/ashmem.h>
#include <hardware/sensors.h>
+#include <utils/Atomic.h>
+#include <utils/Errors.h>
+#include <utils/Singleton.h>
-#include "SensorDevice.h"
-#include "SensorService.h"
+#include <inttypes.h>
+#include <math.h>
+#include <sys/mman.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sstream>
+#include <unistd.h>
namespace android {
// ---------------------------------------------------------------------------
@@ -386,7 +390,7 @@
void SensorDevice::disableAllSensors() {
Mutex::Autolock _l(mLock);
- for (size_t i = 0; i< mActivationCount.size(); ++i) {
+ for (size_t i = 0; i< mActivationCount.size(); ++i) {
const Info& info = mActivationCount.valueAt(i);
// Check if this sensor has been activated previously and disable it.
if (info.batchParams.size() > 0) {
@@ -486,6 +490,29 @@
mDisabledClients.remove(ident);
}
+int32_t SensorDevice::registerDirectChannel(const sensors_direct_mem_t* memory) {
+ Mutex::Autolock _l(mLock);
+
+ int32_t channelHandle = mSensorDevice->register_direct_channel(
+ mSensorDevice, memory, -1 /*channel_handle*/);
+ return channelHandle;
+}
+
+void SensorDevice::unregisterDirectChannel(int32_t channelHandle) {
+ Mutex::Autolock _l(mLock);
+
+ mSensorDevice->register_direct_channel(mSensorDevice, nullptr, channelHandle);
+}
+
+int32_t SensorDevice::configureDirectChannel(int32_t sensorHandle, int32_t channelHandle,
+ const struct sensors_direct_cfg_t *config) {
+ Mutex::Autolock _l(mLock);
+
+ int32_t ret = mSensorDevice->config_direct_report(
+ mSensorDevice, sensorHandle, channelHandle, config);
+ ALOGE_IF(ret < 0, "SensorDevice::configureDirectChannel ret %d", ret);
+ return ret;
+}
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 0bb0752..b6886a2 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -26,6 +26,7 @@
#include <stdint.h>
#include <sys/types.h>
+#include <string>
#ifdef ENABLE_TREBLE
#include <map>
@@ -57,6 +58,12 @@
status_t setDelay(void* ident, int handle, int64_t ns);
status_t flush(void* ident, int handle);
status_t setMode(uint32_t mode);
+
+ int32_t registerDirectChannel(const sensors_direct_mem_t *memory);
+ void unregisterDirectChannel(int32_t channelHandle);
+ int32_t configureDirectChannel(int32_t sensorHandle,
+ int32_t channelHandle, const struct sensors_direct_cfg_t *config);
+
void disableAllSensors();
void enableAllSensors();
void autoDisable(void *ident, int handle);
diff --git a/services/sensorservice/SensorDeviceTreble.cpp b/services/sensorservice/SensorDeviceTreble.cpp
index e215f65..0a75400 100644
--- a/services/sensorservice/SensorDeviceTreble.cpp
+++ b/services/sensorservice/SensorDeviceTreble.cpp
@@ -29,16 +29,9 @@
#include <sensors/convert.h>
-using android::hardware::sensors::V1_0::ISensors;
using android::hardware::hidl_vec;
-using Event = android::hardware::sensors::V1_0::Event;
-using SensorInfo = android::hardware::sensors::V1_0::SensorInfo;
-using SensorType = android::hardware::sensors::V1_0::SensorType;
-using DynamicSensorInfo = android::hardware::sensors::V1_0::DynamicSensorInfo;
-using SensorInfo = android::hardware::sensors::V1_0::SensorInfo;
-using Result = android::hardware::sensors::V1_0::Result;
-
+using namespace android::hardware::sensors::V1_0;
using namespace android::hardware::sensors::V1_0::implementation;
namespace android {
@@ -62,7 +55,7 @@
}
SensorDevice::SensorDevice() {
- mSensors = ISensors::getService("sensors");
+ mSensors = ISensors::getService();
if (mSensors == NULL) {
return;
@@ -81,8 +74,7 @@
mActivationCount.add(list[i].sensorHandle, model);
- /* auto result = */mSensors->activate(
- list[i].sensorHandle, 0 /* enabled */);
+ mSensors->activate(list[i].sensorHandle, 0 /* enabled */);
}
});
}
@@ -91,7 +83,7 @@
if (connected) {
Info model;
mActivationCount.add(handle, model);
- /* auto result = */mSensors->activate(handle, 0 /* enabled */);
+ mSensors->activate(handle, 0 /* enabled */);
} else {
mActivationCount.removeItem(handle);
}
@@ -100,13 +92,6 @@
std::string SensorDevice::dump() const {
if (mSensors == NULL) return "HAL not initialized\n";
-#if 0
- result.appendFormat("HAL: %s (%s), version %#010x\n",
- mSensorModule->common.name,
- mSensorModule->common.author,
- getHalDeviceVersion());
-#endif
-
String8 result;
mSensors->getSensorsList([&](const auto &list) {
const size_t count = list.size();
@@ -242,21 +227,17 @@
// This is the last connection, we need to de-activate the underlying h/w sensor.
actuateHardware = true;
} else {
- const int halVersion = getHalDeviceVersion();
- if (halVersion >= SENSORS_DEVICE_API_VERSION_1_1) {
- // Call batch for this sensor with the previously calculated best effort
- // batch_rate and timeout. One of the apps has unregistered for sensor
- // events, and the best effort batch parameters might have changed.
- ALOGD_IF(DEBUG_CONNECTIONS,
- "\t>>> actuating h/w batch %d %d %" PRId64 " %" PRId64, handle,
- info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
- info.bestBatchParams.batchTimeout);
- /* auto result = */mSensors->batch(
- handle,
- info.bestBatchParams.flags,
- info.bestBatchParams.batchDelay,
- info.bestBatchParams.batchTimeout);
- }
+ // Call batch for this sensor with the previously calculated best effort
+ // batch_rate and timeout. One of the apps has unregistered for sensor
+ // events, and the best effort batch parameters might have changed.
+ ALOGD_IF(DEBUG_CONNECTIONS,
+ "\t>>> actuating h/w batch %d %d %" PRId64 " %" PRId64, handle,
+ info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
+ info.bestBatchParams.batchTimeout);
+ mSensors->batch(
+ handle,
+ info.bestBatchParams.batchDelay,
+ info.bestBatchParams.batchTimeout);
}
} else {
// sensor wasn't enabled for this ident
@@ -280,13 +261,6 @@
}
}
- // On older devices which do not support batch, call setDelay().
- if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1 && info.numActiveClients() > 0) {
- ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w setDelay %d %" PRId64, handle,
- info.bestBatchParams.batchDelay);
- /* auto result = */mSensors->setDelay(
- handle, info.bestBatchParams.batchDelay);
- }
return err;
}
@@ -302,12 +276,6 @@
samplingPeriodNs = MINIMUM_EVENTS_PERIOD;
}
- const int halVersion = getHalDeviceVersion();
- if (halVersion < SENSORS_DEVICE_API_VERSION_1_1 && maxBatchReportLatencyNs != 0) {
- // Batch is not supported on older devices return invalid operation.
- return INVALID_OPERATION;
- }
-
ALOGD_IF(DEBUG_CONNECTIONS,
"SensorDevice::batch: ident=%p, handle=0x%08x, flags=%d, period_ns=%" PRId64 " timeout=%" PRId64,
ident, handle, flags, samplingPeriodNs, maxBatchReportLatencyNs);
@@ -336,21 +304,14 @@
status_t err(NO_ERROR);
// If the min period or min timeout has changed since the last batch call, call batch.
if (prevBestBatchParams != info.bestBatchParams) {
- if (halVersion >= SENSORS_DEVICE_API_VERSION_1_1) {
- ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w BATCH %d %d %" PRId64 " %" PRId64, handle,
- info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
- info.bestBatchParams.batchTimeout);
- err = StatusFromResult(
- mSensors->batch(
- handle,
- info.bestBatchParams.flags,
- info.bestBatchParams.batchDelay,
- info.bestBatchParams.batchTimeout));
- } else {
- // For older devices which do not support batch, call setDelay() after activate() is
- // called. Some older devices may not support calling setDelay before activate(), so
- // call setDelay in SensorDevice::activate() method.
- }
+ ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w BATCH %d %d %" PRId64 " %" PRId64, handle,
+ info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
+ info.bestBatchParams.batchTimeout);
+ err = StatusFromResult(
+ mSensors->batch(
+ handle,
+ info.bestBatchParams.batchDelay,
+ info.bestBatchParams.batchTimeout));
if (err != NO_ERROR) {
ALOGE("sensor batch failed %p %d %d %" PRId64 " %" PRId64 " err=%s",
mSensors.get(), handle,
@@ -384,7 +345,7 @@
info.selectBatchParams();
return StatusFromResult(
- mSensors->setDelay(handle, info.bestBatchParams.batchDelay));
+ mSensors->batch(handle, info.bestBatchParams.batchDelay, 0));
}
int SensorDevice::getHalDeviceVersion() const {
@@ -393,9 +354,6 @@
}
status_t SensorDevice::flush(void* ident, int handle) {
- if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1) {
- return INVALID_OPERATION;
- }
if (isClientDisabled(ident)) return INVALID_OPERATION;
ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w flush %d", handle);
return StatusFromResult(mSensors->flush(handle));
@@ -414,7 +372,6 @@
Mutex::Autolock _l(mLock);
mDisabledClients.clear();
ALOGI("cleared mDisabledClients");
- const int halVersion = getHalDeviceVersion();
for (size_t i = 0; i< mActivationCount.size(); ++i) {
Info& info = mActivationCount.editValueAt(i);
if (info.batchParams.isEmpty()) continue;
@@ -422,29 +379,18 @@
const int sensor_handle = mActivationCount.keyAt(i);
ALOGD_IF(DEBUG_CONNECTIONS, "\t>> reenable actuating h/w sensor enable handle=%d ",
sensor_handle);
- status_t err(NO_ERROR);
- if (halVersion > SENSORS_DEVICE_API_VERSION_1_0) {
- err = StatusFromResult(
- mSensors->batch(
- sensor_handle,
- info.bestBatchParams.flags,
- info.bestBatchParams.batchDelay,
- info.bestBatchParams.batchTimeout));
- ALOGE_IF(err, "Error calling batch on sensor %d (%s)", sensor_handle, strerror(-err));
- }
+ status_t err = StatusFromResult(
+ mSensors->batch(
+ sensor_handle,
+ info.bestBatchParams.batchDelay,
+ info.bestBatchParams.batchTimeout));
+ ALOGE_IF(err, "Error calling batch on sensor %d (%s)", sensor_handle, strerror(-err));
if (err == NO_ERROR) {
err = StatusFromResult(
mSensors->activate(sensor_handle, 1 /* enabled */));
ALOGE_IF(err, "Error activating sensor %d (%s)", sensor_handle, strerror(-err));
}
-
- if (halVersion <= SENSORS_DEVICE_API_VERSION_1_0) {
- err = StatusFromResult(
- mSensors->setDelay(
- sensor_handle, info.bestBatchParams.batchDelay));
- ALOGE_IF(err, "Error calling setDelay sensor %d (%s)", sensor_handle, strerror(-err));
- }
}
}
@@ -457,8 +403,7 @@
const int sensor_handle = mActivationCount.keyAt(i);
ALOGD_IF(DEBUG_CONNECTIONS, "\t>> actuating h/w sensor disable handle=%d ",
sensor_handle);
- /* auto result = */mSensors->activate(
- sensor_handle, 0 /* enabled */);
+ mSensors->activate(sensor_handle, 0 /* enabled */);
// Add all the connections that were registered for this sensor to the disabled
// clients list.
@@ -480,10 +425,6 @@
injected_sensor_event->data[3], injected_sensor_event->data[4],
injected_sensor_event->data[5]);
- if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_4) {
- return INVALID_OPERATION;
- }
-
Event ev;
convertFromSensorEvent(*injected_sensor_event, &ev);
@@ -491,9 +432,6 @@
}
status_t SensorDevice::setMode(uint32_t mode) {
- if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_4) {
- return INVALID_OPERATION;
- }
return StatusFromResult(
mSensors->setOperationMode(
@@ -559,12 +497,96 @@
mDisabledClients.remove(ident);
}
+int32_t SensorDevice::registerDirectChannel(const sensors_direct_mem_t* memory) {
+ Mutex::Autolock _l(mLock);
+
+ SharedMemType type;
+ switch (memory->type) {
+ case SENSOR_DIRECT_MEM_TYPE_ASHMEM:
+ type = SharedMemType::ASHMEM;
+ break;
+ case SENSOR_DIRECT_MEM_TYPE_GRALLOC:
+ type = SharedMemType::GRALLOC;
+ break;
+ default:
+ return BAD_VALUE;
+ }
+
+ SharedMemFormat format;
+ if (memory->format != SENSOR_DIRECT_FMT_SENSORS_EVENT) {
+ return BAD_VALUE;
+ }
+ format = SharedMemFormat::SENSORS_EVENT;
+
+ SharedMemInfo mem = {
+ .type = type,
+ .format = format,
+ .size = static_cast<uint32_t>(memory->size),
+ .memoryHandle = memory->handle,
+ };
+
+ int32_t ret;
+ mSensors->registerDirectChannel(mem,
+ [&ret](auto result, auto channelHandle) {
+ if (result == Result::OK) {
+ ret = channelHandle;
+ } else {
+ ret = StatusFromResult(result);
+ }
+ });
+ return ret;
+}
+
+void SensorDevice::unregisterDirectChannel(int32_t channelHandle) {
+ Mutex::Autolock _l(mLock);
+ mSensors->unregisterDirectChannel(channelHandle);
+}
+
+int32_t SensorDevice::configureDirectChannel(int32_t sensorHandle,
+ int32_t channelHandle, const struct sensors_direct_cfg_t *config) {
+ Mutex::Autolock _l(mLock);
+
+ RateLevel rate;
+ switch(config->rate_level) {
+ case SENSOR_DIRECT_RATE_STOP:
+ rate = RateLevel::STOP;
+ break;
+ case SENSOR_DIRECT_RATE_NORMAL:
+ rate = RateLevel::NORMAL;
+ break;
+ case SENSOR_DIRECT_RATE_FAST:
+ rate = RateLevel::FAST;
+ break;
+ case SENSOR_DIRECT_RATE_VERY_FAST:
+ rate = RateLevel::VERY_FAST;
+ break;
+ default:
+ return BAD_VALUE;
+ }
+
+ int32_t ret;
+ mSensors->configDirectReport(sensorHandle, channelHandle, rate,
+ [&ret, rate] (auto result, auto token) {
+ if (rate == RateLevel::STOP) {
+ ret = StatusFromResult(result);
+ } else {
+ if (result == Result::OK) {
+ ret = token;
+ } else {
+ ret = StatusFromResult(result);
+ }
+ }
+ });
+
+ return ret;
+}
+
void SensorDevice::convertToSensorEvent(
const Event &src, sensors_event_t *dst) {
::android::hardware::sensors::V1_0::implementation::convertToSensorEvent(
src, dst);
- if (src.sensorType == SensorType::SENSOR_TYPE_DYNAMIC_SENSOR_META) {
+ if (src.sensorType == SensorType::DYNAMIC_SENSOR_META) {
const DynamicSensorInfo &dyn = src.u.dynamic;
dst->dynamic_sensor_meta.connected = dyn.connected;
@@ -608,4 +630,3 @@
// ---------------------------------------------------------------------------
}; // namespace android
-
diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp
new file mode 100644
index 0000000..662f320
--- /dev/null
+++ b/services/sensorservice/SensorDirectConnection.cpp
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2016 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 "SensorDevice.h"
+#include "SensorDirectConnection.h"
+#include <hardware/sensors.h>
+
+#include <sys/stat.h>
+
+#define UNUSED(x) (void)(x)
+
+namespace android {
+
+SensorService::SensorDirectConnection::SensorDirectConnection(const sp<SensorService>& service,
+ uid_t uid, const sensors_direct_mem_t *mem, int32_t halChannelHandle,
+ const String16& opPackageName)
+ : mService(service), mUid(uid), mMem(*mem),
+ mHalChannelHandle(halChannelHandle),
+ mOpPackageName(opPackageName) {
+ ALOGD_IF(DEBUG_CONNECTIONS, "Created SensorDirectConnection");
+}
+
+SensorService::SensorDirectConnection::~SensorDirectConnection() {
+ ALOGD_IF(DEBUG_CONNECTIONS, "~SensorDirectConnection %p", this);
+
+ stopAll();
+ mService->cleanupConnection(this);
+ if (mMem.handle != nullptr) {
+ native_handle_close(mMem.handle);
+ native_handle_delete(const_cast<struct native_handle*>(mMem.handle));
+ }
+}
+
+void SensorService::SensorDirectConnection::onFirstRef() {
+}
+
+void SensorService::SensorDirectConnection::dump(String8& result) const {
+ Mutex::Autolock _l(mConnectionLock);
+ result.appendFormat("\tPackage %s, HAL channel handle %d, total sensor activated %zu\n",
+ String8(mOpPackageName).string(), getHalChannelHandle(), mActivated.size());
+ for (auto &i : mActivated) {
+ result.appendFormat("\t\tSensor %#08x, rate %d\n", i.first, i.second);
+ }
+}
+
+sp<BitTube> SensorService::SensorDirectConnection::getSensorChannel() const {
+ return nullptr;
+}
+
+status_t SensorService::SensorDirectConnection::enableDisable(
+ int handle, bool enabled, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs,
+ int reservedFlags) {
+ // SensorDirectConnection does not support enableDisable, parameters not used
+ UNUSED(handle);
+ UNUSED(enabled);
+ UNUSED(samplingPeriodNs);
+ UNUSED(maxBatchReportLatencyNs);
+ UNUSED(reservedFlags);
+ return INVALID_OPERATION;
+}
+
+status_t SensorService::SensorDirectConnection::setEventRate(
+ int handle, nsecs_t samplingPeriodNs) {
+ // SensorDirectConnection does not support setEventRate, parameters not used
+ UNUSED(handle);
+ UNUSED(samplingPeriodNs);
+ return INVALID_OPERATION;
+}
+
+status_t SensorService::SensorDirectConnection::flush() {
+ // SensorDirectConnection does not support flush
+ return INVALID_OPERATION;
+}
+
+int32_t SensorService::SensorDirectConnection::configureChannel(int handle, int rateLevel) {
+
+ if (handle == -1 && rateLevel == SENSOR_DIRECT_RATE_STOP) {
+ stopAll();
+ return NO_ERROR;
+ }
+
+ if (mService->isOperationRestricted(mOpPackageName)) {
+ return PERMISSION_DENIED;
+ }
+
+ sp<SensorInterface> si = mService->getSensorInterfaceFromHandle(handle);
+ if (si == nullptr) {
+ return NAME_NOT_FOUND;
+ }
+
+ const Sensor& s = si->getSensor();
+ if (!SensorService::canAccessSensor(s, "config direct channel", mOpPackageName)) {
+ return PERMISSION_DENIED;
+ }
+
+ if (s.getHighestDirectReportRateLevel() == 0
+ || rateLevel > s.getHighestDirectReportRateLevel()
+ || !s.isDirectChannelTypeSupported(mMem.type)) {
+ return INVALID_OPERATION;
+ }
+
+ struct sensors_direct_cfg_t config = {
+ .rate_level = rateLevel
+ };
+
+ Mutex::Autolock _l(mConnectionLock);
+ SensorDevice& dev(SensorDevice::getInstance());
+ int ret = dev.configureDirectChannel(handle, getHalChannelHandle(), &config);
+
+ if (rateLevel == SENSOR_DIRECT_RATE_STOP) {
+ if (ret == NO_ERROR) {
+ mActivated.erase(handle);
+ } else if (ret > 0) {
+ ret = UNKNOWN_ERROR;
+ }
+ } else {
+ if (ret > 0) {
+ mActivated[handle] = rateLevel;
+ }
+ }
+
+ return ret;
+}
+
+void SensorService::SensorDirectConnection::stopAll(bool backupRecord) {
+
+ struct sensors_direct_cfg_t config = {
+ .rate_level = SENSOR_DIRECT_RATE_STOP
+ };
+
+ Mutex::Autolock _l(mConnectionLock);
+ SensorDevice& dev(SensorDevice::getInstance());
+ for (auto &i : mActivated) {
+ dev.configureDirectChannel(i.first, getHalChannelHandle(), &config);
+ }
+
+ if (backupRecord && mActivatedBackup.empty()) {
+ mActivatedBackup = mActivated;
+ }
+ mActivated.clear();
+}
+
+void SensorService::SensorDirectConnection::recoverAll() {
+ stopAll(false);
+
+ Mutex::Autolock _l(mConnectionLock);
+ SensorDevice& dev(SensorDevice::getInstance());
+
+ // recover list of report from backup
+ mActivated = mActivatedBackup;
+ mActivatedBackup.clear();
+
+ // re-enable them
+ for (auto &i : mActivated) {
+ struct sensors_direct_cfg_t config = {
+ .rate_level = i.second
+ };
+ dev.configureDirectChannel(i.first, getHalChannelHandle(), &config);
+ }
+}
+
+int32_t SensorService::SensorDirectConnection::getHalChannelHandle() const {
+ return mHalChannelHandle;
+}
+
+bool SensorService::SensorDirectConnection::isEquivalent(const sensors_direct_mem_t *mem) const {
+ bool ret = false;
+
+ if (mMem.type == mem->type) {
+ switch (mMem.type) {
+ case SENSOR_DIRECT_MEM_TYPE_ASHMEM: {
+ struct stat s1, s2;
+ int fd1, fd2;
+ fd1 = mMem.handle->data[0];
+ fd2 = mem->handle->data[1];
+ if (fstat(fd1, &s1) < 0 || fstat(fd2, &s2) < 0 || s1.st_ino == s2.st_ino) {
+ ret = true;
+ }
+ }
+ case SENSOR_DIRECT_MEM_TYPE_GRALLOC:
+ LOG_FATAL("%s: Implement GRALLOC or remove", __FUNCTION__);
+ ret = true;
+ default:
+ ALOGE("Unexpected mem type %d", mMem.type);
+ ret = true;
+ }
+ }
+ return ret;
+}
+
+} // namespace android
+
diff --git a/services/sensorservice/SensorDirectConnection.h b/services/sensorservice/SensorDirectConnection.h
new file mode 100644
index 0000000..692ef0d
--- /dev/null
+++ b/services/sensorservice/SensorDirectConnection.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2016 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_SENSOR_DIRECT_CONNECTION_H
+#define ANDROID_SENSOR_DIRECT_CONNECTION_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/BinderService.h>
+
+#include <gui/Sensor.h>
+#include <gui/BitTube.h>
+#include <gui/ISensorServer.h>
+#include <gui/ISensorEventConnection.h>
+
+#include "SensorService.h"
+
+namespace android {
+
+class SensorService;
+class BitTube;
+
+class SensorService::SensorDirectConnection: public BnSensorEventConnection {
+public:
+ SensorDirectConnection(const sp<SensorService>& service, uid_t uid,
+ const sensors_direct_mem_t *mem, int32_t halChannelHandle,
+ const String16& opPackageName);
+ void dump(String8& result) const;
+ uid_t getUid() const { return mUid; }
+ int32_t getHalChannelHandle() const;
+ bool isEquivalent(const sensors_direct_mem_t *mem) const;
+
+ // stop all active sensor report. if backupRecord is set to false,
+ // those report can be recovered by recoverAll
+ // called by SensorService when enter restricted mode
+ void stopAll(bool clearRecord = false);
+
+ // recover sensor reports previously stopped by stopAll(true)
+ // called by SensorService when return to NORMAL mode.
+ void recoverAll();
+
+protected:
+ virtual ~SensorDirectConnection();
+ // ISensorEventConnection functions
+ virtual void onFirstRef();
+ virtual sp<BitTube> getSensorChannel() const;
+ virtual status_t enableDisable(int handle, bool enabled, nsecs_t samplingPeriodNs,
+ nsecs_t maxBatchReportLatencyNs, int reservedFlags);
+ virtual status_t setEventRate(int handle, nsecs_t samplingPeriodNs);
+ virtual status_t flush();
+ virtual int32_t configureChannel(int handle, int rateLevel);
+
+private:
+ const sp<SensorService> mService;
+ const uid_t mUid;
+ const sensors_direct_mem_t mMem;
+ const int32_t mHalChannelHandle;
+ const String16 mOpPackageName;
+
+ mutable Mutex mConnectionLock;
+ std::unordered_map<int, int> mActivated;
+ std::unordered_map<int, int> mActivatedBackup;
+};
+
+} // namepsace android
+
+#endif // ANDROID_SENSOR_DIRECT_CONNECTION_H
+
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index f2f1444..d84d36e 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -23,6 +23,8 @@
#include "SensorEventConnection.h"
#include "SensorDevice.h"
+#define UNUSED(x) (void)(x)
+
namespace android {
SensorService::SensorEventConnection::SensorEventConnection(
@@ -524,6 +526,13 @@
return mService->flushSensor(this, mOpPackageName);
}
+int32_t SensorService::SensorEventConnection::configureChannel(int handle, int rateLevel) {
+ // SensorEventConnection does not support configureChannel, parameters not used
+ UNUSED(handle);
+ UNUSED(rateLevel);
+ return INVALID_OPERATION;
+}
+
int SensorService::SensorEventConnection::handleEvent(int fd, int events, void* /*data*/) {
if (events & ALOOPER_EVENT_HANGUP || events & ALOOPER_EVENT_ERROR) {
{
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index 883c16e..cd81ddd 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -74,6 +74,8 @@
nsecs_t maxBatchReportLatencyNs, int reservedFlags);
virtual status_t setEventRate(int handle, nsecs_t samplingPeriodNs);
virtual status_t flush();
+ virtual int32_t configureChannel(int handle, int rateLevel);
+
// Count the number of flush complete events which are about to be dropped in the buffer.
// Increment mPendingFlushEventsToSend in mSensorInfo. These flush complete events will be sent
// separately before the next batch of events.
diff --git a/services/sensorservice/SensorList.cpp b/services/sensorservice/SensorList.cpp
index e0101c1..31c8251 100644
--- a/services/sensorservice/SensorList.cpp
+++ b/services/sensorservice/SensorList.cpp
@@ -124,7 +124,7 @@
forEachSensor([&result] (const Sensor& s) -> bool {
result.appendFormat(
"%#010x) %-25s | %-15s | ver: %" PRId32 " | type: %20s(%" PRId32
- ") | perm: %s\n\t",
+ ") | perm: %s\n",
s.getHandle(),
s.getName().string(),
s.getVendor().string(),
@@ -133,17 +133,18 @@
s.getType(),
s.getRequiredPermission().size() ? s.getRequiredPermission().string() : "n/a");
+ result.append("\t");
const int reportingMode = s.getReportingMode();
if (reportingMode == AREPORTING_MODE_CONTINUOUS) {
- result.append(" continuous | ");
+ result.append("continuous | ");
} else if (reportingMode == AREPORTING_MODE_ON_CHANGE) {
- result.append(" on-change | ");
+ result.append("on-change | ");
} else if (reportingMode == AREPORTING_MODE_ONE_SHOT) {
- result.append(" one-shot | ");
+ result.append("one-shot | ");
} else if (reportingMode == AREPORTING_MODE_SPECIAL_TRIGGER) {
- result.append(" special-trigger | ");
+ result.append("special-trigger | ");
} else {
- result.append(" unknown-mode | ");
+ result.append("unknown-mode | ");
}
if (s.getMaxDelay() > 0) {
@@ -178,8 +179,19 @@
if (s.hasAdditionalInfo()) {
result.appendFormat("has-additional-info, ");
}
-
result.append("\n");
+
+ if (s.getHighestDirectReportRateLevel() > SENSOR_DIRECT_RATE_STOP) {
+ result.appendFormat("\thighest rate level = %d, support shared mem: ",
+ s.getHighestDirectReportRateLevel());
+ if (s.isDirectChannelTypeSupported(SENSOR_DIRECT_MEM_TYPE_ASHMEM)) {
+ result.append("ashmem, ");
+ }
+ if (s.isDirectChannelTypeSupported(SENSOR_DIRECT_MEM_TYPE_GRALLOC)) {
+ result.append("gralloc, ");
+ }
+ result.append("\n");
+ }
return true;
});
return std::string(result.string());
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 2e44736..143a3c5 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -21,6 +21,7 @@
#include <binder/IServiceManager.h>
#include <binder/PermissionCache.h>
+#include <cutils/ashmem.h>
#include <gui/SensorEventQueue.h>
#include <hardware/sensors.h>
@@ -40,6 +41,7 @@
#include "SensorInterface.h"
#include "SensorService.h"
+#include "SensorDirectConnection.h"
#include "SensorEventAckReceiver.h"
#include "SensorEventConnection.h"
#include "SensorRecord.h"
@@ -337,7 +339,16 @@
if (mCurrentOperatingMode != NORMAL) {
return INVALID_OPERATION;
}
+
mCurrentOperatingMode = RESTRICTED;
+ // temporarily stop all sensor direct report
+ for (auto &i : mDirectConnections) {
+ sp<SensorDirectConnection> connection(i.promote());
+ if (connection != nullptr) {
+ connection->stopAll(true /* backupRecord */);
+ }
+ }
+
dev.disableAllSensors();
// Clear all pending flush connections for all active sensors. If one of the active
// connections has called flush() and the underlying sensor has been disabled before a
@@ -352,6 +363,13 @@
if (mCurrentOperatingMode == RESTRICTED) {
mCurrentOperatingMode = NORMAL;
dev.enableAllSensors();
+ // recover all sensor direct report
+ for (auto &i : mDirectConnections) {
+ sp<SensorDirectConnection> connection(i.promote());
+ if (connection != nullptr) {
+ connection->recoverAll();
+ }
+ }
}
if (mCurrentOperatingMode == DATA_INJECTION) {
resetToNormalModeLocked();
@@ -430,8 +448,8 @@
case DATA_INJECTION:
result.appendFormat(" DATA_INJECTION : %s\n", mWhiteListedPackage.string());
}
- result.appendFormat("%zd active connections\n", mActiveConnections.size());
+ result.appendFormat("%zd active connections\n", mActiveConnections.size());
for (size_t i=0 ; i < mActiveConnections.size() ; i++) {
sp<SensorEventConnection> connection(mActiveConnections[i].promote());
if (connection != 0) {
@@ -440,6 +458,15 @@
}
}
+ result.appendFormat("%zd direct connections\n", mDirectConnections.size());
+ for (size_t i = 0 ; i < mDirectConnections.size() ; i++) {
+ sp<SensorDirectConnection> connection(mDirectConnections[i].promote());
+ if (connection != nullptr) {
+ result.appendFormat("Direct connection %zu:\n", i);
+ connection->dump(result);
+ }
+ }
+
result.appendFormat("Previous Registrations:\n");
// Log in the reverse chronological order.
int currentIndex = (mNextSensorRegIndex - 1 + SENSOR_REGISTRATIONS_BUF_SIZE) %
@@ -936,6 +963,85 @@
return (mCurrentOperatingMode == DATA_INJECTION);
}
+sp<ISensorEventConnection> SensorService::createSensorDirectConnection(
+ const String16& opPackageName, uint32_t size, int32_t type, int32_t format,
+ const native_handle *resource) {
+ Mutex::Autolock _l(mLock);
+
+ struct sensors_direct_mem_t mem = {
+ .type = type,
+ .format = format,
+ .size = size,
+ .handle = resource,
+ };
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+
+ if (mem.handle == nullptr) {
+ ALOGE("Failed to clone resource handle");
+ return nullptr;
+ }
+
+ // check format
+ if (format != SENSOR_DIRECT_FMT_SENSORS_EVENT) {
+ ALOGE("Direct channel format %d is unsupported!", format);
+ return nullptr;
+ }
+
+ // check for duplication
+ for (auto &i : mDirectConnections) {
+ sp<SensorDirectConnection> connection(i.promote());
+ if (connection != nullptr && connection->isEquivalent(&mem)) {
+ return nullptr;
+ }
+ }
+
+ // check specific to memory type
+ switch(type) {
+ case SENSOR_DIRECT_MEM_TYPE_ASHMEM: { // channel backed by ashmem
+ int fd = resource->data[0];
+ int size2 = ashmem_get_size_region(fd);
+ // check size consistency
+ if (size2 != static_cast<int>(size)) {
+ ALOGE("Ashmem direct channel size mismatch, %" PRIu32 " vs %d", size, size2);
+ return nullptr;
+ }
+ break;
+ }
+ case SENSOR_DIRECT_MEM_TYPE_GRALLOC:
+ LOG_FATAL("%s: Finish implementation of ION and GRALLOC or remove", __FUNCTION__);
+ break;
+ default:
+ ALOGE("Unknown direct connection memory type %d", type);
+ return nullptr;
+ }
+
+ native_handle_t *clone = native_handle_clone(resource);
+ if (!clone) {
+ return nullptr;
+ }
+
+ SensorDirectConnection* conn = nullptr;
+ SensorDevice& dev(SensorDevice::getInstance());
+ int channelHandle = dev.registerDirectChannel(&mem);
+
+ if (channelHandle <= 0) {
+ ALOGE("SensorDevice::registerDirectChannel returns %d", channelHandle);
+ } else {
+ mem.handle = clone;
+ conn = new SensorDirectConnection(this, uid, &mem, channelHandle, opPackageName);
+ }
+
+ if (conn == nullptr) {
+ native_handle_close(clone);
+ native_handle_delete(clone);
+ } else {
+ // add to list of direct connections
+ // sensor service should never hold pointer or sp of SensorDirectConnection object.
+ mDirectConnections.add(wp<SensorDirectConnection>(conn));
+ }
+ return conn;
+}
+
status_t SensorService::resetToNormalMode() {
Mutex::Autolock _l(mLock);
return resetToNormalModeLocked();
@@ -995,11 +1101,18 @@
dev.notifyConnectionDestroyed(c);
}
+void SensorService::cleanupConnection(SensorDirectConnection* c) {
+ Mutex::Autolock _l(mLock);
+
+ SensorDevice& dev(SensorDevice::getInstance());
+ dev.unregisterDirectChannel(c->getHalChannelHandle());
+ mDirectConnections.remove(c);
+}
+
sp<SensorInterface> SensorService::getSensorInterfaceFromHandle(int handle) const {
return mSensors.getInterface(handle);
}
-
status_t SensorService::enable(const sp<SensorEventConnection>& connection,
int handle, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags,
const String16& opPackageName) {
@@ -1013,7 +1126,7 @@
}
Mutex::Autolock _l(mLock);
- if ((mCurrentOperatingMode == RESTRICTED || mCurrentOperatingMode == DATA_INJECTION)
+ if (mCurrentOperatingMode != NORMAL
&& !isWhiteListedPackage(connection->getPackageName())) {
return INVALID_OPERATION;
}
@@ -1331,5 +1444,14 @@
return (packageName.contains(mWhiteListedPackage.string()));
}
+bool SensorService::isOperationRestricted(const String16& opPackageName) {
+ Mutex::Autolock _l(mLock);
+ if (mCurrentOperatingMode != RESTRICTED) {
+ String8 package(opPackageName);
+ return !isWhiteListedPackage(package);
+ }
+ return false;
+}
+
}; // namespace android
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index e969d8a..eeedd4a 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -67,9 +67,11 @@
{
// nested class/struct for internal use
class SensorEventConnection;
+ class SensorDirectConnection;
public:
void cleanupConnection(SensorEventConnection* connection);
+ void cleanupConnection(SensorDirectConnection* c);
status_t enable(const sp<SensorEventConnection>& connection, int handle,
nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags,
@@ -154,6 +156,8 @@
const String8& packageName,
int requestedMode, const String16& opPackageName);
virtual int isDataInjectionEnabled();
+ virtual sp<ISensorEventConnection> createSensorDirectConnection(const String16& opPackageName,
+ uint32_t size, int32_t type, int32_t format, const native_handle *resource);
virtual status_t dump(int fd, const Vector<String16>& args);
String8 getSensorName(int handle) const;
@@ -203,6 +207,7 @@
// allowed to register for or call flush on sensors. Typically only cts test packages are
// allowed.
bool isWhiteListedPackage(const String8& packageName);
+ bool isOperationRestricted(const String16& opPackageName);
// Reset the state of SensorService to NORMAL mode.
status_t resetToNormalMode();
@@ -239,6 +244,7 @@
sensors_event_t *mSensorEventBuffer, *mSensorEventScratch;
wp<const SensorEventConnection> * mMapFlushEventsToConnections;
std::unordered_map<int, RecentEventLogger*> mRecentEvent;
+ SortedVector< wp<SensorDirectConnection> > mDirectConnections;
Mode mCurrentOperatingMode;
// This packagaName is set when SensorService is in RESTRICTED or DATA_INJECTION mode. Only
diff --git a/services/surfaceflinger/Colorizer.h b/services/surfaceflinger/Colorizer.h
index f2e6491..d56b1c8 100644
--- a/services/surfaceflinger/Colorizer.h
+++ b/services/surfaceflinger/Colorizer.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_SURFACE_FLINGER_COLORIZER_H
#define ANDROID_SURFACE_FLINGER_COLORIZER_H
+#include <utils/String8.h>
+
namespace android {
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 9eaf57b..72f6a7e 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1796,7 +1796,7 @@
}
#ifdef USE_HWC2
-void Layer::releasePendingBuffer() {
+void Layer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
mSurfaceFlingerConsumer->releasePendingBuffer();
auto releaseFenceTime = std::make_shared<FenceTime>(
mSurfaceFlingerConsumer->getPrevFinalReleaseFence());
@@ -1804,7 +1804,7 @@
Mutex::Autolock lock(mFrameEventHistoryMutex);
mFrameEventHistory.addRelease(
- mPreviousFrameNumber, std::move(releaseFenceTime));
+ mPreviousFrameNumber, dequeueReadyTime, std::move(releaseFenceTime));
}
#endif
@@ -1981,7 +1981,7 @@
mSurfaceFlingerConsumer->getPrevFinalReleaseFence());
mReleaseTimeline.push(releaseFenceTime);
mFrameEventHistory.addRelease(
- mPreviousFrameNumber, std::move(releaseFenceTime));
+ mPreviousFrameNumber, latchTime, std::move(releaseFenceTime));
#endif
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index c3eab37..92d2292 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -286,7 +286,7 @@
#ifdef USE_HWC2
// If a buffer was replaced this frame, release the former buffer
- void releasePendingBuffer();
+ void releasePendingBuffer(nsecs_t dequeueReadyTime);
#endif
/*
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index db6b366..5f25ef5 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -575,10 +575,13 @@
*outSupported = {
FrameEvent::REQUESTED_PRESENT,
FrameEvent::ACQUIRE,
+ FrameEvent::LATCH,
FrameEvent::FIRST_REFRESH_START,
+ FrameEvent::LAST_REFRESH_START,
FrameEvent::GL_COMPOSITION_DONE,
getHwComposer().presentFenceRepresentsStartOfScanout() ?
FrameEvent::DISPLAY_PRESENT : FrameEvent::DISPLAY_RETIRE,
+ FrameEvent::DEQUEUE_READY,
FrameEvent::RELEASE,
};
return NO_ERROR;
@@ -1226,8 +1229,9 @@
ALOGV("postComposition");
// Release any buffers which were replaced this frame
+ nsecs_t dequeueReadyTime = systemTime();
for (auto& layer : mLayersWithQueuedFrames) {
- layer->releasePendingBuffer();
+ layer->releasePendingBuffer(dequeueReadyTime);
}
const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 0d05e9e..fcf0185 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -608,9 +608,12 @@
*outSupported = {
FrameEvent::REQUESTED_PRESENT,
FrameEvent::ACQUIRE,
+ FrameEvent::LATCH,
FrameEvent::FIRST_REFRESH_START,
+ FrameEvent::LAST_REFRESH_START,
FrameEvent::GL_COMPOSITION_DONE,
FrameEvent::DISPLAY_RETIRE,
+ FrameEvent::DEQUEUE_READY,
FrameEvent::RELEASE,
};
return NO_ERROR;
diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
index ed89fc6..93b90d0 100644
--- a/vulkan/api/vulkan.api
+++ b/vulkan/api/vulkan.api
@@ -150,6 +150,9 @@
@extension("VK_NVX_device_generated_commands") define VK_NVX_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 1
@extension("VK_NVX_device_generated_commands") define VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME "VK_NVX_device_generated_commands"
+@extension("VK_KHR_swapchain_front_buffered") define VK_KHR_SWAPCHAIN_FRONT_BUFFERED_SPEC_VERSION 2
+@extension("VK_KHR_swapchain_front_buffered") define VK_KHR_SWAPCHAIN_FRONT_BUFFERED_EXTENSION_NAME "VK_KHR_swapchain_front_buffered"
+
/////////////
@@ -757,7 +760,7 @@
VK_STRUCTURE_TYPE_SWAPCHAIN_IMAGE_CREATE_INFO_ANDROID = 1000010001,
//@extension("VK_GOOGLE_display_timing")
- VK_STRUCTURE_TYPE_PRESENT_TIMES_GOOGLE = 1000092000,
+ VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE = 1000092000,
//@extension("VK_EXT_debug_report")
VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT = 1000011000,
@@ -924,6 +927,10 @@
VK_PRESENT_MODE_MAILBOX_KHR = 0x00000001,
VK_PRESENT_MODE_FIFO_KHR = 0x00000002,
VK_PRESENT_MODE_FIFO_RELAXED_KHR = 0x00000003,
+ //@extension("VK_KHR_swapchain_front_buffered")
+ VK_PRESENT_MODE_FRONT_BUFFERED_DEMAND_REFRESH_KHR = 1000111000,
+ //@extension("VK_KHR_swapchain_front_buffered")
+ VK_PRESENT_MODE_FRONT_BUFFERED_CONTINUOUS_REFRESH_KHR = 1000111001,
}
@extension("VK_KHR_surface")
@@ -2886,27 +2893,6 @@
platform.HWND hwnd
}
-@extension("VK_KHR_incremental_present")
-class VkRectLayerKHR {
- VkOffset2D offset
- VkExtent2D extent
- uint32_t layer
-}
-
-@extension("VK_KHR_incremental_present")
-class VkPresentRegionKHR {
- uint32_t rectangleCount
- const VkRectLayerKHR* pRectangles
-}
-
-@extension("VK_KHR_incremental_present")
-class VkPresentRegionsKHR {
- VkStructureType sType
- const void* pNext
- uint32_t swapchainCount
- const VkPresentRegionKHR* pRegions
-}
-
@extension("VK_ANDROID_native_buffer")
class VkNativeBufferANDROID {
VkStructureType sType
@@ -2921,34 +2907,35 @@
class VkSwapchainImageCreateInfoANDROID {
VkStructureType sType
const void* pNext
- VkSwapchainImageUsageFlagBitsANDROID flags
+ VkSwapchainImageUsageFlagsANDROID flags
+}
@extension("VK_GOOGLE_display_timing")
class VkRefreshCycleDurationGOOGLE {
- uint64_t minRefreshDuration
- uint64_t maxRefreshDuration
+ u64 minRefreshDuration
+ u64 maxRefreshDuration
}
@extension("VK_GOOGLE_display_timing")
class VkPastPresentationTimingGOOGLE {
- uint32_t presentID
- uint64_t desiredPresentTime
- uint64_t actualPresentTime
- uint64_t earliestPresentTime
- uint64_t presentMargin
+ u32 presentID
+ u64 desiredPresentTime
+ u64 actualPresentTime
+ u64 earliestPresentTime
+ u64 presentMargin
}
@extension("VK_GOOGLE_display_timing")
class VkPresentTimeGOOGLE {
- uint32_t presentID
- uint64_t desiredPresentTime
+ u32 presentID
+ u64 desiredPresentTime
}
@extension("VK_GOOGLE_display_timing")
class VkPresentTimesInfoGOOGLE {
VkStructureType sType
const void* pNext
- uint32_t swapchainCount
+ u32 swapchainCount
const VkPresentTimeGOOGLE* pTimes
}
@@ -5889,18 +5876,6 @@
VkSwapchainKHR swapchain,
u32* pPresentationTimingCount,
VkPastPresentationTimingGOOGLE* pPresentationTimings) {
- deviceObject := GetDevice(device)
-
- count := as!u32(?)
- pPresentationTimingCount[0] = count
- presentationTimings := pPresentationTimings[0:count]
-
- for i in (0 .. count) {
- presentationTiming := ?
- presentationTimings[i] = presentationTiming
- State.Timings[presentationTiming] = new!PresentationTiming(device: device)
- }
-
return ?
}
@@ -6141,6 +6116,13 @@
VkDeviceGeneratedCommandsLimitsNVX* pLimits) {
}
+@extension("VK_KHR_swapchain_front_buffered")
+cmd VkResult vkGetSwapchainStatusKHR(
+ VkDevice device,
+ VkSwapchainKHR swapchain) {
+ return ?
+}
+
////////////////
// Validation //
diff --git a/vulkan/doc/implementors_guide/implementors_guide.adoc b/vulkan/doc/implementors_guide/implementors_guide.adoc
index ce21791..dc18e9d 100644
--- a/vulkan/doc/implementors_guide/implementors_guide.adoc
+++ b/vulkan/doc/implementors_guide/implementors_guide.adoc
@@ -123,7 +123,7 @@
VkStructureType sType; // must be VK_STRUCTURE_TYPE_SWAPCHAIN_IMAGE_CREATE_INFO_ANDROID
const void* pNext;
- VkSwapchainImageUsageFlagBitsANDROID usage;
+ VkSwapchainImageUsageFlagsANDROID usage;
} VkSwapchainImageCreateInfoANDROID;
----
diff --git a/vulkan/doc/implementors_guide/implementors_guide.html b/vulkan/doc/implementors_guide/implementors_guide.html
index 5ff1269..ce52c7f 100644
--- a/vulkan/doc/implementors_guide/implementors_guide.html
+++ b/vulkan/doc/implementors_guide/implementors_guide.html
@@ -876,7 +876,7 @@
<span style="color: #008080">VkStructureType</span> sType<span style="color: #990000">;</span> <span style="font-style: italic"><span style="color: #9A1900">// must be VK_STRUCTURE_TYPE_SWAPCHAIN_IMAGE_CREATE_INFO_ANDROID</span></span>
<span style="font-weight: bold"><span style="color: #0000FF">const</span></span> <span style="color: #009900">void</span><span style="color: #990000">*</span> pNext<span style="color: #990000">;</span>
- <span style="color: #008080">VkSwapchainImageUsageFlagBitsANDROID</span> usage<span style="color: #990000">;</span>
+ <span style="color: #008080">VkSwapchainImageUsageFlagsANDROID</span> usage<span style="color: #990000">;</span>
<span style="color: #FF0000">}</span> VkSwapchainImageCreateInfoANDROID<span style="color: #990000">;</span></tt></pre></div></div>
<div class="paragraph"><p><span class="monospaced">vkAcquireImageANDROID</span> acquires ownership of a swapchain image and imports an
externally-signalled native fence into both an existing VkSemaphore object
@@ -1052,7 +1052,7 @@
<div id="footer">
<div id="footer-text">
Version 5<br>
-Last updated 2017-01-09 09:52:43 NZDT
+Last updated 2017-01-12 14:25:30 NZDT
</div>
</div>
</body>
diff --git a/vulkan/include/vulkan/vk_android_native_buffer.h b/vulkan/include/vulkan/vk_android_native_buffer.h
index 0fd041a..a2ab07b 100644
--- a/vulkan/include/vulkan/vk_android_native_buffer.h
+++ b/vulkan/include/vulkan/vk_android_native_buffer.h
@@ -32,6 +32,7 @@
#define VK_ANDROID_NATIVE_BUFFER_ENUM(type,id) ((type)(1000000000 + (1000 * (VK_ANDROID_NATIVE_BUFFER_EXTENSION_NUMBER - 1)) + (id)))
#define VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID VK_ANDROID_NATIVE_BUFFER_ENUM(VkStructureType, 0)
+#define VK_STRUCTURE_TYPE_SWAPCHAIN_IMAGE_CREATE_INFO_ANDROID VK_ANDROID_NATIVE_BUFFER_ENUM(VkStructureType, 1)
typedef enum VkSwapchainImageUsageFlagBitsANDROID {
VK_SWAPCHAIN_IMAGE_USAGE_FRONT_BUFFER_BIT_ANDROID = 0x00000001,
@@ -56,7 +57,7 @@
VkStructureType sType; // must be VK_STRUCTURE_TYPE_SWAPCHAIN_IMAGE_CREATE_INFO_ANDROID
const void* pNext;
- VkSwapchainImageUsageFlagBitsANDROID usage;
+ VkSwapchainImageUsageFlagsANDROID usage;
} VkSwapchainImageCreateInfoANDROID;
typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainGrallocUsageANDROID)(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int* grallocUsage);
diff --git a/vulkan/include/vulkan/vulkan.h b/vulkan/include/vulkan/vulkan.h
index 6ddce8f..5d38ff9 100644
--- a/vulkan/include/vulkan/vulkan.h
+++ b/vulkan/include/vulkan/vulkan.h
@@ -242,7 +242,7 @@
VK_STRUCTURE_TYPE_CMD_RESERVE_SPACE_FOR_COMMANDS_INFO_NVX = 1000086003,
VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_LIMITS_NVX = 1000086004,
VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_FEATURES_NVX = 1000086005,
- VK_STRUCTURE_TYPE_PRESENT_TIMES_GOOGLE = 1000092000,
+ VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE = 1000092000,
VK_STRUCTURE_TYPE_BEGIN_RANGE = VK_STRUCTURE_TYPE_APPLICATION_INFO,
VK_STRUCTURE_TYPE_END_RANGE = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO,
VK_STRUCTURE_TYPE_RANGE_SIZE = (VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO - VK_STRUCTURE_TYPE_APPLICATION_INFO + 1),
@@ -3228,6 +3228,8 @@
VK_PRESENT_MODE_MAILBOX_KHR = 1,
VK_PRESENT_MODE_FIFO_KHR = 2,
VK_PRESENT_MODE_FIFO_RELAXED_KHR = 3,
+ VK_PRESENT_MODE_FRONT_BUFFERED_DEMAND_REFRESH_KHR = 1000111000,
+ VK_PRESENT_MODE_FRONT_BUFFERED_CONTINUOUS_REFRESH_KHR = 1000111001,
VK_PRESENT_MODE_BEGIN_RANGE_KHR = VK_PRESENT_MODE_IMMEDIATE_KHR,
VK_PRESENT_MODE_END_RANGE_KHR = VK_PRESENT_MODE_FIFO_RELAXED_KHR,
VK_PRESENT_MODE_RANGE_SIZE_KHR = (VK_PRESENT_MODE_FIFO_RELAXED_KHR - VK_PRESENT_MODE_IMMEDIATE_KHR + 1),
@@ -3884,6 +3886,18 @@
const VkPresentRegionKHR* pRegions;
} VkPresentRegionsKHR;
+#define VK_KHR_swapchain_front_buffered 1
+#define VK_KHR_SWAPCHAIN_FRONT_BUFFERED_SPEC_VERSION 2
+#define VK_KHR_SWAPCHAIN_FRONT_BUFFERED_EXTENSION_NAME "VK_KHR_swapchain_front_buffered"
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainStatusKHR)(VkDevice device, VkSwapchainKHR swapchain);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainStatusKHR(
+ VkDevice device,
+ VkSwapchainKHR swapchain);
+#endif
+
#define VK_EXT_debug_report 1
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT)
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index ba883f7..746ab4e 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -69,6 +69,7 @@
"vulkan_headers",
],
shared_libs: [
+ "libgui",
"libziparchive",
"libhardware",
"libsync",
diff --git a/vulkan/libvulkan/api_gen.cpp b/vulkan/libvulkan/api_gen.cpp
index a33b1b7..b8b7e94 100644
--- a/vulkan/libvulkan/api_gen.cpp
+++ b/vulkan/libvulkan/api_gen.cpp
@@ -427,8 +427,6 @@
VKAPI_ATTR VkResult AcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex);
VKAPI_ATTR VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* pPresentInfo);
VKAPI_ATTR VkResult CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
-VKAPI_ATTR VkResult GetRefreshCycleDurationGOOGLE(VkDevice device, VkSwapchainKHR swapchain, VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties);
-VKAPI_ATTR VkResult GetPastPresentationTimingGOOGLE(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pPresentationTimingCount, VkPastPresentationTimingGOOGLE* pPresentationTimings);
VKAPI_ATTR VkResult EnumeratePhysicalDevices(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices) {
return GetData(instance).dispatch.EnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices);
@@ -1212,14 +1210,6 @@
return GetData(instance).dispatch.CreateAndroidSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface);
}
-VKAPI_ATTR VkResult GetRefreshCycleDurationGOOGLE(VkDevice device, VkSwapchainKHR swapchain, VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties) {
- return GetData(device).dispatch.GetRefreshCycleDurationGOOGLE(device, swapchain, pDisplayTimingProperties);
-}
-
-VKAPI_ATTR VkResult GetPastPresentationTimingGOOGLE(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pPresentationTimingCount, VkPastPresentationTimingGOOGLE* pPresentationTimings) {
- return GetData(device).dispatch.GetPastPresentationTimingGOOGLE(device, swapchain, pPresentationTimingCount, pPresentationTimings);
-}
-
} // anonymous namespace
diff --git a/vulkan/libvulkan/api_gen.h b/vulkan/libvulkan/api_gen.h
index 918c1f5..7f8d274 100644
--- a/vulkan/libvulkan/api_gen.h
+++ b/vulkan/libvulkan/api_gen.h
@@ -177,8 +177,6 @@
PFN_vkGetSwapchainImagesKHR GetSwapchainImagesKHR;
PFN_vkAcquireNextImageKHR AcquireNextImageKHR;
PFN_vkQueuePresentKHR QueuePresentKHR;
- PFN_vkGetRefreshCycleDurationGOOGLE GetRefreshCycleDurationGOOGLE;
- PFN_vkGetPastPresentationTimingGOOGLE GetPastPresentationTimingGOOGLE;
// clang-format on
};
diff --git a/vulkan/libvulkan/code-generator.tmpl b/vulkan/libvulkan/code-generator.tmpl
index dd64d45..9021972 100644
--- a/vulkan/libvulkan/code-generator.tmpl
+++ b/vulkan/libvulkan/code-generator.tmpl
@@ -704,8 +704,8 @@
VK_KHR_incremental_present
VK_KHR_surface
VK_KHR_swapchain
-VK_KHR_incremental_present
VK_GOOGLE_display_timing
+VK_KHR_swapchain_front_buffered
{{end}}
@@ -1152,8 +1152,6 @@
{{ if eq $ext "VK_KHR_surface"}}true
{{else if eq $ext "VK_KHR_swapchain"}}true
{{else if eq $ext "VK_KHR_android_surface"}}true
- {{else if eq $ext "VK_KHR_incremental_present"}}true
- {{else if eq $ext "VK_GOOGLE_display_timing"}}true
{{end}}
{{end}}
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 800e474..46b29ca 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -21,10 +21,15 @@
#include <algorithm>
#include <array>
+#include <dlfcn.h>
#include <new>
#include <log/log.h>
+#include <android/dlext.h>
+#include <cutils/properties.h>
+#include <gui/GraphicsEnv.h>
+
#include "driver.h"
#include "stubhal.h"
@@ -126,17 +131,74 @@
Hal Hal::hal_;
+void* LoadLibrary(const android_dlextinfo& dlextinfo,
+ const char* subname,
+ int subname_len) {
+ const char kLibFormat[] = "vulkan.%*s.so";
+ char* name = static_cast<char*>(
+ alloca(sizeof(kLibFormat) + static_cast<size_t>(subname_len)));
+ sprintf(name, kLibFormat, subname_len, subname);
+ return android_dlopen_ext(name, RTLD_LOCAL | RTLD_NOW, &dlextinfo);
+}
+
+const std::array<const char*, 2> HAL_SUBNAME_KEY_PROPERTIES = {{
+ "ro.hardware." HWVULKAN_HARDWARE_MODULE_ID,
+ "ro.board.platform",
+}};
+
+int LoadUpdatedDriver(const hw_module_t** module) {
+ const android_dlextinfo dlextinfo = {
+ .flags = ANDROID_DLEXT_USE_NAMESPACE,
+ .library_namespace = android::GraphicsEnv::getInstance().getDriverNamespace(),
+ };
+ if (!dlextinfo.library_namespace)
+ return -ENOENT;
+
+ void* so = nullptr;
+ char prop[PROPERTY_VALUE_MAX];
+ for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
+ int prop_len = property_get(key, prop, nullptr);
+ if (prop_len > 0) {
+ so = LoadLibrary(dlextinfo, prop, prop_len);
+ if (so)
+ break;
+ }
+ }
+ if (!so)
+ return -ENOENT;
+
+ hw_module_t* hmi = static_cast<hw_module_t*>(dlsym(so, HAL_MODULE_INFO_SYM_AS_STR));
+ if (!hmi) {
+ ALOGE("couldn't find symbol '%s' in HAL library: %s", HAL_MODULE_INFO_SYM_AS_STR, dlerror());
+ dlclose(so);
+ return -EINVAL;
+ }
+ if (strcmp(hmi->id, HWVULKAN_HARDWARE_MODULE_ID) != 0) {
+ ALOGE("HAL id '%s' != '%s'", hmi->id, HWVULKAN_HARDWARE_MODULE_ID);
+ dlclose(so);
+ return -EINVAL;
+ }
+ hmi->dso = so;
+ *module = hmi;
+ ALOGD("loaded updated driver");
+ return 0;
+}
+
bool Hal::Open() {
ALOG_ASSERT(!hal_.dev_, "OpenHAL called more than once");
// Use a stub device unless we successfully open a real HAL device.
hal_.dev_ = &stubhal::kDevice;
- const hwvulkan_module_t* module;
- int result =
- hw_get_module("vulkan", reinterpret_cast<const hw_module_t**>(&module));
+ int result;
+ const hwvulkan_module_t* module = nullptr;
+
+ result = LoadUpdatedDriver(reinterpret_cast<const hw_module_t**>(&module));
+ if (result == -ENOENT) {
+ result = hw_get_module(HWVULKAN_HARDWARE_MODULE_ID, reinterpret_cast<const hw_module_t**>(&module));
+ }
if (result != 0) {
- ALOGI("no Vulkan HAL present, using stub HAL");
+ ALOGV("unable to load Vulkan HAL, using stub HAL (result=%d)", result);
return true;
}
@@ -405,6 +467,10 @@
name = VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME;
ext_bit = ProcHook::ANDROID_native_buffer;
break;
+ case ProcHook::GOOGLE_display_timing:
+ hook_extensions_.set(ext_bit);
+ // return now as these extensions do not require HAL support
+ return;
case ProcHook::EXTENSION_UNKNOWN:
// HAL's extensions
break;
@@ -663,10 +729,12 @@
uint32_t* pPropertyCount,
VkExtensionProperties* pProperties) {
const InstanceData& data = GetData(physicalDevice);
- static const std::array<VkExtensionProperties, 1> loader_extensions = {{
+ static const std::array<VkExtensionProperties, 2> loader_extensions = {{
// WSI extensions
{VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME,
VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION},
+ {VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME,
+ VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION},
}};
// enumerate our extensions first
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
index dac6e92..4cc2eb5 100644
--- a/vulkan/libvulkan/driver_gen.cpp
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -93,6 +93,15 @@
}
}
+VKAPI_ATTR VkResult checkedGetSwapchainStatusKHR(VkDevice device, VkSwapchainKHR swapchain) {
+ if (GetData(device).hook_extensions[ProcHook::KHR_swapchain_front_buffered]) {
+ return GetSwapchainStatusKHR(device, swapchain);
+ } else {
+ Logger(device).Err(device, "VK_KHR_swapchain_front_buffered not enabled. vkGetSwapchainStatusKHR not executed.");
+ return VK_SUCCESS;
+ }
+}
+
// clang-format on
const ProcHook g_proc_hooks[] = {
@@ -301,6 +310,13 @@
reinterpret_cast<PFN_vkVoidFunction>(checkedGetSwapchainImagesKHR),
},
{
+ "vkGetSwapchainStatusKHR",
+ ProcHook::DEVICE,
+ ProcHook::KHR_swapchain_front_buffered,
+ reinterpret_cast<PFN_vkVoidFunction>(GetSwapchainStatusKHR),
+ reinterpret_cast<PFN_vkVoidFunction>(checkedGetSwapchainStatusKHR),
+ },
+ {
"vkQueuePresentKHR",
ProcHook::DEVICE,
ProcHook::KHR_swapchain,
@@ -334,9 +350,11 @@
if (strcmp(name, "VK_ANDROID_native_buffer") == 0) return ProcHook::ANDROID_native_buffer;
if (strcmp(name, "VK_EXT_debug_report") == 0) return ProcHook::EXT_debug_report;
if (strcmp(name, "VK_KHR_android_surface") == 0) return ProcHook::KHR_android_surface;
+ if (strcmp(name, "VK_KHR_incremental_present") == 0) return ProcHook::KHR_incremental_present;
if (strcmp(name, "VK_KHR_surface") == 0) return ProcHook::KHR_surface;
if (strcmp(name, "VK_KHR_swapchain") == 0) return ProcHook::KHR_swapchain;
if (strcmp(name, "VK_GOOGLE_display_timing") == 0) return ProcHook::GOOGLE_display_timing;
+ if (strcmp(name, "VK_KHR_swapchain_front_buffered") == 0) return ProcHook::KHR_swapchain_front_buffered;
// clang-format on
return ProcHook::EXTENSION_UNKNOWN;
}
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index 167f88c..a137ab6 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -36,9 +36,11 @@
ANDROID_native_buffer,
EXT_debug_report,
KHR_android_surface,
+ KHR_incremental_present,
KHR_surface,
KHR_swapchain,
GOOGLE_display_timing,
+ KHR_swapchain_front_buffered,
EXTENSION_CORE, // valid bit
EXTENSION_COUNT,
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index e069b5d..243ea69 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -20,6 +20,7 @@
#include <gui/BufferQueue.h>
#include <sync/sync.h>
#include <utils/StrongPointer.h>
+#include <utils/SortedVector.h>
#include "driver.h"
@@ -105,6 +106,69 @@
}
}
+class TimingInfo {
+ public:
+ TimingInfo()
+ : vals_{0, 0, 0, 0, 0},
+ timestamp_desired_present_time_(0),
+ timestamp_actual_present_time_(0),
+ timestamp_render_complete_time_(0),
+ timestamp_composition_latch_time_(0) {}
+ TimingInfo(const VkPresentTimeGOOGLE* qp)
+ : vals_{qp->presentID, qp->desiredPresentTime, 0, 0, 0},
+ timestamp_desired_present_time_(0),
+ timestamp_actual_present_time_(0),
+ timestamp_render_complete_time_(0),
+ timestamp_composition_latch_time_(0) {}
+ bool ready() {
+ return (timestamp_desired_present_time_ &&
+ timestamp_actual_present_time_ &&
+ timestamp_render_complete_time_ &&
+ timestamp_composition_latch_time_);
+ }
+ void calculate(uint64_t rdur) {
+ vals_.actualPresentTime = timestamp_actual_present_time_;
+ uint64_t margin = (timestamp_composition_latch_time_ -
+ timestamp_render_complete_time_);
+ // Calculate vals_.earliestPresentTime, and potentially adjust
+ // vals_.presentMargin. The initial value of vals_.earliestPresentTime
+ // is vals_.actualPresentTime. If we can subtract rdur (the duration
+ // of a refresh cycle) from vals_.earliestPresentTime (and also from
+ // vals_.presentMargin) and still leave a positive margin, then we can
+ // report to the application that it could have presented earlier than
+ // it did (per the extension specification). If for some reason, we
+ // can do this subtraction repeatedly, we do, since
+ // vals_.earliestPresentTime really is supposed to be the "earliest".
+ uint64_t early_time = vals_.actualPresentTime;
+ while ((margin > rdur) &&
+ ((early_time - rdur) > timestamp_composition_latch_time_)) {
+ early_time -= rdur;
+ margin -= rdur;
+ }
+ vals_.earliestPresentTime = early_time;
+ vals_.presentMargin = margin;
+ }
+ void get_values(VkPastPresentationTimingGOOGLE* values) { *values = vals_; }
+
+ public:
+ VkPastPresentationTimingGOOGLE vals_;
+
+ uint64_t timestamp_desired_present_time_;
+ uint64_t timestamp_actual_present_time_;
+ uint64_t timestamp_render_complete_time_;
+ uint64_t timestamp_composition_latch_time_;
+};
+
+static inline int compare_type(const TimingInfo& lhs, const TimingInfo& rhs) {
+ // TODO(ianelliott): Change this from presentID to the frame ID once
+ // brianderson lands the appropriate patch:
+ if (lhs.vals_.presentID < rhs.vals_.presentID)
+ return -1;
+ if (lhs.vals_.presentID > rhs.vals_.presentID)
+ return 1;
+ return 0;
+}
+
// ----------------------------------------------------------------------------
struct Surface {
@@ -120,11 +184,19 @@
return reinterpret_cast<Surface*>(handle);
}
+// Maximum number of TimingInfo structs to keep per swapchain:
+enum { MAX_TIMING_INFOS = 10 };
+// Minimum number of frames to look for in the past (so we don't cause
+// syncronous requests to Surface Flinger):
+enum { MIN_NUM_FRAMES_AGO = 5 };
+
struct Swapchain {
Swapchain(Surface& surface_, uint32_t num_images_)
: surface(surface_),
num_images(num_images_),
- frame_timestamps_enabled(false) {}
+ frame_timestamps_enabled(false) {
+ timing.clear();
+ }
Surface& surface;
uint32_t num_images;
@@ -141,6 +213,8 @@
int dequeue_fence;
bool dequeued;
} images[android::BufferQueue::NUM_BUFFER_SLOTS];
+
+ android::SortedVector<TimingInfo> timing;
};
VkSwapchainKHR HandleFromSwapchain(Swapchain* swapchain) {
@@ -208,6 +282,112 @@
ReleaseSwapchainImage(device, nullptr, -1, swapchain->images[i]);
}
swapchain->surface.swapchain_handle = VK_NULL_HANDLE;
+ swapchain->timing.clear();
+}
+
+uint32_t get_num_ready_timings(Swapchain& swapchain) {
+ uint32_t num_ready = 0;
+ uint32_t num_timings = static_cast<uint32_t>(swapchain.timing.size());
+ uint32_t frames_ago = num_timings;
+ for (uint32_t i = 0; i < num_timings; i++) {
+ TimingInfo* ti = &swapchain.timing.editItemAt(i);
+ if (ti) {
+ if (ti->ready()) {
+ // This TimingInfo is ready to be reported to the user. Add it
+ // to the num_ready.
+ num_ready++;
+ } else {
+ // This TimingInfo is not yet ready to be reported to the user,
+ // and so we should look for any available timestamps that
+ // might make it ready.
+ int64_t desired_present_time = 0;
+ int64_t render_complete_time = 0;
+ int64_t composition_latch_time = 0;
+ int64_t actual_present_time = 0;
+ for (uint32_t f = MIN_NUM_FRAMES_AGO; f < frames_ago; f++) {
+ // Obtain timestamps:
+ int ret = native_window_get_frame_timestamps(
+ swapchain.surface.window.get(), f,
+ &desired_present_time, &render_complete_time,
+ &composition_latch_time,
+ NULL, //&first_composition_start_time,
+ NULL, //&last_composition_start_time,
+ NULL, //&composition_finish_time,
+ // TODO(ianelliott): Maybe ask if this one is
+ // supported, at startup time (since it may not be
+ // supported):
+ &actual_present_time,
+ NULL, //&display_retire_time,
+ NULL, //&dequeue_ready_time,
+ NULL /*&reads_done_time*/);
+ if (ret) {
+ break;
+ } else if (!ret) {
+ // We obtained at least one valid timestamp. See if it
+ // is for the present represented by this TimingInfo:
+ if (static_cast<uint64_t>(desired_present_time) ==
+ ti->vals_.desiredPresentTime) {
+ // Record the timestamp(s) we received, and then
+ // see if this TimingInfo is ready to be reported
+ // to the user:
+ ti->timestamp_desired_present_time_ =
+ static_cast<uint64_t>(desired_present_time);
+ ti->timestamp_actual_present_time_ =
+ static_cast<uint64_t>(actual_present_time);
+ ti->timestamp_render_complete_time_ =
+ static_cast<uint64_t>(render_complete_time);
+ ti->timestamp_composition_latch_time_ =
+ static_cast<uint64_t>(composition_latch_time);
+
+ if (ti->ready()) {
+ // The TimingInfo has received enough
+ // timestamps, and should now use those
+ // timestamps to calculate the info that should
+ // be reported to the user:
+ //
+ // FIXME: GET ACTUAL VALUE RATHER THAN HARD-CODE
+ // IT:
+ ti->calculate(16666666);
+ num_ready++;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ return num_ready;
+}
+
+// TODO(ianelliott): DEAL WITH RETURN VALUE (e.g. VK_INCOMPLETE)!!!
+void copy_ready_timings(Swapchain& swapchain,
+ uint32_t* count,
+ VkPastPresentationTimingGOOGLE* timings) {
+ uint32_t num_copied = 0;
+ uint32_t num_timings = static_cast<uint32_t>(swapchain.timing.size());
+ if (*count < num_timings) {
+ num_timings = *count;
+ }
+ for (uint32_t i = 0; i < num_timings; i++) {
+ TimingInfo* ti = &swapchain.timing.editItemAt(i);
+ if (ti && ti->ready()) {
+ ti->get_values(&timings[num_copied]);
+ num_copied++;
+ // We only report the values for a given present once, so remove
+ // them from swapchain.timing:
+ //
+ // TODO(ianelliott): SEE WHAT HAPPENS TO THE LOOP WHEN THE
+ // FOLLOWING IS DONE:
+ swapchain.timing.removeAt(i);
+ i--;
+ num_timings--;
+ if (*count == num_copied) {
+ break;
+ }
+ }
+ }
+ *count = num_copied;
}
} // anonymous namespace
@@ -330,7 +510,6 @@
// TODO(jessehall): I think these are right, but haven't thought hard about
// it. Do we need to query the driver for support of any of these?
// Currently not included:
- // - VK_IMAGE_USAGE_GENERAL: maybe? does this imply cpu mappable?
// - VK_IMAGE_USAGE_DEPTH_STENCIL_BIT: definitely not
// - VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT: definitely not
capabilities->supportedUsageFlags =
@@ -379,6 +558,9 @@
VkPresentModeKHR* modes) {
const VkPresentModeKHR kModes[] = {
VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_KHR,
+ // TODO(chrisforbes): should only expose this if the driver can.
+ VK_PRESENT_MODE_FRONT_BUFFERED_DEMAND_REFRESH_KHR,
+ VK_PRESENT_MODE_FRONT_BUFFERED_CONTINUOUS_REFRESH_KHR,
};
const uint32_t kNumModes = sizeof(kModes) / sizeof(kModes[0]);
@@ -426,7 +608,9 @@
"swapchain preTransform=%#x not supported",
create_info->preTransform);
ALOGV_IF(!(create_info->presentMode == VK_PRESENT_MODE_FIFO_KHR ||
- create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR),
+ create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR ||
+ create_info->presentMode == VK_PRESENT_MODE_FRONT_BUFFERED_DEMAND_REFRESH_KHR ||
+ create_info->presentMode == VK_PRESENT_MODE_FRONT_BUFFERED_CONTINUOUS_REFRESH_KHR),
"swapchain presentMode=%u not supported",
create_info->presentMode);
@@ -480,6 +664,20 @@
return VK_ERROR_INITIALIZATION_FAILED;
}
+ err = native_window_set_shared_buffer_mode(surface.window.get(), false);
+ if (err != 0) {
+ ALOGE("native_window_set_shared_buffer_mode(false) failed: %s (%d)",
+ strerror(-err), err);
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+
+ err = native_window_set_auto_refresh(surface.window.get(), false);
+ if (err != 0) {
+ ALOGE("native_window_set_auto_refresh(false) failed: %s (%d)",
+ strerror(-err), err);
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+
// -- Configure the native window --
const auto& dispatch = GetData(device).driver;
@@ -587,9 +785,36 @@
return VK_ERROR_INITIALIZATION_FAILED;
}
+ VkSwapchainImageUsageFlagsANDROID swapchain_image_usage = 0;
+ if (create_info->presentMode == VK_PRESENT_MODE_FRONT_BUFFERED_DEMAND_REFRESH_KHR ||
+ create_info->presentMode == VK_PRESENT_MODE_FRONT_BUFFERED_CONTINUOUS_REFRESH_KHR) {
+ swapchain_image_usage |= VK_SWAPCHAIN_IMAGE_USAGE_FRONT_BUFFER_BIT_ANDROID;
+
+ err = native_window_set_shared_buffer_mode(surface.window.get(), true);
+ if (err != 0) {
+ ALOGE("native_window_set_shared_buffer_mode failed: %s (%d)", strerror(-err), err);
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+ }
+
+ if (create_info->presentMode == VK_PRESENT_MODE_FRONT_BUFFERED_CONTINUOUS_REFRESH_KHR) {
+ err = native_window_set_auto_refresh(surface.window.get(), true);
+ if (err != 0) {
+ ALOGE("native_window_set_auto_refresh failed: %s (%d)", strerror(-err), err);
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+ }
+
int gralloc_usage = 0;
- // TODO(jessehall): Remove conditional once all drivers have been updated
- if (dispatch.GetSwapchainGrallocUsageANDROID) {
+ if (dispatch.GetSwapchainGrallocUsage2ANDROID) {
+ result = dispatch.GetSwapchainGrallocUsage2ANDROID(
+ device, create_info->imageFormat, create_info->imageUsage,
+ swapchain_image_usage, &gralloc_usage);
+ if (result != VK_SUCCESS) {
+ ALOGE("vkGetSwapchainGrallocUsage2ANDROID failed: %d", result);
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+ } else if (dispatch.GetSwapchainGrallocUsageANDROID) {
result = dispatch.GetSwapchainGrallocUsageANDROID(
device, create_info->imageFormat, create_info->imageUsage,
&gralloc_usage);
@@ -632,12 +857,20 @@
// -- Dequeue all buffers and create a VkImage for each --
// Any failures during or after this must cancel the dequeued buffers.
+ VkSwapchainImageCreateInfoANDROID swapchain_image_create = {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wold-style-cast"
+ .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_IMAGE_CREATE_INFO_ANDROID,
+#pragma clang diagnostic pop
+ .pNext = nullptr,
+ .usage = swapchain_image_usage,
+ };
VkNativeBufferANDROID image_native_buffer = {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wold-style-cast"
.sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID,
#pragma clang diagnostic pop
- .pNext = nullptr,
+ .pNext = &swapchain_image_create,
};
VkImageCreateInfo image_create = {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
@@ -883,7 +1116,7 @@
case VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR:
present_regions = next;
break;
- case VK_STRUCTURE_TYPE_PRESENT_TIMES_GOOGLE:
+ case VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE:
present_times =
reinterpret_cast<const VkPresentTimesInfoGOOGLE*>(next);
break;
@@ -975,16 +1208,31 @@
}
if (time) {
if (!swapchain.frame_timestamps_enabled) {
+ ALOGV(
+ "Calling "
+ "native_window_enable_frame_timestamps(true)");
native_window_enable_frame_timestamps(window, true);
swapchain.frame_timestamps_enabled = true;
}
- // TODO(ianelliott): need to store the presentID (and
- // desiredPresentTime), so it can be later correlated to
- // this present. Probably modify the following function
- // (and below) to plumb a path to store it in FrameEvents
- // code, on the producer side.
- native_window_set_buffers_timestamp(
- window, static_cast<int64_t>(time->desiredPresentTime));
+ // Record this presentID and desiredPresentTime so it can
+ // be later correlated to this present.
+ TimingInfo timing_record(time);
+ swapchain.timing.add(timing_record);
+ uint32_t num_timings =
+ static_cast<uint32_t>(swapchain.timing.size());
+ if (num_timings > MAX_TIMING_INFOS) {
+ swapchain.timing.removeAt(0);
+ }
+ if (time->desiredPresentTime) {
+ // Set the desiredPresentTime:
+ ALOGV(
+ "Calling "
+ "native_window_set_buffers_timestamp(%" PRId64 ")",
+ time->desiredPresentTime);
+ native_window_set_buffers_timestamp(
+ window,
+ static_cast<int64_t>(time->desiredPresentTime));
+ }
}
err = window->queueBuffer(window, img.buffer.get(), fence);
// queueBuffer always closes fence, even on error
@@ -1031,8 +1279,8 @@
VkResult result = VK_SUCCESS;
// TODO(ianelliott): FULLY IMPLEMENT THIS FUNCTION!!!
- pDisplayTimingProperties->minRefreshDuration = 16666666666;
- pDisplayTimingProperties->maxRefreshDuration = 16666666666;
+ pDisplayTimingProperties->minRefreshDuration = 16666666;
+ pDisplayTimingProperties->maxRefreshDuration = 16666666;
return result;
}
@@ -1048,19 +1296,36 @@
VkResult result = VK_SUCCESS;
if (!swapchain.frame_timestamps_enabled) {
+ ALOGV("Calling native_window_enable_frame_timestamps(true)");
native_window_enable_frame_timestamps(window, true);
swapchain.frame_timestamps_enabled = true;
}
- // TODO(ianelliott): FULLY IMPLEMENT THIS FUNCTION!!!
if (timings) {
- *count = 0;
+ // TODO(ianelliott): plumb return value (e.g. VK_INCOMPLETE)
+ copy_ready_timings(swapchain, count, timings);
} else {
- *count = 0;
+ *count = get_num_ready_timings(swapchain);
}
return result;
}
+VKAPI_ATTR
+VkResult GetSwapchainStatusKHR(
+ VkDevice,
+ VkSwapchainKHR swapchain_handle) {
+ Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
+ VkResult result = VK_SUCCESS;
+
+ if (swapchain.surface.swapchain_handle != swapchain_handle) {
+ return VK_ERROR_OUT_OF_DATE_KHR;
+ }
+
+ // TODO(chrisforbes): Implement this function properly
+
+ return result;
+}
+
} // namespace driver
} // namespace vulkan
diff --git a/vulkan/libvulkan/swapchain.h b/vulkan/libvulkan/swapchain.h
index 8aac427..91d7219 100644
--- a/vulkan/libvulkan/swapchain.h
+++ b/vulkan/libvulkan/swapchain.h
@@ -36,6 +36,7 @@
VKAPI_ATTR VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info);
VKAPI_ATTR VkResult GetRefreshCycleDurationGOOGLE(VkDevice device, VkSwapchainKHR swapchain, VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties);
VKAPI_ATTR VkResult GetPastPresentationTimingGOOGLE(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pPresentationTimingCount, VkPastPresentationTimingGOOGLE* pPresentationTimings);
+VKAPI_ATTR VkResult GetSwapchainStatusKHR(VkDevice device, VkSwapchainKHR swapchain);
// clang-format on
} // namespace driver