diff options
305 files changed, 11957 insertions, 9593 deletions
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp index a3d210ad1f..9def406ea0 100644 --- a/cmds/atrace/atrace.cpp +++ b/cmds/atrace/atrace.cpp @@ -23,6 +23,7 @@ #include <stdbool.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <sys/sendfile.h> #include <time.h> #include <zlib.h> @@ -34,6 +35,7 @@ #include <cutils/properties.h> #include <utils/String8.h> +#include <utils/Timers.h> #include <utils/Trace.h> using namespace android; @@ -135,6 +137,9 @@ static const TracingCategory k_categories[] = { { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable" }, { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable" }, } }, + { "regulators", "Voltage and Current Regulators", 0, { + { REQ, "/sys/kernel/debug/tracing/events/regulator/enable" }, + } }, }; /* Command line options */ @@ -191,6 +196,9 @@ static const char* k_tracingOnPath = static const char* k_tracePath = "/sys/kernel/debug/tracing/trace"; +static const char* k_traceMarkerPath = + "/sys/kernel/debug/tracing/trace_marker"; + // Check whether a file exists. static bool fileExists(const char* filename) { return access(filename, F_OK) != -1; @@ -253,6 +261,14 @@ static bool appendStr(const char* filename, const char* str) return _writeStr(filename, str, O_APPEND|O_WRONLY); } +static void writeClockSyncMarker() +{ + char buffer[128]; + float now_in_seconds = systemTime(CLOCK_MONOTONIC) / 1000000000.0f; + snprintf(buffer, 128, "trace_event_clock_sync: parent_ts=%f\n", now_in_seconds); + writeStr(k_traceMarkerPath, buffer); +} + // Enable or disable a kernel option by writing a "1" or a "0" into a /sys // file. static bool setKernelOptionEnable(const char* filename, bool enable) @@ -630,6 +646,7 @@ static bool startTrace() // Disable tracing in the kernel. static void stopTrace() { + writeClockSyncMarker(); setTracingEnabled(false); } @@ -648,7 +665,7 @@ static void dumpTrace() uint8_t *in, *out; int result, flush; - bzero(&zs, sizeof(zs)); + memset(&zs, 0, sizeof(zs)); result = deflateInit(&zs, Z_DEFAULT_COMPRESSION); if (result != Z_OK) { fprintf(stderr, "error initializing zlib: %d\n", result); @@ -883,7 +900,7 @@ int main(int argc, char **argv) g_traceOverwrite = true; } else if (!strcmp(long_options[option_index].name, "async_stop")) { async = true; - traceStop = false; + traceStart = false; } else if (!strcmp(long_options[option_index].name, "async_dump")) { async = true; traceStart = false; diff --git a/cmds/bugreport/Android.mk b/cmds/bugreport/Android.mk index f476f5e4cd..ced5d30378 100644 --- a/cmds/bugreport/Android.mk +++ b/cmds/bugreport/Android.mk @@ -1,10 +1,12 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES:= bugreport.c +LOCAL_SRC_FILES:= bugreport.cpp LOCAL_MODULE:= bugreport +LOCAL_CFLAGS := -Wall + LOCAL_SHARED_LIBRARIES := libcutils include $(BUILD_EXECUTABLE) diff --git a/cmds/bugreport/bugreport.c b/cmds/bugreport/bugreport.c deleted file mode 100644 index 11e9057fec..0000000000 --- a/cmds/bugreport/bugreport.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2009 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 <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -#include <cutils/properties.h> -#include <cutils/sockets.h> - -int main(int argc, char *argv[]) { - char buffer[65536]; - int i, s; - - /* start the dumpstate service */ - property_set("ctl.start", "dumpstate"); - - /* socket will not be available until service starts */ - for (i = 0; i < 20; i++) { - s = socket_local_client("dumpstate", - ANDROID_SOCKET_NAMESPACE_RESERVED, - SOCK_STREAM); - if (s >= 0) - break; - /* try again in 1 second */ - sleep(1); - } - - if (s < 0) { - fprintf(stderr, "Failed to connect to dumpstate service\n"); - exit(1); - } - - while (1) { - int length = read(s, buffer, sizeof(buffer)); - if (length <= 0) - break; - fwrite(buffer, 1, length, stdout); - } - - close(s); - return 0; -} diff --git a/cmds/bugreport/bugreport.cpp b/cmds/bugreport/bugreport.cpp new file mode 100644 index 0000000000..6892b57f88 --- /dev/null +++ b/cmds/bugreport/bugreport.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2009 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 <errno.h> +#include <stdio.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <unistd.h> + +#include <cutils/properties.h> +#include <cutils/sockets.h> + +// This program will trigger the dumpstate service to start a call to +// dumpstate, then connect to the dumpstate local client to read the +// output. All of the dumpstate output is written to stdout, including +// any errors encountered while reading/writing the output. +int main() { + // Start the dumpstate service. + property_set("ctl.start", "dumpstate"); + + // Socket will not be available until service starts. + int s; + for (int i = 0; i < 20; i++) { + s = socket_local_client("dumpstate", ANDROID_SOCKET_NAMESPACE_RESERVED, + SOCK_STREAM); + if (s >= 0) + break; + // Try again in 1 second. + sleep(1); + } + + if (s == -1) { + printf("Failed to connect to dumpstate service: %s\n", strerror(errno)); + return 1; + } + + // Set a timeout so that if nothing is read in 3 minutes, we'll stop + // reading and quit. No timeout in dumpstate is longer than 60 seconds, + // so this gives lots of leeway in case of unforeseen time outs. + struct timeval tv; + tv.tv_sec = 3 * 60; + tv.tv_usec = 0; + if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) { + printf("WARNING: Cannot set socket timeout: %s\n", strerror(errno)); + } + + while (1) { + char buffer[65536]; + ssize_t bytes_read = TEMP_FAILURE_RETRY(read(s, buffer, sizeof(buffer))); + if (bytes_read == 0) { + break; + } else if (bytes_read == -1) { + // EAGAIN really means time out, so change the errno. + if (errno == EAGAIN) { + errno = ETIMEDOUT; + } + printf("\nBugreport read terminated abnormally (%s).\n", strerror(errno)); + break; + } + + ssize_t bytes_to_send = bytes_read; + ssize_t bytes_written; + do { + bytes_written = TEMP_FAILURE_RETRY(write(STDOUT_FILENO, + buffer + bytes_read - bytes_to_send, + bytes_to_send)); + if (bytes_written == -1) { + printf("Failed to write data to stdout: read %zd, trying to send %zd (%s)\n", + bytes_read, bytes_to_send, strerror(errno)); + return 1; + } + bytes_to_send -= bytes_written; + } while (bytes_written != 0 && bytes_to_send > 0); + } + + close(s); + return 0; +} diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c index dc1ada0873..ef8db06936 100644 --- a/cmds/dumpstate/dumpstate.c +++ b/cmds/dumpstate/dumpstate.c @@ -18,6 +18,7 @@ #include <errno.h> #include <fcntl.h> #include <limits.h> +#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -64,7 +65,8 @@ static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) { time_t thirty_minutes_ago = time(NULL) - 60*30; for (size_t i = 0; i < NUM_TOMBSTONES; i++) { snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i); - int fd = open(data[i].name, O_RDONLY | O_CLOEXEC | O_NOFOLLOW); + int fd = TEMP_FAILURE_RETRY(open(data[i].name, + O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)); struct stat st; if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) && (time_t) st.st_mtime >= thirty_minutes_ago) { @@ -98,8 +100,170 @@ static void dump_dev_files(const char *title, const char *driverpath, const char closedir(d); } +static bool skip_not_stat(const char *path) { + static const char stat[] = "/stat"; + size_t len = strlen(path); + if (path[len - 1] == '/') { /* Directory? */ + return false; + } + return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */ +} + +static const char mmcblk0[] = "/sys/block/mmcblk0/"; +unsigned long worst_write_perf = 20000; /* in KB/s */ + +static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) { + unsigned long fields[11], read_perf, write_perf; + bool z; + char *cp, *buffer = NULL; + size_t i = 0; + FILE *fp = fdopen(fd, "rb"); + getline(&buffer, &i, fp); + fclose(fp); + if (!buffer) { + return -errno; + } + i = strlen(buffer); + while ((i > 0) && (buffer[i - 1] == '\n')) { + buffer[--i] = '\0'; + } + if (!*buffer) { + free(buffer); + return 0; + } + z = true; + for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) { + fields[i] = strtol(cp, &cp, 0); + if (fields[i] != 0) { + z = false; + } + } + if (z) { /* never accessed */ + free(buffer); + return 0; + } + + if (!strncmp(path, mmcblk0, sizeof(mmcblk0) - 1)) { + path += sizeof(mmcblk0) - 1; + } + + printf("%s: %s\n", path, buffer); + free(buffer); + + read_perf = 0; + if (fields[3]) { + read_perf = 512 * fields[2] / fields[3]; + } + write_perf = 0; + if (fields[7]) { + write_perf = 512 * fields[6] / fields[7]; + } + printf("%s: read: %luKB/s write: %luKB/s\n", path, read_perf, write_perf); + if ((write_perf > 1) && (write_perf < worst_write_perf)) { + worst_write_perf = write_perf; + } + return 0; +} + +/* Copied policy from system/core/logd/LogBuffer.cpp */ + +#define LOG_BUFFER_SIZE (256 * 1024) +#define LOG_BUFFER_MIN_SIZE (64 * 1024UL) +#define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL) + +static bool valid_size(unsigned long value) { + if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) { + return false; + } + + long pages = sysconf(_SC_PHYS_PAGES); + if (pages < 1) { + return true; + } + + long pagesize = sysconf(_SC_PAGESIZE); + if (pagesize <= 1) { + pagesize = PAGE_SIZE; + } + + // maximum memory impact a somewhat arbitrary ~3% + pages = (pages + 31) / 32; + unsigned long maximum = pages * pagesize; + + if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) { + return true; + } + + return value <= maximum; +} + +static unsigned long property_get_size(const char *key) { + unsigned long value; + char *cp, property[PROPERTY_VALUE_MAX]; + + property_get(key, property, ""); + value = strtoul(property, &cp, 10); + + switch(*cp) { + case 'm': + case 'M': + value *= 1024; + /* FALLTHRU */ + case 'k': + case 'K': + value *= 1024; + /* FALLTHRU */ + case '\0': + break; + + default: + value = 0; + } + + if (!valid_size(value)) { + value = 0; + } + + return value; +} + +/* timeout in ms */ +static unsigned long logcat_timeout(char *name) { + static const char global_tuneable[] = "persist.logd.size"; // Settings App + static const char global_default[] = "ro.logd.size"; // BoardConfig.mk + char key[PROP_NAME_MAX]; + unsigned long property_size, default_size; + + default_size = property_get_size(global_tuneable); + if (!default_size) { + default_size = property_get_size(global_default); + } + + snprintf(key, sizeof(key), "%s.%s", global_tuneable, name); + property_size = property_get_size(key); + + if (!property_size) { + snprintf(key, sizeof(key), "%s.%s", global_default, name); + property_size = property_get_size(key); + } + + if (!property_size) { + property_size = default_size; + } + + if (!property_size) { + property_size = LOG_BUFFER_SIZE; + } + + /* Engineering margin is ten-fold our guess */ + return 10 * (property_size + worst_write_perf) / worst_write_perf; +} + +/* End copy from system/core/logd/LogBuffer.cpp */ + /* dumps the current system state to stdout */ static void dumpstate() { + unsigned long timeout; time_t now = time(NULL); char build[PROPERTY_VALUE_MAX], fingerprint[PROPERTY_VALUE_MAX]; char radio[PROPERTY_VALUE_MAX], bootloader[PROPERTY_VALUE_MAX]; @@ -132,7 +296,7 @@ static void dumpstate() { dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version"); run_command("UPTIME", 10, "uptime", NULL); - dump_file("MMC PERF", "/sys/block/mmcblk0/stat"); + dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd); dump_file("MEMORY INFO", "/proc/meminfo"); run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-t", NULL); run_command("PROCRANK", 20, "procrank", NULL); @@ -148,7 +312,6 @@ static void dumpstate() { dump_file("KERNEL WAKE SOURCES", "/d/wakeup_sources"); dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state"); dump_file("KERNEL SYNC", "/d/sync"); - dump_file("KERNEL BLUEDROID", "/d/bluedroid"); run_command("PROCESSES", 10, "ps", "-P", NULL); run_command("PROCESSES AND THREADS", 10, "ps", "-t", "-p", "-P", NULL); @@ -168,9 +331,24 @@ static void dumpstate() { } // dump_file("EVENT LOG TAGS", "/etc/event-log-tags"); - run_command("SYSTEM LOG", 20, "logcat", "-v", "threadtime", "-d", "*:v", NULL); - run_command("EVENT LOG", 20, "logcat", "-b", "events", "-v", "threadtime", "-d", "*:v", NULL); - run_command("RADIO LOG", 20, "logcat", "-b", "radio", "-v", "threadtime", "-d", "*:v", NULL); + // calculate timeout + timeout = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash"); + if (timeout < 20000) { + timeout = 20000; + } + run_command("SYSTEM LOG", timeout / 1000, "logcat", "-v", "threadtime", "-d", "*:v", NULL); + timeout = logcat_timeout("events"); + if (timeout < 20000) { + timeout = 20000; + } + run_command("EVENT LOG", timeout / 1000, "logcat", "-b", "events", "-v", "threadtime", "-d", "*:v", NULL); + timeout = logcat_timeout("radio"); + if (timeout < 20000) { + timeout = 20000; + } + run_command("RADIO LOG", timeout / 1000, "logcat", "-b", "radio", "-v", "threadtime", "-d", "*:v", NULL); + + run_command("LOG STATISTICS", 10, "logcat", "-b", "all", "-S", NULL); /* show the traces we collected in main(), if that was done */ if (dump_traces_path != NULL) { @@ -184,7 +362,8 @@ static void dumpstate() { if (!anr_traces_path[0]) { printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n"); } else { - int fd = open(anr_traces_path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW); + int fd = TEMP_FAILURE_RETRY(open(anr_traces_path, + O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)); if (fd < 0) { printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno)); } else { @@ -236,13 +415,13 @@ static void dumpstate() { dump_file("LAST KMSG", "/proc/last_kmsg"); } - dump_file("LAST PANIC CONSOLE", "/data/dontpanic/apanic_console"); - dump_file("LAST PANIC THREADS", "/data/dontpanic/apanic_threads"); - - for_each_userid(do_dump_settings, NULL); + /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */ + run_command("LAST LOGCAT", 10, "logcat", "-L", "-v", "threadtime", + "-b", "all", "-d", "*:v", NULL); /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */ - run_command("NETWORK INTERFACES", 10, SU_PATH, "root", "netcfg", NULL); + + run_command("NETWORK INTERFACES", 10, "ip", "link", NULL); run_command("IPv4 ADDRESSES", 10, "ip", "-4", "addr", "show", NULL); run_command("IPv6 ADDRESSES", 10, "ip", "-6", "addr", "show", NULL); @@ -255,6 +434,8 @@ static void dumpstate() { run_command("ARP CACHE", 10, "ip", "-4", "neigh", "show", NULL); run_command("IPv6 ND CACHE", 10, "ip", "-6", "neigh", "show", NULL); + run_command("NETWORK DIAGNOSTICS", 10, "dumpsys", "connectivity", "--diag", NULL); + run_command("IPTABLES", 10, SU_PATH, "root", "iptables", "-L", "-nvx", NULL); run_command("IP6TABLES", 10, SU_PATH, "root", "ip6tables", "-L", "-nvx", NULL); run_command("IPTABLE NAT", 10, SU_PATH, "root", "iptables", "-t", "nat", "-L", "-nvx", NULL); @@ -358,6 +539,7 @@ static void dumpstate() { run_command("CHECKIN NETSTATS", 30, "dumpsys", "netstats", "--checkin", NULL); run_command("CHECKIN PROCSTATS", 30, "dumpsys", "procstats", "-c", NULL); run_command("CHECKIN USAGESTATS", 30, "dumpsys", "usagestats", "-c", NULL); + run_command("CHECKIN PACKAGE", 30, "dumpsys", "package", "--checkin", NULL); printf("========================================================\n"); printf("== Running Application Activities\n"); @@ -387,7 +569,6 @@ static void usage() { fprintf(stderr, "usage: dumpstate [-b soundfile] [-e soundfile] [-o file [-d] [-p] [-z]] [-s] [-q]\n" " -o: write to file (instead of stdout)\n" " -d: append date to filename (requires -o)\n" - " -z: gzip output (requires -o)\n" " -p: capture screenshot to filename.png (requires -o)\n" " -s: write output to control socket (for init)\n" " -b: play sound file instead of vibrate, at beginning of job\n" @@ -410,7 +591,6 @@ static void vibrate(FILE* vibrator, int ms) { int main(int argc, char *argv[]) { struct sigaction sigact; int do_add_date = 0; - int do_compress = 0; int do_vibrate = 1; char* use_outfile = 0; int use_socket = 0; @@ -435,7 +615,7 @@ int main(int argc, char *argv[]) { /* set as high priority, and protect from OOM killer */ setpriority(PRIO_PROCESS, 0, -20); - FILE *oom_adj = fopen("/proc/self/oom_adj", "w"); + FILE *oom_adj = fopen("/proc/self/oom_adj", "we"); if (oom_adj) { fputs("-17", oom_adj); fclose(oom_adj); @@ -450,7 +630,6 @@ int main(int argc, char *argv[]) { case 's': use_socket = 1; break; case 'v': break; // compatibility no-op case 'q': do_vibrate = 0; break; - case 'z': do_compress = 6; break; case 'p': do_fb = 1; break; case 'B': do_broadcast = 1; break; case '?': printf("\n"); @@ -469,15 +648,14 @@ int main(int argc, char *argv[]) { /* open the vibrator before dropping root */ FILE *vibrator = 0; if (do_vibrate) { - vibrator = fopen("/sys/class/timed_output/vibrator/enable", "w"); + vibrator = fopen("/sys/class/timed_output/vibrator/enable", "we"); if (vibrator) { - fcntl(fileno(vibrator), F_SETFD, FD_CLOEXEC); vibrate(vibrator, 150); } } /* read /proc/cmdline before dropping root */ - FILE *cmdline = fopen("/proc/cmdline", "r"); + FILE *cmdline = fopen("/proc/cmdline", "re"); if (cmdline != NULL) { fgets(cmdline_buf, sizeof(cmdline_buf), cmdline); fclose(cmdline); @@ -545,10 +723,9 @@ int main(int argc, char *argv[]) { strlcat(screenshot_path, ".png", sizeof(screenshot_path)); } strlcat(path, ".txt", sizeof(path)); - if (do_compress) strlcat(path, ".gz", sizeof(path)); strlcpy(tmp_path, path, sizeof(tmp_path)); strlcat(tmp_path, ".tmp", sizeof(tmp_path)); - gzip_pid = redirect_to_file(stdout, tmp_path, do_compress); + redirect_to_file(stdout, tmp_path); } dumpstate(); diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index 53bfff601e..c5d3044ae3 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -26,14 +26,25 @@ typedef void (for_each_pid_func)(int, const char *); typedef void (for_each_tid_func)(int, int, const char *); -typedef void (for_each_userid_func)(int); /* prints the contents of a file */ int dump_file(const char *title, const char *path); -/* prints the contents of the fd */ +/* prints the contents of the fd + * fd must have been opened with the flag O_NONBLOCK. + */ int dump_file_from_fd(const char *title, const char *path, int fd); +/* calls skip to gate calling dump_from_fd recursively + * in the specified directory. dump_from_fd defaults to + * dump_file_from_fd above when set to NULL. skip defaults + * to false when set to NULL. dump_from_fd will always be + * called with title NULL. + */ +int dump_files(const char *title, const char *dir, + bool (*skip)(const char *path), + int (*dump_from_fd)(const char *title, const char *path, int fd)); + /* forks a command and waits for it to finish -- terminate args with NULL */ int run_command(const char *title, int timeout_seconds, const char *command, ...); @@ -43,8 +54,8 @@ void print_properties(); /* redirect output to a service control socket */ void redirect_to_socket(FILE *redirect, const char *service); -/* redirect output to a file, optionally gzipping; returns gzip pid */ -pid_t redirect_to_file(FILE *redirect, char *path, int gzip_level); +/* redirect output to a file */ +void redirect_to_file(FILE *redirect, char *path); /* dump Dalvik and native stack traces, return the trace file location (NULL if none) */ const char *dump_traces(); @@ -55,9 +66,6 @@ void for_each_pid(for_each_pid_func func, const char *header); /* for each thread in the system, run the specified function */ void for_each_tid(for_each_tid_func func, const char *header); -/* for each user id in the system, run the specified function */ -void for_each_userid(for_each_userid_func func, const char *header); - /* Displays a blocked processes in-kernel wait channel */ void show_wchan(int pid, int tid, const char *name); @@ -67,9 +75,6 @@ void do_showmap(int pid, const char *name); /* Gets the dmesg output for the kernel */ void do_dmesg(); -/* Dumps settings for a given user id */ -void do_dump_settings(int userid); - /* Prints the contents of all the routing tables, both IPv4 and IPv6. */ void dump_route_tables(); diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c index 3e0b24be41..d679787966 100644 --- a/cmds/dumpstate/utils.c +++ b/cmds/dumpstate/utils.c @@ -53,6 +53,12 @@ static const char* native_processes_to_dump[] = { NULL, }; +static uint64_t nanotime() { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (uint64_t)ts.tv_sec * NANOS_PER_SEC + ts.tv_nsec; +} + void for_each_userid(void (*func)(int), const char *header) { DIR *d; struct dirent *de; @@ -98,7 +104,7 @@ static void __for_each_pid(void (*helper)(int, const char *, void *), const char sprintf(cmdpath,"/proc/%d/cmdline", pid); memset(cmdline, 0, sizeof(cmdline)); - if ((fd = open(cmdpath, O_RDONLY)) < 0) { + if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) < 0) { strcpy(cmdline, "N/A"); } else { read(fd, cmdline, sizeof(cmdline) - 1); @@ -149,7 +155,7 @@ static void for_each_tid_helper(int pid, const char *cmdline, void *arg) { sprintf(commpath,"/proc/%d/comm", tid); memset(comm, 0, sizeof(comm)); - if ((fd = open(commpath, O_RDONLY)) < 0) { + if ((fd = TEMP_FAILURE_RETRY(open(commpath, O_RDONLY | O_CLOEXEC))) < 0) { strcpy(comm, "N/A"); } else { char *c; @@ -180,7 +186,7 @@ void show_wchan(int pid, int tid, const char *name) { memset(buffer, 0, sizeof(buffer)); sprintf(path, "/proc/%d/wchan", tid); - if ((fd = open(path, O_RDONLY)) < 0) { + if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) { printf("Failed to open '%s' (%s)\n", path, strerror(errno)); return; } @@ -200,22 +206,6 @@ out_close: return; } -void do_dump_settings(int userid) { - char title[255]; - char dbpath[255]; - char sql[255]; - sprintf(title, "SYSTEM SETTINGS (user %d)", userid); - if (userid == 0) { - strcpy(dbpath, "/data/data/com.android.providers.settings/databases/settings.db"); - strcpy(sql, "pragma user_version; select * from system; select * from secure; select * from global;"); - } else { - sprintf(dbpath, "/data/system/users/%d/settings.db", userid); - strcpy(sql, "pragma user_version; select * from system; select * from secure;"); - } - run_command(title, 20, SU_PATH, "root", "sqlite3", dbpath, sql, NULL); - return; -} - void do_dmesg() { printf("------ KERNEL LOG (dmesg) ------\n"); /* Get size of kernel buffer */ @@ -250,22 +240,7 @@ void do_showmap(int pid, const char *name) { run_command(title, 10, SU_PATH, "root", "showmap", arg, NULL); } -/* prints the contents of a file */ -int dump_file(const char *title, const char *path) { - int fd = open(path, O_RDONLY); - if (fd < 0) { - int err = errno; - if (title) printf("------ %s (%s) ------\n", title, path); - printf("*** %s: %s\n", path, strerror(err)); - if (title) printf("\n"); - return -1; - } - return dump_file_from_fd(title, path, fd); -} - -int dump_file_from_fd(const char *title, const char *path, int fd) { - char buffer[32768]; - +static int _dump_file_from_fd(const char *title, const char *path, int fd) { if (title) printf("------ %s (%s", title, path); if (title) { @@ -279,14 +254,41 @@ int dump_file_from_fd(const char *title, const char *path, int fd) { printf(") ------\n"); } - int newline = 0; - for (;;) { - int ret = read(fd, buffer, sizeof(buffer)); - if (ret > 0) { - newline = (buffer[ret - 1] == '\n'); - ret = fwrite(buffer, ret, 1, stdout); + bool newline = false; + fd_set read_set; + struct timeval tm; + while (1) { + FD_ZERO(&read_set); + FD_SET(fd, &read_set); + /* Timeout if no data is read for 30 seconds. */ + tm.tv_sec = 30; + tm.tv_usec = 0; + uint64_t elapsed = nanotime(); + int ret = TEMP_FAILURE_RETRY(select(fd + 1, &read_set, NULL, NULL, &tm)); + if (ret == -1) { + printf("*** %s: select failed: %s\n", path, strerror(errno)); + newline = true; + break; + } else if (ret == 0) { + elapsed = nanotime() - elapsed; + printf("*** %s: Timed out after %.3fs\n", path, + (float) elapsed / NANOS_PER_SEC); + newline = true; + break; + } else { + char buffer[65536]; + ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer))); + if (bytes_read > 0) { + fwrite(buffer, bytes_read, 1, stdout); + newline = (buffer[bytes_read-1] == '\n'); + } else { + if (bytes_read == -1) { + printf("*** %s: Failed to read from fd: %s", path, strerror(errno)); + newline = true; + } + break; + } } - if (ret <= 0) break; } close(fd); @@ -295,16 +297,152 @@ int dump_file_from_fd(const char *title, const char *path, int fd) { return 0; } -static int64_t nanotime() { +/* prints the contents of a file */ +int dump_file(const char *title, const char *path) { + int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC)); + if (fd < 0) { + int err = errno; + if (title) printf("------ %s (%s) ------\n", title, path); + printf("*** %s: %s\n", path, strerror(err)); + if (title) printf("\n"); + return -1; + } + return _dump_file_from_fd(title, path, fd); +} + +/* calls skip to gate calling dump_from_fd recursively + * in the specified directory. dump_from_fd defaults to + * dump_file_from_fd above when set to NULL. skip defaults + * to false when set to NULL. dump_from_fd will always be + * called with title NULL. + */ +int dump_files(const char *title, const char *dir, + bool (*skip)(const char *path), + int (*dump_from_fd)(const char *title, const char *path, int fd)) { + DIR *dirp; + struct dirent *d; + char *newpath = NULL; + char *slash = "/"; + int fd, retval = 0; + + if (title) { + printf("------ %s (%s) ------\n", title, dir); + } + + if (dir[strlen(dir) - 1] == '/') { + ++slash; + } + dirp = opendir(dir); + if (dirp == NULL) { + retval = -errno; + fprintf(stderr, "%s: %s\n", dir, strerror(errno)); + return retval; + } + + if (!dump_from_fd) { + dump_from_fd = dump_file_from_fd; + } + for (; ((d = readdir(dirp))); free(newpath), newpath = NULL) { + if ((d->d_name[0] == '.') + && (((d->d_name[1] == '.') && (d->d_name[2] == '\0')) + || (d->d_name[1] == '\0'))) { + continue; + } + asprintf(&newpath, "%s%s%s%s", dir, slash, d->d_name, + (d->d_type == DT_DIR) ? "/" : ""); + if (!newpath) { + retval = -errno; + continue; + } + if (skip && (*skip)(newpath)) { + continue; + } + if (d->d_type == DT_DIR) { + int ret = dump_files(NULL, newpath, skip, dump_from_fd); + if (ret < 0) { + retval = ret; + } + continue; + } + fd = TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC)); + if (fd < 0) { + retval = fd; + printf("*** %s: %s\n", newpath, strerror(errno)); + continue; + } + (*dump_from_fd)(NULL, newpath, fd); + } + closedir(dirp); + if (title) { + printf("\n"); + } + return retval; +} + +/* fd must have been opened with the flag O_NONBLOCK. With this flag set, + * it's possible to avoid issues where opening the file itself can get + * stuck. + */ +int dump_file_from_fd(const char *title, const char *path, int fd) { + int flags = fcntl(fd, F_GETFL); + if (flags == -1) { + printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno)); + return -1; + } else if (!(flags & O_NONBLOCK)) { + printf("*** %s: fd must have O_NONBLOCK set.\n", path); + return -1; + } + return _dump_file_from_fd(title, path, fd); +} + +bool waitpid_with_timeout(pid_t pid, int timeout_seconds, int* status) { + sigset_t child_mask, old_mask; + sigemptyset(&child_mask); + sigaddset(&child_mask, SIGCHLD); + + if (sigprocmask(SIG_BLOCK, &child_mask, &old_mask) == -1) { + printf("*** sigprocmask failed: %s\n", strerror(errno)); + return false; + } + struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return (int64_t)ts.tv_sec * NANOS_PER_SEC + ts.tv_nsec; + ts.tv_sec = timeout_seconds; + ts.tv_nsec = 0; + int ret = TEMP_FAILURE_RETRY(sigtimedwait(&child_mask, NULL, &ts)); + int saved_errno = errno; + // Set the signals back the way they were. + if (sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1) { + printf("*** sigprocmask failed: %s\n", strerror(errno)); + if (ret == 0) { + return false; + } + } + if (ret == -1) { + errno = saved_errno; + if (errno == EAGAIN) { + errno = ETIMEDOUT; + } else { + printf("*** sigtimedwait failed: %s\n", strerror(errno)); + } + return false; + } + + pid_t child_pid = waitpid(pid, status, WNOHANG); + if (child_pid != pid) { + if (child_pid != -1) { + printf("*** Waiting for pid %d, got pid %d instead\n", pid, child_pid); + } else { + printf("*** waitpid failed: %s\n", strerror(errno)); + } + return false; + } + return true; } /* forks a command and waits for it to finish */ int run_command(const char *title, int timeout_seconds, const char *command, ...) { fflush(stdout); - int64_t start = nanotime(); + uint64_t start = nanotime(); pid_t pid = fork(); /* handle error case */ @@ -345,28 +483,35 @@ int run_command(const char *title, int timeout_seconds, const char *command, ... } /* handle parent case */ - for (;;) { - int status; - pid_t p = waitpid(pid, &status, WNOHANG); - int64_t elapsed = nanotime() - start; - if (p == pid) { - if (WIFSIGNALED(status)) { - printf("*** %s: Killed by signal %d\n", command, WTERMSIG(status)); - } else if (WIFEXITED(status) && WEXITSTATUS(status) > 0) { - printf("*** %s: Exit code %d\n", command, WEXITSTATUS(status)); - } - if (title) printf("[%s: %.3fs elapsed]\n\n", command, (float)elapsed / NANOS_PER_SEC); - return status; + int status; + bool ret = waitpid_with_timeout(pid, timeout_seconds, &status); + uint64_t elapsed = nanotime() - start; + if (!ret) { + if (errno == ETIMEDOUT) { + printf("*** %s: Timed out after %.3fs (killing pid %d)\n", command, + (float) elapsed / NANOS_PER_SEC, pid); + } else { + printf("*** %s: Error after %.4fs (killing pid %d)\n", command, + (float) elapsed / NANOS_PER_SEC, pid); } - - if (timeout_seconds && elapsed / NANOS_PER_SEC > timeout_seconds) { - printf("*** %s: Timed out after %.3fs (killing pid %d)\n", command, (float) elapsed / NANOS_PER_SEC, pid); - kill(pid, SIGTERM); - return -1; + kill(pid, SIGTERM); + if (!waitpid_with_timeout(pid, 5, NULL)) { + kill(pid, SIGKILL); + if (!waitpid_with_timeout(pid, 5, NULL)) { + printf("*** %s: Cannot kill %d even with SIGKILL.\n", command, pid); + } } + return -1; + } - usleep(100000); // poll every 0.1 sec + if (WIFSIGNALED(status)) { + printf("*** %s: Killed by signal %d\n", command, WTERMSIG(status)); + } else if (WIFEXITED(status) && WEXITSTATUS(status) > 0) { + printf("*** %s: Exit code %d\n", command, WEXITSTATUS(status)); } + if (title) printf("[%s: %.3fs elapsed]\n\n", command, (float)elapsed / NANOS_PER_SEC); + + return status; } size_t num_props = 0; @@ -407,6 +552,7 @@ void redirect_to_socket(FILE *redirect, const char *service) { fprintf(stderr, "android_get_control_socket(%s): %s\n", service, strerror(errno)); exit(1); } + fcntl(s, F_SETFD, FD_CLOEXEC); if (listen(s, 4) < 0) { fprintf(stderr, "listen(control socket): %s\n", strerror(errno)); exit(1); @@ -425,8 +571,8 @@ void redirect_to_socket(FILE *redirect, const char *service) { close(fd); } -/* redirect output to a file, optionally gzipping; returns gzip pid (or -1) */ -pid_t redirect_to_file(FILE *redirect, char *path, int gzip_level) { +/* redirect output to a file */ +void redirect_to_file(FILE *redirect, char *path) { char *chp = path; /* skip initial slash */ @@ -443,52 +589,15 @@ pid_t redirect_to_file(FILE *redirect, char *path, int gzip_level) { } } - int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + int fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)); if (fd < 0) { fprintf(stderr, "%s: %s\n", path, strerror(errno)); exit(1); } - pid_t gzip_pid = -1; - if (gzip_level > 0) { - int fds[2]; - if (pipe(fds)) { - fprintf(stderr, "pipe: %s\n", strerror(errno)); - exit(1); - } - - fflush(redirect); - fflush(stdout); - - gzip_pid = fork(); - if (gzip_pid < 0) { - fprintf(stderr, "fork: %s\n", strerror(errno)); - exit(1); - } - - if (gzip_pid == 0) { - dup2(fds[0], STDIN_FILENO); - dup2(fd, STDOUT_FILENO); - - close(fd); - close(fds[0]); - close(fds[1]); - - char level[10]; - snprintf(level, sizeof(level), "-%d", gzip_level); - execlp("gzip", "gzip", level, NULL); - fprintf(stderr, "exec(gzip): %s\n", strerror(errno)); - _exit(-1); - } - - close(fd); - close(fds[0]); - fd = fds[1]; - } - - dup2(fd, fileno(redirect)); + TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect))); close(fd); - return gzip_pid; } static bool should_dump_native_traces(const char* path) { @@ -536,7 +645,8 @@ const char *dump_traces() { } /* create a new, empty traces.txt file to receive stack dumps */ - int fd = open(traces_path, O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW, 0666); /* -rw-rw-rw- */ + int fd = TEMP_FAILURE_RETRY(open(traces_path, O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW | O_CLOEXEC, + 0666)); /* -rw-rw-rw- */ if (fd < 0) { fprintf(stderr, "%s: %s\n", traces_path, strerror(errno)); return NULL; @@ -586,7 +696,7 @@ const char *dump_traces() { if (!strncmp(data, "/system/bin/app_process", strlen("/system/bin/app_process"))) { /* skip zygote -- it won't dump its stack anyway */ snprintf(path, sizeof(path), "/proc/%d/cmdline", pid); - int cfd = open(path, O_RDONLY); + int cfd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC)); len = read(cfd, data, sizeof(data) - 1); close(cfd); if (len <= 0) { @@ -598,7 +708,7 @@ const char *dump_traces() { } ++dalvik_found; - int64_t start = nanotime(); + uint64_t start = nanotime(); if (kill(pid, SIGQUIT)) { fprintf(stderr, "kill(%d, SIGQUIT): %s\n", pid, strerror(errno)); continue; @@ -628,7 +738,7 @@ const char *dump_traces() { fprintf(stderr, "lseek: %s\n", strerror(errno)); } else { static uint16_t timeout_failures = 0; - int64_t start = nanotime(); + uint64_t start = nanotime(); /* If 3 backtrace dumps fail in a row, consider debuggerd dead. */ if (timeout_failures == 3) { @@ -671,7 +781,7 @@ error_close_fd: void dump_route_tables() { const char* const RT_TABLES_PATH = "/data/misc/net/rt_tables"; dump_file("RT_TABLES", RT_TABLES_PATH); - FILE* fp = fopen(RT_TABLES_PATH, "r"); + FILE* fp = fopen(RT_TABLES_PATH, "re"); if (!fp) { printf("*** %s: %s\n", RT_TABLES_PATH, strerror(errno)); return; diff --git a/cmds/installd/Android.mk b/cmds/installd/Android.mk index 8224e94b39..6dec7f6895 100644 --- a/cmds/installd/Android.mk +++ b/cmds/installd/Android.mk @@ -1,6 +1,6 @@ LOCAL_PATH := $(call my-dir) -common_src_files := commands.c utils.c +common_src_files := commands.cpp utils.cpp common_cflags := -Wall -Werror # @@ -12,7 +12,12 @@ LOCAL_MODULE := libinstalld LOCAL_MODULE_TAGS := eng tests LOCAL_SRC_FILES := $(common_src_files) LOCAL_CFLAGS := $(common_cflags) +LOCAL_SHARED_LIBRARIES := \ + libbase \ + liblogwrap \ + LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk +LOCAL_CLANG := true include $(BUILD_STATIC_LIBRARY) # @@ -23,8 +28,15 @@ include $(CLEAR_VARS) LOCAL_MODULE := installd LOCAL_MODULE_TAGS := optional LOCAL_CFLAGS := $(common_cflags) -LOCAL_SRC_FILES := installd.c $(common_src_files) -LOCAL_SHARED_LIBRARIES := libcutils liblog libselinux +LOCAL_SRC_FILES := installd.cpp $(common_src_files) +LOCAL_SHARED_LIBRARIES := \ + libbase \ + libcutils \ + liblog \ + liblogwrap \ + libselinux \ + LOCAL_STATIC_LIBRARIES := libdiskusage LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk +LOCAL_CLANG := true include $(BUILD_EXECUTABLE) diff --git a/cmds/installd/commands.c b/cmds/installd/commands.cpp index 76bc9d5ce2..7090b36775 100644 --- a/cmds/installd/commands.c +++ b/cmds/installd/commands.cpp @@ -14,13 +14,22 @@ ** limitations under the License. */ -#include <inttypes.h> -#include <sys/capability.h> #include "installd.h" + +#include <base/stringprintf.h> +#include <base/logging.h> #include <cutils/sched_policy.h> #include <diskusage/dirsize.h> -#include <selinux/android.h> +#include <logwrap/logwrap.h> #include <system/thread_defs.h> +#include <selinux/android.h> + +#include <inttypes.h> +#include <sys/capability.h> +#include <sys/file.h> +#include <unistd.h> + +using android::base::StringPrintf; /* Directory records that are used in execution of commands. */ dir_rec_t android_data_dir; @@ -29,34 +38,20 @@ dir_rec_t android_app_dir; dir_rec_t android_app_private_dir; dir_rec_t android_app_lib_dir; dir_rec_t android_media_dir; +dir_rec_t android_mnt_expand_dir; dir_rec_array_t android_system_dirs; -int install(const char *pkgname, uid_t uid, gid_t gid, const char *seinfo) -{ - char pkgdir[PKG_PATH_MAX]; - char libsymlink[PKG_PATH_MAX]; - char applibdir[PKG_PATH_MAX]; - struct stat libStat; +static const char* kCpPath = "/system/bin/cp"; +int install(const char *uuid, const char *pkgname, uid_t uid, gid_t gid, const char *seinfo) +{ if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) { ALOGE("invalid uid/gid: %d %d\n", uid, gid); return -1; } - if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) { - ALOGE("cannot create package path\n"); - return -1; - } - - if (create_pkg_path(libsymlink, pkgname, PKG_LIB_POSTFIX, 0)) { - ALOGE("cannot create package lib symlink origin path\n"); - return -1; - } - - if (create_pkg_path_in_dir(applibdir, &android_app_lib_dir, pkgname, PKG_DIR_POSTFIX)) { - ALOGE("cannot create package lib symlink dest path\n"); - return -1; - } + std::string _pkgdir(create_data_user_package_path(uuid, 0, pkgname)); + const char* pkgdir = _pkgdir.c_str(); if (mkdir(pkgdir, 0751) < 0) { ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno)); @@ -68,42 +63,14 @@ int install(const char *pkgname, uid_t uid, gid_t gid, const char *seinfo) return -1; } - if (lstat(libsymlink, &libStat) < 0) { - if (errno != ENOENT) { - ALOGE("couldn't stat lib dir: %s\n", strerror(errno)); - return -1; - } - } else { - if (S_ISDIR(libStat.st_mode)) { - if (delete_dir_contents(libsymlink, 1, NULL) < 0) { - ALOGE("couldn't delete lib directory during install for: %s", libsymlink); - return -1; - } - } else if (S_ISLNK(libStat.st_mode)) { - if (unlink(libsymlink) < 0) { - ALOGE("couldn't unlink lib directory during install for: %s", libsymlink); - return -1; - } - } - } - if (selinux_android_setfilecon(pkgdir, pkgname, seinfo, uid) < 0) { ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno)); - unlink(libsymlink); unlink(pkgdir); return -errno; } - if (symlink(applibdir, libsymlink) < 0) { - ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libsymlink, applibdir, - strerror(errno)); - unlink(pkgdir); - return -1; - } - if (chown(pkgdir, uid, gid) < 0) { ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno)); - unlink(libsymlink); unlink(pkgdir); return -1; } @@ -111,12 +78,10 @@ int install(const char *pkgname, uid_t uid, gid_t gid, const char *seinfo) return 0; } -int uninstall(const char *pkgname, userid_t userid) +int uninstall(const char *uuid, const char *pkgname, userid_t userid) { - char pkgdir[PKG_PATH_MAX]; - - if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, userid)) - return -1; + std::string _pkgdir(create_data_user_package_path(uuid, userid, pkgname)); + const char* pkgdir = _pkgdir.c_str(); remove_profile_file(pkgname); @@ -141,21 +106,17 @@ int renamepkg(const char *oldpkgname, const char *newpkgname) return 0; } -int fix_uid(const char *pkgname, uid_t uid, gid_t gid) +int fix_uid(const char *uuid, const char *pkgname, uid_t uid, gid_t gid) { - char pkgdir[PKG_PATH_MAX]; struct stat s; - int rc = 0; if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) { ALOGE("invalid uid/gid: %d %d\n", uid, gid); return -1; } - if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) { - ALOGE("cannot create package path\n"); - return -1; - } + std::string _pkgdir(create_data_user_package_path(uuid, 0, pkgname)); + const char* pkgdir = _pkgdir.c_str(); if (stat(pkgdir, &s) < 0) return -1; @@ -178,35 +139,18 @@ int fix_uid(const char *pkgname, uid_t uid, gid_t gid) return 0; } -int delete_user_data(const char *pkgname, userid_t userid) +int delete_user_data(const char *uuid, const char *pkgname, userid_t userid) { - char pkgdir[PKG_PATH_MAX]; - - if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, userid)) - return -1; + std::string _pkgdir(create_data_user_package_path(uuid, userid, pkgname)); + const char* pkgdir = _pkgdir.c_str(); return delete_dir_contents(pkgdir, 0, NULL); } -int make_user_data(const char *pkgname, uid_t uid, userid_t userid, const char* seinfo) +int make_user_data(const char *uuid, const char *pkgname, uid_t uid, userid_t userid, const char* seinfo) { - char pkgdir[PKG_PATH_MAX]; - char applibdir[PKG_PATH_MAX]; - char libsymlink[PKG_PATH_MAX]; - struct stat libStat; - - // Create the data dir for the package - if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, userid)) { - return -1; - } - if (create_pkg_path(libsymlink, pkgname, PKG_LIB_POSTFIX, userid)) { - ALOGE("cannot create package lib symlink origin path\n"); - return -1; - } - if (create_pkg_path_in_dir(applibdir, &android_app_lib_dir, pkgname, PKG_DIR_POSTFIX)) { - ALOGE("cannot create package lib symlink dest path\n"); - return -1; - } + std::string _pkgdir(create_data_user_package_path(uuid, userid, pkgname)); + const char* pkgdir = _pkgdir.c_str(); if (mkdir(pkgdir, 0751) < 0) { ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno)); @@ -218,47 +162,14 @@ int make_user_data(const char *pkgname, uid_t uid, userid_t userid, const char* return -errno; } - if (lstat(libsymlink, &libStat) < 0) { - if (errno != ENOENT) { - ALOGE("couldn't stat lib dir for non-primary: %s\n", strerror(errno)); - unlink(pkgdir); - return -1; - } - } else { - if (S_ISDIR(libStat.st_mode)) { - if (delete_dir_contents(libsymlink, 1, NULL) < 0) { - ALOGE("couldn't delete lib directory during install for non-primary: %s", - libsymlink); - unlink(pkgdir); - return -1; - } - } else if (S_ISLNK(libStat.st_mode)) { - if (unlink(libsymlink) < 0) { - ALOGE("couldn't unlink lib directory during install for non-primary: %s", - libsymlink); - unlink(pkgdir); - return -1; - } - } - } - if (selinux_android_setfilecon(pkgdir, pkgname, seinfo, uid) < 0) { ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno)); - unlink(libsymlink); unlink(pkgdir); return -errno; } - if (symlink(applibdir, libsymlink) < 0) { - ALOGE("couldn't symlink directory for non-primary '%s' -> '%s': %s\n", libsymlink, - applibdir, strerror(errno)); - unlink(pkgdir); - return -1; - } - if (chown(pkgdir, uid, uid) < 0) { ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno)); - unlink(libsymlink); unlink(pkgdir); return -errno; } @@ -266,6 +177,115 @@ int make_user_data(const char *pkgname, uid_t uid, userid_t userid, const char* return 0; } +int copy_complete_app(const char *from_uuid, const char *to_uuid, + const char *package_name, const char *data_app_name, appid_t appid, + const char* seinfo) { + std::vector<userid_t> users = get_known_users(from_uuid); + + // Copy app + { + std::string from(create_data_app_package_path(from_uuid, data_app_name)); + std::string to(create_data_app_package_path(to_uuid, data_app_name)); + std::string to_parent(create_data_app_path(to_uuid)); + + char *argv[] = { + (char*) kCpPath, + (char*) "-F", /* delete any existing destination file first (--remove-destination) */ + (char*) "-p", /* preserve timestamps, ownership, and permissions */ + (char*) "-R", /* recurse into subdirectories (DEST must be a directory) */ + (char*) "-P", /* Do not follow symlinks [default] */ + (char*) "-d", /* don't dereference symlinks */ + (char*) from.c_str(), + (char*) to_parent.c_str() + }; + + LOG(DEBUG) << "Copying " << from << " to " << to; + int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true); + + if (rc != 0) { + LOG(ERROR) << "Failed copying " << from << " to " << to + << ": status " << rc; + goto fail; + } + + if (selinux_android_restorecon(to.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) { + LOG(ERROR) << "Failed to restorecon " << to; + goto fail; + } + } + + // Copy private data for all known users + for (auto user : users) { + std::string from(create_data_user_package_path(from_uuid, user, package_name)); + std::string to(create_data_user_package_path(to_uuid, user, package_name)); + std::string to_parent(create_data_user_path(to_uuid, user)); + + // Data source may not exist for all users; that's okay + if (access(from.c_str(), F_OK) != 0) { + LOG(INFO) << "Missing source " << from; + continue; + } + + std::string user_path(create_data_user_path(to_uuid, user)); + if (fs_prepare_dir(user_path.c_str(), 0771, AID_SYSTEM, AID_SYSTEM) != 0) { + LOG(ERROR) << "Failed to prepare user target " << user_path; + goto fail; + } + + uid_t uid = multiuser_get_uid(user, appid); + if (make_user_data(to_uuid, package_name, uid, user, seinfo) != 0) { + LOG(ERROR) << "Failed to create package target " << to; + goto fail; + } + + char *argv[] = { + (char*) kCpPath, + (char*) "-F", /* delete any existing destination file first (--remove-destination) */ + (char*) "-p", /* preserve timestamps, ownership, and permissions */ + (char*) "-R", /* recurse into subdirectories (DEST must be a directory) */ + (char*) "-P", /* Do not follow symlinks [default] */ + (char*) "-d", /* don't dereference symlinks */ + (char*) from.c_str(), + (char*) to_parent.c_str() + }; + + LOG(DEBUG) << "Copying " << from << " to " << to; + int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true); + + if (rc != 0) { + LOG(ERROR) << "Failed copying " << from << " to " << to + << ": status " << rc; + goto fail; + } + } + + if (restorecon_data(to_uuid, package_name, seinfo, multiuser_get_uid(0, appid)) != 0) { + LOG(ERROR) << "Failed to restorecon"; + goto fail; + } + + // We let the framework scan the new location and persist that before + // deleting the data in the old location; this ordering ensures that + // we can recover from things like battery pulls. + return 0; + +fail: + // Nuke everything we might have already copied + { + std::string to(create_data_app_package_path(to_uuid, data_app_name)); + if (delete_dir_contents(to.c_str(), 1, NULL) != 0) { + LOG(WARNING) << "Failed to rollback " << to; + } + } + for (auto user : users) { + std::string to(create_data_user_package_path(to_uuid, user, package_name)); + if (delete_dir_contents(to.c_str(), 1, NULL) != 0) { + LOG(WARNING) << "Failed to rollback " << to; + } + } + return -1; +} + int make_user_config(userid_t userid) { if (ensure_config_user_dirs(userid) == -1) { @@ -275,49 +295,49 @@ int make_user_config(userid_t userid) return 0; } -int delete_user(userid_t userid) +int delete_user(const char *uuid, userid_t userid) { int status = 0; - char data_path[PKG_PATH_MAX]; - if ((create_user_path(data_path, userid) != 0) - || (delete_dir_contents(data_path, 1, NULL) != 0)) { + std::string data_path(create_data_user_path(uuid, userid)); + if (delete_dir_contents(data_path.c_str(), 1, NULL) != 0) { status = -1; } - char media_path[PATH_MAX]; - if ((create_user_media_path(media_path, userid) != 0) - || (delete_dir_contents(media_path, 1, NULL) != 0)) { + std::string media_path(create_data_media_path(uuid, userid)); + if (delete_dir_contents(media_path.c_str(), 1, NULL) != 0) { status = -1; } - char config_path[PATH_MAX]; - if ((create_user_config_path(config_path, userid) != 0) - || (delete_dir_contents(config_path, 1, NULL) != 0)) { - status = -1; + // Config paths only exist on internal storage + if (uuid == nullptr) { + char config_path[PATH_MAX]; + if ((create_user_config_path(config_path, userid) != 0) + || (delete_dir_contents(config_path, 1, NULL) != 0)) { + status = -1; + } } return status; } -int delete_cache(const char *pkgname, userid_t userid) +int delete_cache(const char *uuid, const char *pkgname, userid_t userid) { - char cachedir[PKG_PATH_MAX]; - - if (create_pkg_path(cachedir, pkgname, CACHE_DIR_POSTFIX, userid)) - return -1; + std::string _cachedir( + create_data_user_package_path(uuid, userid, pkgname) + CACHE_DIR_POSTFIX); + const char* cachedir = _cachedir.c_str(); /* delete contents, not the directory, no exceptions */ return delete_dir_contents(cachedir, 0, NULL); } -int delete_code_cache(const char *pkgname, userid_t userid) +int delete_code_cache(const char *uuid, const char *pkgname, userid_t userid) { - char codecachedir[PKG_PATH_MAX]; - struct stat s; + std::string _codecachedir( + create_data_user_package_path(uuid, userid, pkgname) + CODE_CACHE_DIR_POSTFIX); + const char* codecachedir = _codecachedir.c_str(); - if (create_pkg_path(codecachedir, pkgname, CODE_CACHE_DIR_POSTFIX, userid)) - return -1; + struct stat s; /* it's okay if code cache is missing */ if (lstat(codecachedir, &s) == -1 && errno == ENOENT) { @@ -335,7 +355,7 @@ int delete_code_cache(const char *pkgname, userid_t userid) * also require that apps constantly modify file metadata even * when just reading from the cache, which is pretty awful. */ -int free_cache(int64_t free_size) +int free_cache(const char *uuid, int64_t free_size) { cache_t* cache; int64_t avail; @@ -344,7 +364,9 @@ int free_cache(int64_t free_size) char tmpdir[PATH_MAX]; char *dirpos; - avail = data_disk_free(); + std::string data_path(create_data_path(uuid)); + + avail = data_disk_free(data_path); if (avail < 0) return -1; ALOGI("free_cache(%" PRId64 ") avail %" PRId64 "\n", free_size, avail); @@ -352,15 +374,16 @@ int free_cache(int64_t free_size) cache = start_cache_collection(); - // Collect cache files for primary user. - if (create_user_path(tmpdir, 0) == 0) { - //ALOGI("adding cache files from %s\n", tmpdir); - add_cache_files(cache, tmpdir, "cache"); + // Special case for owner on internal storage + if (uuid == nullptr) { + std::string _tmpdir(create_data_user_path(nullptr, 0)); + add_cache_files(cache, _tmpdir.c_str(), "cache"); } // Search for other users and add any cache files from them. - snprintf(tmpdir, sizeof(tmpdir), "%s%s", android_data_dir.path, - SECONDARY_USER_PREFIX); + std::string _tmpdir(create_data_path(uuid) + "/" + SECONDARY_USER_PREFIX); + strcpy(tmpdir, _tmpdir.c_str()); + dirpos = tmpdir + strlen(tmpdir); d = opendir(tmpdir); if (d != NULL) { @@ -412,10 +435,10 @@ int free_cache(int64_t free_size) closedir(d); } - clear_cache_files(cache, free_size); + clear_cache_files(data_path, cache, free_size); finish_cache_collection(cache); - return data_disk_free() >= free_size ? 0 : -1; + return data_disk_free(data_path) >= free_size ? 0 : -1; } int move_dex(const char *src, const char *dst, const char *instruction_set) @@ -466,7 +489,7 @@ int rm_dex(const char *path, const char *instruction_set) } } -int get_size(const char *pkgname, userid_t userid, const char *apkpath, +int get_size(const char *uuid, const char *pkgname, int userid, const char *apkpath, const char *libdirpath, const char *fwdlock_apkpath, const char *asecpath, const char *instruction_set, int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize, int64_t* _asecsize) @@ -482,30 +505,38 @@ int get_size(const char *pkgname, userid_t userid, const char *apkpath, int64_t cachesize = 0; int64_t asecsize = 0; - /* count the source apk as code -- but only if it's not - * on the /system partition and its not on the sdcard. - */ + /* count the source apk as code -- but only if it's not + * on the /system partition and its not on the sdcard. */ if (validate_system_app_path(apkpath) && strncmp(apkpath, android_asec_dir.path, android_asec_dir.len) != 0) { if (stat(apkpath, &s) == 0) { codesize += stat_size(&s); + if (S_ISDIR(s.st_mode)) { + d = opendir(apkpath); + if (d != NULL) { + dfd = dirfd(d); + codesize += calculate_dir_size(dfd); + closedir(d); + } + } } } - /* count the forward locked apk as code if it is given - */ + + /* count the forward locked apk as code if it is given */ if (fwdlock_apkpath != NULL && fwdlock_apkpath[0] != '!') { if (stat(fwdlock_apkpath, &s) == 0) { codesize += stat_size(&s); } } - /* count the cached dexfile as code */ + + /* count the cached dexfile as code */ if (!create_cache_path(path, apkpath, instruction_set)) { if (stat(path, &s) == 0) { codesize += stat_size(&s); } } - /* add in size of any libraries */ + /* add in size of any libraries */ if (libdirpath != NULL && libdirpath[0] != '!') { d = opendir(libdirpath); if (d != NULL) { @@ -515,69 +546,76 @@ int get_size(const char *pkgname, userid_t userid, const char *apkpath, } } - /* compute asec size if it is given - */ + /* compute asec size if it is given */ if (asecpath != NULL && asecpath[0] != '!') { if (stat(asecpath, &s) == 0) { asecsize += stat_size(&s); } } - if (create_pkg_path(path, pkgname, PKG_DIR_POSTFIX, userid)) { - goto done; + std::vector<userid_t> users; + if (userid == -1) { + users = get_known_users(uuid); + } else { + users.push_back(userid); } - d = opendir(path); - if (d == NULL) { - goto done; - } - dfd = dirfd(d); + for (auto user : users) { + std::string _pkgdir(create_data_user_package_path(uuid, user, pkgname)); + const char* pkgdir = _pkgdir.c_str(); - /* most stuff in the pkgdir is data, except for the "cache" - * directory and below, which is cache, and the "lib" directory - * and below, which is code... - */ - while ((de = readdir(d))) { - const char *name = de->d_name; + d = opendir(pkgdir); + if (d == NULL) { + PLOG(WARNING) << "Failed to open " << pkgdir; + continue; + } + dfd = dirfd(d); - if (de->d_type == DT_DIR) { - int subfd; - int64_t statsize = 0; - int64_t dirsize = 0; - /* always skip "." and ".." */ - if (name[0] == '.') { - if (name[1] == 0) continue; - if ((name[1] == '.') && (name[2] == 0)) continue; - } - if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) { - statsize = stat_size(&s); - } - subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY); - if (subfd >= 0) { - dirsize = calculate_dir_size(subfd); - } - if(!strcmp(name,"lib")) { - codesize += dirsize + statsize; - } else if(!strcmp(name,"cache")) { - cachesize += dirsize + statsize; + /* most stuff in the pkgdir is data, except for the "cache" + * directory and below, which is cache, and the "lib" directory + * and below, which is code... + */ + while ((de = readdir(d))) { + const char *name = de->d_name; + + if (de->d_type == DT_DIR) { + int subfd; + int64_t statsize = 0; + int64_t dirsize = 0; + /* always skip "." and ".." */ + if (name[0] == '.') { + if (name[1] == 0) continue; + if ((name[1] == '.') && (name[2] == 0)) continue; + } + if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) { + statsize = stat_size(&s); + } + subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY); + if (subfd >= 0) { + dirsize = calculate_dir_size(subfd); + } + if(!strcmp(name,"lib")) { + codesize += dirsize + statsize; + } else if(!strcmp(name,"cache")) { + cachesize += dirsize + statsize; + } else { + datasize += dirsize + statsize; + } + } else if (de->d_type == DT_LNK && !strcmp(name,"lib")) { + // This is the symbolic link to the application's library + // code. We'll count this as code instead of data, since + // it is not something that the app creates. + if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) { + codesize += stat_size(&s); + } } else { - datasize += dirsize + statsize; - } - } else if (de->d_type == DT_LNK && !strcmp(name,"lib")) { - // This is the symbolic link to the application's library - // code. We'll count this as code instead of data, since - // it is not something that the app creates. - if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) { - codesize += stat_size(&s); - } - } else { - if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) { - datasize += stat_size(&s); + if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) { + datasize += stat_size(&s); + } } } + closedir(d); } - closedir(d); -done: *_codesize = codesize; *_datasize = datasize; *_cachesize = cachesize; @@ -625,30 +663,40 @@ int create_cache_path(char path[PKG_PATH_MAX], const char *src, const char *inst return 0; } -static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name, - const char* output_file_name) +static int split_count(const char *str) { - /* platform-specific flags affecting optimization and verification */ - char dexopt_flags[PROPERTY_VALUE_MAX]; - property_get("dalvik.vm.dexopt-flags", dexopt_flags, ""); - ALOGV("dalvik.vm.dexopt-flags=%s\n", dexopt_flags); + char *ctx; + int count = 0; + char buf[PROPERTY_VALUE_MAX]; - static const char* DEX_OPT_BIN = "/system/bin/dexopt"; - static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig - char zip_num[MAX_INT_LEN]; - char odex_num[MAX_INT_LEN]; + strncpy(buf, str, sizeof(buf)); + char *pBuf = buf; - sprintf(zip_num, "%d", zip_fd); - sprintf(odex_num, "%d", odex_fd); + while(strtok_r(pBuf, " ", &ctx) != NULL) { + count++; + pBuf = NULL; + } - ALOGV("Running %s in=%s out=%s\n", DEX_OPT_BIN, input_file_name, output_file_name); - execl(DEX_OPT_BIN, DEX_OPT_BIN, "--zip", zip_num, odex_num, input_file_name, - dexopt_flags, (char*) NULL); - ALOGE("execl(%s) failed: %s\n", DEX_OPT_BIN, strerror(errno)); + return count; +} + +static int split(char *buf, const char **argv) +{ + char *ctx; + int count = 0; + char *tok; + char *pBuf = buf; + + while((tok = strtok_r(pBuf, " ", &ctx)) != NULL) { + argv[count++] = tok; + pBuf = NULL; + } + + return count; } static void run_patchoat(int input_fd, int oat_fd, const char* input_file_name, - const char* output_file_name, const char *pkgname, const char *instruction_set) + const char* output_file_name, const char *pkgname __unused, const char *instruction_set) { static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig static const unsigned int MAX_INSTRUCTION_SET_LEN = 7; @@ -670,7 +718,7 @@ static void run_patchoat(int input_fd, int oat_fd, const char* input_file_name, sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set); sprintf(output_oat_fd_arg, "--output-oat-fd=%d", oat_fd); sprintf(input_oat_fd_arg, "--input-oat-fd=%d", input_fd); - ALOGE("Running %s isa=%s in-fd=%d (%s) out-fd=%d (%s)\n", + ALOGV("Running %s isa=%s in-fd=%d (%s) out-fd=%d (%s)\n", PATCHOAT_BIN, instruction_set, input_fd, input_file_name, oat_fd, output_file_name); /* patchoat, patched-image-location, no-lock, isa, input-fd, output-fd */ @@ -687,9 +735,18 @@ static void run_patchoat(int input_fd, int oat_fd, const char* input_file_name, ALOGE("execv(%s) failed: %s\n", PATCHOAT_BIN, strerror(errno)); } +static bool check_boolean_property(const char* property_name, bool default_value = false) { + char tmp_property_value[PROPERTY_VALUE_MAX]; + bool have_property = property_get(property_name, tmp_property_value, nullptr) > 0; + if (!have_property) { + return default_value; + } + return strcmp(tmp_property_value, "true") == 0; +} + static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name, const char* output_file_name, int swap_fd, const char *pkgname, const char *instruction_set, - bool vm_safe_mode) + bool vm_safe_mode, bool debuggable) { static const unsigned int MAX_INSTRUCTION_SET_LEN = 7; @@ -712,14 +769,32 @@ static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name, bool have_dex2oat_compiler_filter_flag = property_get("dalvik.vm.dex2oat-filter", dex2oat_compiler_filter_flag, NULL) > 0; + char dex2oat_threads_buf[PROPERTY_VALUE_MAX]; + bool have_dex2oat_threads_flag = property_get("dalvik.vm.dex2oat-threads", dex2oat_threads_buf, + NULL) > 0; + char dex2oat_threads_arg[PROPERTY_VALUE_MAX + 2]; + if (have_dex2oat_threads_flag) { + sprintf(dex2oat_threads_arg, "-j%s", dex2oat_threads_buf); + } + char dex2oat_isa_features_key[PROPERTY_KEY_MAX]; sprintf(dex2oat_isa_features_key, "dalvik.vm.isa.%s.features", instruction_set); char dex2oat_isa_features[PROPERTY_VALUE_MAX]; bool have_dex2oat_isa_features = property_get(dex2oat_isa_features_key, dex2oat_isa_features, NULL) > 0; + char dex2oat_isa_variant_key[PROPERTY_KEY_MAX]; + sprintf(dex2oat_isa_variant_key, "dalvik.vm.isa.%s.variant", instruction_set); + char dex2oat_isa_variant[PROPERTY_VALUE_MAX]; + bool have_dex2oat_isa_variant = property_get(dex2oat_isa_variant_key, + dex2oat_isa_variant, NULL) > 0; + + const char *dex2oat_norelocation = "-Xnorelocate"; + bool have_dex2oat_relocation_skip_flag = false; + char dex2oat_flags[PROPERTY_VALUE_MAX]; - bool have_dex2oat_flags = property_get("dalvik.vm.dex2oat-flags", dex2oat_flags, NULL) > 0; + int dex2oat_flags_count = property_get("dalvik.vm.dex2oat-flags", + dex2oat_flags, NULL) <= 0 ? 0 : split_count(dex2oat_flags); ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags); // If we booting without the real /data, don't spend time compiling. @@ -729,6 +804,9 @@ static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name, (strcmp(vold_decrypt, "trigger_restart_min_framework") == 0 || (strcmp(vold_decrypt, "1") == 0))); + bool use_jit = check_boolean_property("debug.usejit"); + bool generate_debug_info = check_boolean_property("debug.generate-debug-info"); + static const char* DEX2OAT_BIN = "/system/bin/dex2oat"; static const char* RUNTIME_ARG = "--runtime-arg"; @@ -740,6 +818,7 @@ static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name, char oat_fd_arg[strlen("--oat-fd=") + MAX_INT_LEN]; char oat_location_arg[strlen("--oat-location=") + PKG_PATH_MAX]; char instruction_set_arg[strlen("--instruction-set=") + MAX_INSTRUCTION_SET_LEN]; + char instruction_set_variant_arg[strlen("--instruction-set-variant=") + PROPERTY_VALUE_MAX]; char instruction_set_features_arg[strlen("--instruction-set-features=") + PROPERTY_VALUE_MAX]; char profile_file_arg[strlen("--profile-file=") + PKG_PATH_MAX]; char top_k_profile_threshold_arg[strlen("--top-k-profile-threshold=") + PROPERTY_VALUE_MAX]; @@ -754,6 +833,7 @@ static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name, sprintf(oat_fd_arg, "--oat-fd=%d", oat_fd); sprintf(oat_location_arg, "--oat-location=%s", output_file_name); sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set); + sprintf(instruction_set_variant_arg, "--instruction-set-variant=%s", dex2oat_isa_variant); sprintf(instruction_set_features_arg, "--instruction-set-features=%s", dex2oat_isa_features); if (swap_fd >= 0) { have_dex2oat_swap_fd = true; @@ -787,31 +867,50 @@ static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name, if (skip_compilation) { strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=verify-none"); have_dex2oat_compiler_filter_flag = true; + have_dex2oat_relocation_skip_flag = true; } else if (vm_safe_mode) { strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=interpret-only"); have_dex2oat_compiler_filter_flag = true; + } else if (use_jit) { + strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=verify-at-runtime"); + have_dex2oat_compiler_filter_flag = true; } else if (have_dex2oat_compiler_filter_flag) { sprintf(dex2oat_compiler_filter_arg, "--compiler-filter=%s", dex2oat_compiler_filter_flag); } + // Check whether all apps should be compiled debuggable. + if (!debuggable) { + debuggable = + (property_get("dalvik.vm.always_debuggable", prop_buf, "0") > 0) && + (prop_buf[0] == '1'); + } + ALOGV("Running %s in=%s out=%s\n", DEX2OAT_BIN, input_file_name, output_file_name); - char* argv[7 // program name, mandatory arguments and the final NULL - + (have_dex2oat_isa_features ? 1 : 0) - + (have_profile_file ? 1 : 0) - + (have_top_k_profile_threshold ? 1 : 0) - + (have_dex2oat_Xms_flag ? 2 : 0) - + (have_dex2oat_Xmx_flag ? 2 : 0) - + (have_dex2oat_compiler_filter_flag ? 1 : 0) - + (have_dex2oat_flags ? 1 : 0) - + (have_dex2oat_swap_fd ? 1 : 0)]; + const char* argv[7 // program name, mandatory arguments and the final NULL + + (have_dex2oat_isa_variant ? 1 : 0) + + (have_dex2oat_isa_features ? 1 : 0) + + (have_profile_file ? 1 : 0) + + (have_top_k_profile_threshold ? 1 : 0) + + (have_dex2oat_Xms_flag ? 2 : 0) + + (have_dex2oat_Xmx_flag ? 2 : 0) + + (have_dex2oat_compiler_filter_flag ? 1 : 0) + + (have_dex2oat_threads_flag ? 1 : 0) + + (have_dex2oat_swap_fd ? 1 : 0) + + (have_dex2oat_relocation_skip_flag ? 2 : 0) + + (generate_debug_info ? 1 : 0) + + (debuggable ? 1 : 0) + + dex2oat_flags_count]; int i = 0; - argv[i++] = (char*)DEX2OAT_BIN; + argv[i++] = DEX2OAT_BIN; argv[i++] = zip_fd_arg; argv[i++] = zip_location_arg; argv[i++] = oat_fd_arg; argv[i++] = oat_location_arg; argv[i++] = instruction_set_arg; + if (have_dex2oat_isa_variant) { + argv[i++] = instruction_set_variant_arg; + } if (have_dex2oat_isa_features) { argv[i++] = instruction_set_features_arg; } @@ -822,27 +921,40 @@ static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name, argv[i++] = top_k_profile_threshold_arg; } if (have_dex2oat_Xms_flag) { - argv[i++] = (char*)RUNTIME_ARG; + argv[i++] = RUNTIME_ARG; argv[i++] = dex2oat_Xms_arg; } if (have_dex2oat_Xmx_flag) { - argv[i++] = (char*)RUNTIME_ARG; + argv[i++] = RUNTIME_ARG; argv[i++] = dex2oat_Xmx_arg; } if (have_dex2oat_compiler_filter_flag) { argv[i++] = dex2oat_compiler_filter_arg; } - if (have_dex2oat_flags) { - argv[i++] = dex2oat_flags; + if (have_dex2oat_threads_flag) { + argv[i++] = dex2oat_threads_arg; } if (have_dex2oat_swap_fd) { argv[i++] = dex2oat_swap_fd; } + if (generate_debug_info) { + argv[i++] = "--generate-debug-info"; + } + if (debuggable) { + argv[i++] = "--debuggable"; + } + if (dex2oat_flags_count) { + i += split(dex2oat_flags, argv + i); + } + if (have_dex2oat_relocation_skip_flag) { + argv[i++] = RUNTIME_ARG; + argv[i++] = dex2oat_norelocation; + } // Do not add after dex2oat_flags, they should override others for debugging. argv[i] = NULL; - execv(DEX2OAT_BIN, (char* const *)argv); - ALOGE("execl(%s) failed: %s\n", DEX2OAT_BIN, strerror(errno)); + execv(DEX2OAT_BIN, (char * const *)argv); + ALOGE("execv(%s) failed: %s\n", DEX2OAT_BIN, strerror(errno)); } static int wait_child(pid_t pid) @@ -872,32 +984,95 @@ static int wait_child(pid_t pid) } /* - * Whether dexopt should use a swap file when compiling an APK. If kAlwaysProvideSwapFile, do this - * on all devices (dex2oat will make a more informed decision itself, anyways). Otherwise, only do - * this on a low-mem device. + * Whether dexopt should use a swap file when compiling an APK. + * + * If kAlwaysProvideSwapFile, do this on all devices (dex2oat will make a more informed decision + * itself, anyways). + * + * Otherwise, read "dalvik.vm.dex2oat-swap". If the property exists, return whether it is "true". + * + * Otherwise, return true if this is a low-mem device. + * + * Otherwise, return default value. */ -static bool kAlwaysProvideSwapFile = true; +static bool kAlwaysProvideSwapFile = false; +static bool kDefaultProvideSwapFile = true; static bool ShouldUseSwapFileForDexopt() { if (kAlwaysProvideSwapFile) { return true; } - char low_mem_buf[PROPERTY_VALUE_MAX]; - property_get("ro.config.low_ram", low_mem_buf, ""); - return (strcmp(low_mem_buf, "true") == 0); + // Check the "override" property. If it exists, return value == "true". + char dex2oat_prop_buf[PROPERTY_VALUE_MAX]; + if (property_get("dalvik.vm.dex2oat-swap", dex2oat_prop_buf, "") > 0) { + if (strcmp(dex2oat_prop_buf, "true") == 0) { + return true; + } else { + return false; + } + } + + // Shortcut for default value. This is an implementation optimization for the process sketched + // above. If the default value is true, we can avoid to check whether this is a low-mem device, + // as low-mem is never returning false. The compiler will optimize this away if it can. + if (kDefaultProvideSwapFile) { + return true; + } + + bool is_low_mem = check_boolean_property("ro.config.low_ram"); + if (is_low_mem) { + return true; + } + + // Default value must be false here. + return kDefaultProvideSwapFile; +} + +/* + * Computes the odex file for the given apk_path and instruction_set. + * /system/framework/whatever.jar -> /system/framework/oat/<isa>/whatever.odex + * + * Returns false if it failed to determine the odex file path. + */ +static bool calculate_odex_file_path(char path[PKG_PATH_MAX], + const char *apk_path, + const char *instruction_set) +{ + if (strlen(apk_path) + strlen("oat/") + strlen(instruction_set) + + strlen("/") + strlen("odex") + 1 > PKG_PATH_MAX) { + ALOGE("apk_path '%s' may be too long to form odex file path.\n", apk_path); + return false; + } + + strcpy(path, apk_path); + char *end = strrchr(path, '/'); + if (end == NULL) { + ALOGE("apk_path '%s' has no '/'s in it?!\n", apk_path); + return false; + } + const char *apk_end = apk_path + (end - path); // strrchr(apk_path, '/'); + + strcpy(end + 1, "oat/"); // path = /system/framework/oat/\0 + strcat(path, instruction_set); // path = /system/framework/oat/<isa>\0 + strcat(path, apk_end); // path = /system/framework/oat/<isa>/whatever.jar\0 + end = strrchr(path, '.'); + if (end == NULL) { + ALOGE("apk_path '%s' has no extension.\n", apk_path); + return false; + } + strcpy(end + 1, "odex"); + return true; } int dexopt(const char *apk_path, uid_t uid, bool is_public, - const char *pkgname, const char *instruction_set, - bool vm_safe_mode, bool is_patchoat) + const char *pkgname, const char *instruction_set, int dexopt_needed, + bool vm_safe_mode, bool debuggable, const char* oat_dir) { struct utimbuf ut; - struct stat input_stat, dex_stat; + struct stat input_stat; char out_path[PKG_PATH_MAX]; - char persist_sys_dalvik_vm_lib[PROPERTY_VALUE_MAX]; char swap_file_name[PKG_PATH_MAX]; - char *end; const char *input_file; char in_odex_path[PKG_PATH_MAX]; int res, input_fd=-1, out_fd=-1, swap_fd=-1; @@ -906,55 +1081,43 @@ int dexopt(const char *apk_path, uid_t uid, bool is_public, // Note: the cache path will require an additional 5 bytes for ".swap", but we'll try to run // without a swap file, if necessary. if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) { + ALOGE("apk_path too long '%s'\n", apk_path); return -1; } - /* The command to run depend on the value of persist.sys.dalvik.vm.lib */ - property_get("persist.sys.dalvik.vm.lib.2", persist_sys_dalvik_vm_lib, "libart.so"); - - if (is_patchoat && strncmp(persist_sys_dalvik_vm_lib, "libart", 6) != 0) { - /* We may only patch if we are libart */ - ALOGE("Patching is only supported in libart\n"); - return -1; - } - - /* Before anything else: is there a .odex file? If so, we have - * precompiled the apk and there is nothing to do here. - * - * We skip this if we are doing a patchoat. - */ - strcpy(out_path, apk_path); - end = strrchr(out_path, '.'); - if (end != NULL && !is_patchoat) { - strcpy(end, ".odex"); - if (stat(out_path, &dex_stat) == 0) { - return 0; - } - } - - if (create_cache_path(out_path, apk_path, instruction_set)) { - return -1; - } - - if (is_patchoat) { - /* /system/framework/whatever.jar -> /system/framework/<isa>/whatever.odex */ - strcpy(in_odex_path, apk_path); - end = strrchr(in_odex_path, '/'); - if (end == NULL) { - ALOGE("apk_path '%s' has no '/'s in it?!\n", apk_path); + if (oat_dir != NULL && oat_dir[0] != '!') { + if (validate_apk_path(oat_dir)) { + ALOGE("invalid oat_dir '%s'\n", oat_dir); return -1; } - const char *apk_end = apk_path + (end - in_odex_path); // strrchr(apk_path, '/'); - strcpy(end + 1, instruction_set); // in_odex_path now is /system/framework/<isa>\0 - strcat(in_odex_path, apk_end); - end = strrchr(in_odex_path, '.'); - if (end == NULL) { + if (calculate_oat_file_path(out_path, oat_dir, apk_path, instruction_set)) { return -1; } - strcpy(end + 1, "odex"); - input_file = in_odex_path; } else { - input_file = apk_path; + if (create_cache_path(out_path, apk_path, instruction_set)) { + return -1; + } + } + + switch (dexopt_needed) { + case DEXOPT_DEX2OAT_NEEDED: + input_file = apk_path; + break; + + case DEXOPT_PATCHOAT_NEEDED: + if (!calculate_odex_file_path(in_odex_path, apk_path, instruction_set)) { + return -1; + } + input_file = in_odex_path; + break; + + case DEXOPT_SELF_PATCHOAT_NEEDED: + input_file = out_path; + break; + + default: + ALOGE("Invalid dexopt needed: %d\n", dexopt_needed); + exit(72); } memset(&input_stat, 0, sizeof(input_stat)); @@ -989,7 +1152,7 @@ int dexopt(const char *apk_path, uid_t uid, bool is_public, } // Create a swap file if necessary. - if (!is_patchoat && ShouldUseSwapFileForDexopt()) { + if (ShouldUseSwapFileForDexopt()) { // Make sure there really is enough space. size_t out_len = strlen(out_path); if (out_len + strlen(".swap") + 1 <= PKG_PATH_MAX) { @@ -1048,17 +1211,21 @@ int dexopt(const char *apk_path, uid_t uid, bool is_public, exit(67); } - if (strncmp(persist_sys_dalvik_vm_lib, "libdvm", 6) == 0) { - run_dexopt(input_fd, out_fd, input_file, out_path); - } else if (strncmp(persist_sys_dalvik_vm_lib, "libart", 6) == 0) { - if (is_patchoat) { - run_patchoat(input_fd, out_fd, input_file, out_path, pkgname, instruction_set); + if (dexopt_needed == DEXOPT_PATCHOAT_NEEDED + || dexopt_needed == DEXOPT_SELF_PATCHOAT_NEEDED) { + run_patchoat(input_fd, out_fd, input_file, out_path, pkgname, instruction_set); + } else if (dexopt_needed == DEXOPT_DEX2OAT_NEEDED) { + const char *input_file_name = strrchr(input_file, '/'); + if (input_file_name == NULL) { + input_file_name = input_file; } else { - run_dex2oat(input_fd, out_fd, input_file, out_path, swap_fd, pkgname, - instruction_set, vm_safe_mode); + input_file_name++; } + run_dex2oat(input_fd, out_fd, input_file_name, out_path, swap_fd, pkgname, + instruction_set, vm_safe_mode, debuggable); } else { - exit(69); /* Unexpected persist.sys.dalvik.vm.lib value */ + ALOGE("Invalid dexopt needed: %d\n", dexopt_needed); + exit(73); } exit(68); /* only get here on exec failure */ } else { @@ -1368,21 +1535,16 @@ done: return 0; } -int linklib(const char* pkgname, const char* asecLibDir, int userId) +int linklib(const char* uuid, const char* pkgname, const char* asecLibDir, int userId) { - char pkgdir[PKG_PATH_MAX]; - char libsymlink[PKG_PATH_MAX]; struct stat s, libStat; int rc = 0; - if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, userId)) { - ALOGE("cannot create package path\n"); - return -1; - } - if (create_pkg_path(libsymlink, pkgname, PKG_LIB_POSTFIX, userId)) { - ALOGE("cannot create package lib symlink origin path\n"); - return -1; - } + std::string _pkgdir(create_data_user_package_path(uuid, userId, pkgname)); + std::string _libsymlink(_pkgdir + PKG_LIB_POSTFIX); + + const char* pkgdir = _pkgdir.c_str(); + const char* libsymlink = _libsymlink.c_str(); if (stat(pkgdir, &s) < 0) return -1; @@ -1551,14 +1713,12 @@ fail: return -1; } -int restorecon_data(const char* pkgName, const char* seinfo, uid_t uid) +int restorecon_data(const char* uuid, const char* pkgName, + const char* seinfo, uid_t uid) { struct dirent *entry; DIR *d; struct stat s; - char *userdir; - char *primarydir; - char *pkgdir; int ret = 0; // SELINUX_ANDROID_RESTORECON_DATADATA flag is set by libselinux. Not needed here. @@ -1569,26 +1729,20 @@ int restorecon_data(const char* pkgName, const char* seinfo, uid_t uid) return -1; } - if (asprintf(&primarydir, "%s%s%s", android_data_dir.path, PRIMARY_USER_PREFIX, pkgName) < 0) { - return -1; - } - - // Relabel for primary user. - if (selinux_android_restorecon_pkgdir(primarydir, seinfo, uid, flags) < 0) { - ALOGE("restorecon failed for %s: %s\n", primarydir, strerror(errno)); - ret |= -1; - } + // Special case for owner on internal storage + if (uuid == nullptr) { + std::string path(create_data_user_package_path(nullptr, 0, pkgName)); - if (asprintf(&userdir, "%s%s", android_data_dir.path, SECONDARY_USER_PREFIX) < 0) { - free(primarydir); - return -1; + if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid, flags) < 0) { + PLOG(ERROR) << "restorecon failed for " << path; + ret |= -1; + } } // Relabel package directory for all secondary users. - d = opendir(userdir); + std::string userdir(create_data_path(uuid) + "/" + SECONDARY_USER_PREFIX); + d = opendir(userdir.c_str()); if (d == NULL) { - free(primarydir); - free(userdir); return -1; } @@ -1609,25 +1763,100 @@ int restorecon_data(const char* pkgName, const char* seinfo, uid_t uid) continue; } - if (asprintf(&pkgdir, "%s%s/%s", userdir, user, pkgName) < 0) { + std::string pkgdir(StringPrintf("%s%s/%s", userdir.c_str(), user, pkgName)); + if (stat(pkgdir.c_str(), &s) < 0) { continue; } - if (stat(pkgdir, &s) < 0) { - free(pkgdir); - continue; - } - - if (selinux_android_restorecon_pkgdir(pkgdir, seinfo, uid, flags) < 0) { - ALOGE("restorecon failed for %s: %s\n", pkgdir, strerror(errno)); + if (selinux_android_restorecon_pkgdir(pkgdir.c_str(), seinfo, s.st_uid, flags) < 0) { + PLOG(ERROR) << "restorecon failed for " << pkgdir; ret |= -1; } - free(pkgdir); } closedir(d); - free(primarydir); - free(userdir); return ret; } +int create_oat_dir(const char* oat_dir, const char* instruction_set) +{ + char oat_instr_dir[PKG_PATH_MAX]; + + if (validate_apk_path(oat_dir)) { + ALOGE("invalid apk path '%s' (bad prefix)\n", oat_dir); + return -1; + } + if (fs_prepare_dir(oat_dir, S_IRWXU | S_IRWXG | S_IXOTH, AID_SYSTEM, AID_INSTALL)) { + return -1; + } + if (selinux_android_restorecon(oat_dir, 0)) { + ALOGE("cannot restorecon dir '%s': %s\n", oat_dir, strerror(errno)); + return -1; + } + snprintf(oat_instr_dir, PKG_PATH_MAX, "%s/%s", oat_dir, instruction_set); + if (fs_prepare_dir(oat_instr_dir, S_IRWXU | S_IRWXG | S_IXOTH, AID_SYSTEM, AID_INSTALL)) { + return -1; + } + return 0; +} + +int rm_package_dir(const char* apk_path) +{ + if (validate_apk_path(apk_path)) { + ALOGE("invalid apk path '%s' (bad prefix)\n", apk_path); + return -1; + } + return delete_dir_contents(apk_path, 1 /* also_delete_dir */ , NULL /* exclusion_predicate */); +} + +int link_file(const char* relative_path, const char* from_base, const char* to_base) { + char from_path[PKG_PATH_MAX]; + char to_path[PKG_PATH_MAX]; + snprintf(from_path, PKG_PATH_MAX, "%s/%s", from_base, relative_path); + snprintf(to_path, PKG_PATH_MAX, "%s/%s", to_base, relative_path); + + if (validate_apk_path_subdirs(from_path)) { + ALOGE("invalid app data sub-path '%s' (bad prefix)\n", from_path); + return -1; + } + + if (validate_apk_path_subdirs(to_path)) { + ALOGE("invalid app data sub-path '%s' (bad prefix)\n", to_path); + return -1; + } + + const int ret = link(from_path, to_path); + if (ret < 0) { + ALOGE("link(%s, %s) failed : %s", from_path, to_path, strerror(errno)); + return -1; + } + + return 0; +} + +int calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path, + const char *instruction_set) { + char *file_name_start; + char *file_name_end; + + file_name_start = strrchr(apk_path, '/'); + if (file_name_start == NULL) { + ALOGE("apk_path '%s' has no '/'s in it\n", apk_path); + return -1; + } + file_name_end = strrchr(apk_path, '.'); + if (file_name_end < file_name_start) { + ALOGE("apk_path '%s' has no extension\n", apk_path); + return -1; + } + + // Calculate file_name + int file_name_len = file_name_end - file_name_start - 1; + char file_name[file_name_len + 1]; + memcpy(file_name, file_name_start + 1, file_name_len); + file_name[file_name_len] = '\0'; + + // <apk_parent_dir>/oat/<isa>/<file_name>.odex + snprintf(path, PKG_PATH_MAX, "%s/%s/%s.odex", oat_dir, instruction_set, file_name); + return 0; +} diff --git a/cmds/installd/installd.c b/cmds/installd/installd.cpp index 5b8a1e35e2..13e3168686 100644 --- a/cmds/installd/installd.c +++ b/cmds/installd/installd.cpp @@ -1,90 +1,101 @@ /* ** Copyright 2008, 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 +** 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 +** 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 +** 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 "installd.h" + +#include <base/logging.h> + #include <sys/capability.h> #include <sys/prctl.h> #include <selinux/android.h> #include <selinux/avc.h> -#include "installd.h" - - #define BUFFER_MAX 1024 /* input buffer for commands */ -#define TOKEN_MAX 8 /* max number of arguments in buffer */ +#define TOKEN_MAX 16 /* max number of arguments in buffer */ #define REPLY_MAX 256 /* largest reply allowed */ -static int do_ping(char **arg, char reply[REPLY_MAX]) +static char* parse_null(char* arg) { + if (strcmp(arg, "!") == 0) { + return nullptr; + } else { + return arg; + } +} + +static int do_ping(char **arg __unused, char reply[REPLY_MAX] __unused) { return 0; } -static int do_install(char **arg, char reply[REPLY_MAX]) +static int do_install(char **arg, char reply[REPLY_MAX] __unused) { - return install(arg[0], atoi(arg[1]), atoi(arg[2]), arg[3]); /* pkgname, uid, gid, seinfo */ + return install(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]), arg[4]); /* uuid, pkgname, uid, gid, seinfo */ } -static int do_dexopt(char **arg, char reply[REPLY_MAX]) +static int do_dexopt(char **arg, char reply[REPLY_MAX] __unused) { - /* apk_path, uid, is_public, pkgname, instruction_set, vm_safe_mode, should_relocate */ - return dexopt(arg[0], atoi(arg[1]), atoi(arg[2]), arg[3], arg[4], atoi(arg[5]), 0); + /* apk_path, uid, is_public, pkgname, instruction_set, + * dexopt_needed, vm_safe_mode, debuggable, oat_dir */ + return dexopt(arg[0], atoi(arg[1]), atoi(arg[2]), arg[3], arg[4], atoi(arg[5]), + atoi(arg[6]), atoi(arg[7]), arg[8]); } -static int do_mark_boot_complete(char **arg, char reply[REPLY_MAX]) +static int do_mark_boot_complete(char **arg, char reply[REPLY_MAX] __unused) { return mark_boot_complete(arg[0] /* instruction set */); } -static int do_move_dex(char **arg, char reply[REPLY_MAX]) +static int do_move_dex(char **arg, char reply[REPLY_MAX] __unused) { return move_dex(arg[0], arg[1], arg[2]); /* src, dst, instruction_set */ } -static int do_rm_dex(char **arg, char reply[REPLY_MAX]) +static int do_rm_dex(char **arg, char reply[REPLY_MAX] __unused) { return rm_dex(arg[0], arg[1]); /* pkgname, instruction_set */ } -static int do_remove(char **arg, char reply[REPLY_MAX]) +static int do_remove(char **arg, char reply[REPLY_MAX] __unused) { - return uninstall(arg[0], atoi(arg[1])); /* pkgname, userid */ + return uninstall(parse_null(arg[0]), arg[1], atoi(arg[2])); /* uuid, pkgname, userid */ } -static int do_rename(char **arg, char reply[REPLY_MAX]) +static int do_rename(char **arg, char reply[REPLY_MAX] __unused) { return renamepkg(arg[0], arg[1]); /* oldpkgname, newpkgname */ } -static int do_fixuid(char **arg, char reply[REPLY_MAX]) +static int do_fixuid(char **arg, char reply[REPLY_MAX] __unused) { - return fix_uid(arg[0], atoi(arg[1]), atoi(arg[2])); /* pkgname, uid, gid */ + return fix_uid(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3])); /* uuid, pkgname, uid, gid */ } -static int do_free_cache(char **arg, char reply[REPLY_MAX]) /* TODO int:free_size */ +static int do_free_cache(char **arg, char reply[REPLY_MAX] __unused) /* TODO int:free_size */ { - return free_cache((int64_t)atoll(arg[0])); /* free_size */ + return free_cache(parse_null(arg[0]), (int64_t)atoll(arg[1])); /* uuid, free_size */ } -static int do_rm_cache(char **arg, char reply[REPLY_MAX]) +static int do_rm_cache(char **arg, char reply[REPLY_MAX] __unused) { - return delete_cache(arg[0], atoi(arg[1])); /* pkgname, userid */ + return delete_cache(parse_null(arg[0]), arg[1], atoi(arg[2])); /* uuid, pkgname, userid */ } -static int do_rm_code_cache(char **arg, char reply[REPLY_MAX]) +static int do_rm_code_cache(char **arg, char reply[REPLY_MAX] __unused) { - return delete_code_cache(arg[0], atoi(arg[1])); /* pkgname, userid */ + return delete_code_cache(parse_null(arg[0]), arg[1], atoi(arg[2])); /* uuid, pkgname, userid */ } static int do_get_size(char **arg, char reply[REPLY_MAX]) @@ -95,9 +106,9 @@ static int do_get_size(char **arg, char reply[REPLY_MAX]) int64_t asecsize = 0; int res = 0; - /* pkgdir, userid, apkpath */ - res = get_size(arg[0], atoi(arg[1]), arg[2], arg[3], arg[4], arg[5], - arg[6], &codesize, &datasize, &cachesize, &asecsize); + /* uuid, pkgdir, userid, apkpath */ + res = get_size(parse_null(arg[0]), arg[1], atoi(arg[2]), arg[3], arg[4], arg[5], arg[6], + arg[7], &codesize, &datasize, &cachesize, &asecsize); /* * Each int64_t can take up 22 characters printed out. Make sure it @@ -108,51 +119,70 @@ static int do_get_size(char **arg, char reply[REPLY_MAX]) return res; } -static int do_rm_user_data(char **arg, char reply[REPLY_MAX]) +static int do_rm_user_data(char **arg, char reply[REPLY_MAX] __unused) { - return delete_user_data(arg[0], atoi(arg[1])); /* pkgname, userid */ + return delete_user_data(parse_null(arg[0]), arg[1], atoi(arg[2])); /* uuid, pkgname, userid */ } -static int do_mk_user_data(char **arg, char reply[REPLY_MAX]) +static int do_cp_complete_app(char **arg, char reply[REPLY_MAX] __unused) { - return make_user_data(arg[0], atoi(arg[1]), atoi(arg[2]), arg[3]); - /* pkgname, uid, userid, seinfo */ + // from_uuid, to_uuid, package_name, data_app_name, appid, seinfo + return copy_complete_app(parse_null(arg[0]), parse_null(arg[1]), arg[2], arg[3], atoi(arg[4]), arg[5]); } -static int do_mk_user_config(char **arg, char reply[REPLY_MAX]) +static int do_mk_user_data(char **arg, char reply[REPLY_MAX] __unused) +{ + return make_user_data(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]), arg[4]); + /* uuid, pkgname, uid, userid, seinfo */ +} + +static int do_mk_user_config(char **arg, char reply[REPLY_MAX] __unused) { return make_user_config(atoi(arg[0])); /* userid */ } -static int do_rm_user(char **arg, char reply[REPLY_MAX]) +static int do_rm_user(char **arg, char reply[REPLY_MAX] __unused) { - return delete_user(atoi(arg[0])); /* userid */ + return delete_user(parse_null(arg[0]), atoi(arg[1])); /* uuid, userid */ } -static int do_movefiles(char **arg, char reply[REPLY_MAX]) +static int do_movefiles(char **arg __unused, char reply[REPLY_MAX] __unused) { return movefiles(); } -static int do_linklib(char **arg, char reply[REPLY_MAX]) +static int do_linklib(char **arg, char reply[REPLY_MAX] __unused) { - return linklib(arg[0], arg[1], atoi(arg[2])); + return linklib(parse_null(arg[0]), arg[1], arg[2], atoi(arg[3])); } -static int do_idmap(char **arg, char reply[REPLY_MAX]) +static int do_idmap(char **arg, char reply[REPLY_MAX] __unused) { return idmap(arg[0], arg[1], atoi(arg[2])); } static int do_restorecon_data(char **arg, char reply[REPLY_MAX] __attribute__((unused))) { - return restorecon_data(arg[0], arg[1], atoi(arg[2])); - /* pkgName, seinfo, uid*/ + return restorecon_data(parse_null(arg[0]), arg[1], arg[2], atoi(arg[3])); + /* uuid, pkgName, seinfo, uid*/ +} + +static int do_create_oat_dir(char **arg, char reply[REPLY_MAX] __unused) +{ + /* oat_dir, instruction_set */ + return create_oat_dir(arg[0], arg[1]); } -static int do_patchoat(char **arg, char reply[REPLY_MAX]) { - /* apk_path, uid, is_public, pkgname, instruction_set, vm_safe_mode, should_relocate */ - return dexopt(arg[0], atoi(arg[1]), atoi(arg[2]), arg[3], arg[4], 0, 1); +static int do_rm_package_dir(char **arg, char reply[REPLY_MAX] __unused) +{ + /* oat_dir */ + return rm_package_dir(arg[0]); +} + +static int do_link_file(char **arg, char reply[REPLY_MAX] __unused) +{ + /* relative_path, from_base, to_base */ + return link_file(arg[0], arg[1], arg[2]); } struct cmdinfo { @@ -163,32 +193,35 @@ struct cmdinfo { struct cmdinfo cmds[] = { { "ping", 0, do_ping }, - { "install", 4, do_install }, - { "dexopt", 6, do_dexopt }, + { "install", 5, do_install }, + { "dexopt", 9, do_dexopt }, { "markbootcomplete", 1, do_mark_boot_complete }, { "movedex", 3, do_move_dex }, { "rmdex", 2, do_rm_dex }, - { "remove", 2, do_remove }, + { "remove", 3, do_remove }, { "rename", 2, do_rename }, - { "fixuid", 3, do_fixuid }, - { "freecache", 1, do_free_cache }, - { "rmcache", 2, do_rm_cache }, - { "rmcodecache", 2, do_rm_code_cache }, - { "getsize", 7, do_get_size }, - { "rmuserdata", 2, do_rm_user_data }, + { "fixuid", 4, do_fixuid }, + { "freecache", 2, do_free_cache }, + { "rmcache", 3, do_rm_cache }, + { "rmcodecache", 3, do_rm_code_cache }, + { "getsize", 8, do_get_size }, + { "rmuserdata", 3, do_rm_user_data }, + { "cpcompleteapp", 6, do_cp_complete_app }, { "movefiles", 0, do_movefiles }, - { "linklib", 3, do_linklib }, - { "mkuserdata", 4, do_mk_user_data }, + { "linklib", 4, do_linklib }, + { "mkuserdata", 5, do_mk_user_data }, { "mkuserconfig", 1, do_mk_user_config }, - { "rmuser", 1, do_rm_user }, + { "rmuser", 2, do_rm_user }, { "idmap", 3, do_idmap }, - { "restorecondata", 3, do_restorecon_data }, - { "patchoat", 5, do_patchoat }, + { "restorecondata", 4, do_restorecon_data }, + { "createoatdir", 2, do_create_oat_dir }, + { "rmpackagedir", 1, do_rm_package_dir }, + { "linkfile", 3, do_link_file } }; static int readx(int s, void *_buf, int count) { - char *buf = _buf; + char *buf = (char *) _buf; int n = 0, r; if (count < 0) return -1; while (n < count) { @@ -209,7 +242,7 @@ static int readx(int s, void *_buf, int count) static int writex(int s, const void *_buf, int count) { - const char *buf = _buf; + const char *buf = (const char *) _buf; int n = 0, r; if (count < 0) return -1; while (n < count) { @@ -255,7 +288,9 @@ static int execute(int s, char cmd[BUFFER_MAX]) goto done; } } - cmd++; + if (*cmd) { + cmd++; + } } for (i = 0; i < sizeof(cmds) / sizeof(cmds[0]); i++) { @@ -333,10 +368,15 @@ int initialize_globals() { return -1; } + // Get the android external app directory. + if (get_path_from_string(&android_mnt_expand_dir, "/mnt/expand/") < 0) { + return -1; + } + // Take note of the system and vendor directories. android_system_dirs.count = 4; - android_system_dirs.dirs = calloc(android_system_dirs.count, sizeof(dir_rec_t)); + android_system_dirs.dirs = (dir_rec_t*) calloc(android_system_dirs.count, sizeof(dir_rec_t)); if (android_system_dirs.dirs == NULL) { ALOGE("Couldn't allocate array for dirs; aborting\n"); return -1; @@ -354,10 +394,10 @@ int initialize_globals() { android_system_dirs.dirs[1].path = build_string2(android_root_dir.path, PRIV_APP_SUBDIR); android_system_dirs.dirs[1].len = strlen(android_system_dirs.dirs[1].path); - android_system_dirs.dirs[2].path = "/vendor/app/"; + android_system_dirs.dirs[2].path = strdup("/vendor/app/"); android_system_dirs.dirs[2].len = strlen(android_system_dirs.dirs[2].path); - android_system_dirs.dirs[3].path = "/oem/app/"; + android_system_dirs.dirs[3].path = strdup("/oem/app/"); android_system_dirs.dirs[3].len = strlen(android_system_dirs.dirs[3].path); return 0; @@ -501,7 +541,7 @@ int initialize_directories() { version = 2; } - if (ensure_media_user_dirs(0) == -1) { + if (ensure_media_user_dirs(nullptr, 0) == -1) { ALOGE("Failed to setup media for user 0"); goto fail; } @@ -596,46 +636,6 @@ fail: return res; } -static void drop_privileges() { - if (prctl(PR_SET_KEEPCAPS, 1) < 0) { - ALOGE("prctl(PR_SET_KEEPCAPS) failed: %s\n", strerror(errno)); - exit(1); - } - - if (setgid(AID_INSTALL) < 0) { - ALOGE("setgid() can't drop privileges; exiting.\n"); - exit(1); - } - - if (setuid(AID_INSTALL) < 0) { - ALOGE("setuid() can't drop privileges; exiting.\n"); - exit(1); - } - - struct __user_cap_header_struct capheader; - struct __user_cap_data_struct capdata[2]; - memset(&capheader, 0, sizeof(capheader)); - memset(&capdata, 0, sizeof(capdata)); - capheader.version = _LINUX_CAPABILITY_VERSION_3; - capheader.pid = 0; - - capdata[CAP_TO_INDEX(CAP_DAC_OVERRIDE)].permitted |= CAP_TO_MASK(CAP_DAC_OVERRIDE); - capdata[CAP_TO_INDEX(CAP_CHOWN)].permitted |= CAP_TO_MASK(CAP_CHOWN); - capdata[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID); - capdata[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID); - capdata[CAP_TO_INDEX(CAP_FOWNER)].permitted |= CAP_TO_MASK(CAP_FOWNER); - - capdata[0].effective = capdata[0].permitted; - capdata[1].effective = capdata[1].permitted; - capdata[0].inheritable = 0; - capdata[1].inheritable = 0; - - if (capset(&capheader, &capdata[0]) < 0) { - ALOGE("capset failed: %s\n", strerror(errno)); - exit(1); - } -} - static int log_callback(int type, const char *fmt, ...) { va_list ap; int priority; @@ -657,13 +657,16 @@ static int log_callback(int type, const char *fmt, ...) { return 0; } -int main(const int argc, const char *argv[]) { +int main(const int argc __unused, char *argv[]) { char buf[BUFFER_MAX]; struct sockaddr addr; socklen_t alen; - int lsocket, s, count; + int lsocket, s; int selinux_enabled = (is_selinux_enabled() > 0); + setenv("ANDROID_LOG_TAGS", "*:v", 1); + android::base::InitLogging(argv); + ALOGI("installd firing up\n"); union selinux_callback cb; @@ -685,8 +688,6 @@ int main(const int argc, const char *argv[]) { exit(1); } - drop_privileges(); - lsocket = android_get_control_socket(SOCKET_PATH); if (lsocket < 0) { ALOGE("Failed to get socket from environment: %s\n", strerror(errno)); diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h index a3a5c1628e..7ec5793827 100644 --- a/cmds/installd/installd.h +++ b/cmds/installd/installd.h @@ -31,6 +31,8 @@ #include <sys/socket.h> #include <sys/types.h> #include <sys/wait.h> +#include <string> +#include <vector> #include <cutils/fs.h> #include <cutils/sockets.h> @@ -40,7 +42,7 @@ #include <private/android_filesystem_config.h> -#if INCLUDE_SYS_MOUNT_FOR_STATFS +#if defined(__APPLE__) #include <sys/mount.h> #else #include <sys/statfs.h> @@ -83,6 +85,13 @@ #define PKG_NAME_MAX 128 /* largest allowed package name */ #define PKG_PATH_MAX 256 /* max size of any path we use */ +/* dexopt needed flags matching those in dalvik.system.DexFile */ +#define DEXOPT_DEX2OAT_NEEDED 1 +#define DEXOPT_PATCHOAT_NEEDED 2 +#define DEXOPT_SELF_PATCHOAT_NEEDED 3 + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) + /* data structures */ typedef struct { @@ -101,6 +110,7 @@ extern dir_rec_t android_app_lib_dir; extern dir_rec_t android_data_dir; extern dir_rec_t android_asec_dir; extern dir_rec_t android_media_dir; +extern dir_rec_t android_mnt_expand_dir; extern dir_rec_array_t android_system_dirs; typedef struct cache_dir_struct { @@ -132,20 +142,25 @@ typedef struct { /* util.c */ -int create_pkg_path_in_dir(char path[PKG_PATH_MAX], - const dir_rec_t* dir, - const char* pkgname, - const char* postfix); - int create_pkg_path(char path[PKG_PATH_MAX], const char *pkgname, const char *postfix, userid_t userid); -int create_user_path(char path[PKG_PATH_MAX], - userid_t userid); +std::string create_data_path(const char* volume_uuid); + +std::string create_data_app_path(const char* volume_uuid); + +std::string create_data_app_package_path(const char* volume_uuid, const char* package_name); + +std::string create_data_user_path(const char* volume_uuid, userid_t userid); + +std::string create_data_user_package_path(const char* volume_uuid, + userid_t user, const char* package_name); + +std::string create_data_media_path(const char* volume_uuid, userid_t userid); -int create_user_media_path(char path[PKG_PATH_MAX], userid_t userid); +std::vector<userid_t> get_known_users(const char* volume_uuid); int create_user_config_path(char path[PKG_PATH_MAX], userid_t userid); @@ -169,13 +184,13 @@ int copy_dir_files(const char *srcname, const char *dstname, uid_t owner, gid_t int lookup_media_dir(char basepath[PATH_MAX], const char *dir); -int64_t data_disk_free(); +int64_t data_disk_free(const std::string& data_path); cache_t* start_cache_collection(); void add_cache_files(cache_t* cache, const char *basepath, const char *cachedir); -void clear_cache_files(cache_t* cache, int64_t free_size); +void clear_cache_files(const std::string& data_path, cache_t* cache, int64_t free_size); void finish_cache_collection(cache_t* cache); @@ -188,41 +203,56 @@ int get_path_from_string(dir_rec_t* rec, const char* path); int copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix); int validate_apk_path(const char *path); +int validate_apk_path_subdirs(const char *path); int append_and_increment(char** dst, const char* src, size_t* dst_size); -char *build_string2(char *s1, char *s2); -char *build_string3(char *s1, char *s2, char *s3); +char *build_string2(const char *s1, const char *s2); +char *build_string3(const char *s1, const char *s2, const char *s3); int ensure_dir(const char* path, mode_t mode, uid_t uid, gid_t gid); -int ensure_media_user_dirs(userid_t userid); +int ensure_media_user_dirs(const char* uuid, userid_t userid); int ensure_config_user_dirs(userid_t userid); int create_profile_file(const char *pkgname, gid_t gid); void remove_profile_file(const char *pkgname); /* commands.c */ -int install(const char *pkgname, uid_t uid, gid_t gid, const char *seinfo); -int uninstall(const char *pkgname, userid_t userid); +int install(const char *uuid, const char *pkgname, uid_t uid, gid_t gid, const char *seinfo); +int uninstall(const char *uuid, const char *pkgname, userid_t userid); int renamepkg(const char *oldpkgname, const char *newpkgname); -int fix_uid(const char *pkgname, uid_t uid, gid_t gid); -int delete_user_data(const char *pkgname, userid_t userid); -int make_user_data(const char *pkgname, uid_t uid, userid_t userid, const char* seinfo); +int fix_uid(const char *uuid, const char *pkgname, uid_t uid, gid_t gid); +int delete_user_data(const char *uuid, const char *pkgname, userid_t userid); +int make_user_data(const char *uuid, const char *pkgname, uid_t uid, + userid_t userid, const char* seinfo); +int copy_complete_app(const char* from_uuid, const char *to_uuid, + const char *package_name, const char *data_app_name, appid_t appid, + const char* seinfo); int make_user_config(userid_t userid); -int delete_user(userid_t userid); -int delete_cache(const char *pkgname, userid_t userid); -int delete_code_cache(const char *pkgname, userid_t userid); +int delete_user(const char *uuid, userid_t userid); +int delete_cache(const char *uuid, const char *pkgname, userid_t userid); +int delete_code_cache(const char *uuid, const char *pkgname, userid_t userid); int move_dex(const char *src, const char *dst, const char *instruction_set); int rm_dex(const char *path, const char *instruction_set); int protect(char *pkgname, gid_t gid); -int get_size(const char *pkgname, userid_t userid, const char *apkpath, const char *libdirpath, - const char *fwdlock_apkpath, const char *asecpath, const char *instruction_set, - int64_t *codesize, int64_t *datasize, int64_t *cachesize, int64_t *asecsize); -int free_cache(int64_t free_size); +int get_size(const char *uuid, const char *pkgname, int userid, + const char *apkpath, const char *libdirpath, + const char *fwdlock_apkpath, const char *asecpath, + const char *instruction_set, int64_t *codesize, int64_t *datasize, + int64_t *cachesize, int64_t *asecsize); +int free_cache(const char *uuid, int64_t free_size); int dexopt(const char *apk_path, uid_t uid, bool is_public, const char *pkgName, - const char *instruction_set, bool vm_safe_mode, bool should_relocate); + const char *instruction_set, int dexopt_needed, bool vm_safe_mode, + bool debuggable, const char* oat_dir); int mark_boot_complete(const char *instruction_set); int movefiles(); -int linklib(const char* target, const char* source, int userId); +int linklib(const char* uuid, const char* pkgname, const char* asecLibDir, int userId); int idmap(const char *target_path, const char *overlay_path, uid_t uid); -int restorecon_data(); +int restorecon_data(const char *uuid, const char* pkgName, const char* seinfo, uid_t uid); +int create_oat_dir(const char* oat_dir, const char *instruction_set); +int rm_package_dir(const char* apk_path); +int calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path, + const char *instruction_set); +int move_package_dir(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path, + const char *instruction_set); +int link_file(const char *relative_path, const char *from_base, const char *to_base); diff --git a/cmds/installd/tests/Android.mk b/cmds/installd/tests/Android.mk index 4faf3c069a..38a9f69964 100644 --- a/cmds/installd/tests/Android.mk +++ b/cmds/installd/tests/Android.mk @@ -1,21 +1,20 @@ # Build the unit tests for installd LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk # Build the unit tests. test_src_files := \ installd_utils_test.cpp shared_libraries := \ + libbase \ libutils \ libcutils \ - libstlport static_libraries := \ libinstalld \ libdiskusage \ - libgtest \ - libgtest_main c_includes := \ frameworks/native/cmds/installd @@ -27,5 +26,6 @@ $(foreach file,$(test_src_files), \ $(eval LOCAL_SRC_FILES := $(file)) \ $(eval LOCAL_C_INCLUDES := $(c_includes)) \ $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \ + $(eval LOCAL_CLANG := true) \ $(eval include $(BUILD_NATIVE_TEST)) \ ) diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp index 94e4792826..5e397f9f4b 100644 --- a/cmds/installd/tests/installd_utils_test.cpp +++ b/cmds/installd/tests/installd_utils_test.cpp @@ -17,19 +17,18 @@ #include <stdlib.h> #include <string.h> -#define LOG_TAG "utils_test" -#include <utils/Log.h> - #include <gtest/gtest.h> -extern "C" { #include "installd.h" -} + +#undef LOG_TAG +#define LOG_TAG "utils_test" #define TEST_DATA_DIR "/data/" #define TEST_APP_DIR "/data/app/" #define TEST_APP_PRIVATE_DIR "/data/app-private/" #define TEST_ASEC_DIR "/mnt/asec/" +#define TEST_EXPAND_DIR "/mnt/expand/" #define TEST_SYSTEM_DIR1 "/system/app/" #define TEST_SYSTEM_DIR2 "/vendor/app/" @@ -49,25 +48,28 @@ namespace android { class UtilsTest : public testing::Test { protected: virtual void SetUp() { - android_app_dir.path = TEST_APP_DIR; + android_app_dir.path = (char*) TEST_APP_DIR; android_app_dir.len = strlen(TEST_APP_DIR); - android_app_private_dir.path = TEST_APP_PRIVATE_DIR; + android_app_private_dir.path = (char*) TEST_APP_PRIVATE_DIR; android_app_private_dir.len = strlen(TEST_APP_PRIVATE_DIR); - android_data_dir.path = TEST_DATA_DIR; + android_data_dir.path = (char*) TEST_DATA_DIR; android_data_dir.len = strlen(TEST_DATA_DIR); - android_asec_dir.path = TEST_ASEC_DIR; + android_asec_dir.path = (char*) TEST_ASEC_DIR; android_asec_dir.len = strlen(TEST_ASEC_DIR); + android_mnt_expand_dir.path = (char*) TEST_EXPAND_DIR; + android_mnt_expand_dir.len = strlen(TEST_EXPAND_DIR); + android_system_dirs.count = 2; android_system_dirs.dirs = (dir_rec_t*) calloc(android_system_dirs.count, sizeof(dir_rec_t)); - android_system_dirs.dirs[0].path = TEST_SYSTEM_DIR1; + android_system_dirs.dirs[0].path = (char*) TEST_SYSTEM_DIR1; android_system_dirs.dirs[0].len = strlen(TEST_SYSTEM_DIR1); - android_system_dirs.dirs[1].path = TEST_SYSTEM_DIR2; + android_system_dirs.dirs[1].path = (char*) TEST_SYSTEM_DIR2; android_system_dirs.dirs[1].len = strlen(TEST_SYSTEM_DIR2); } @@ -319,6 +321,7 @@ TEST_F(UtilsTest, CreatePkgPath_LongPkgNameSuccess) { const char *prefix = TEST_DATA_DIR PRIMARY_USER_PREFIX; size_t offset = strlen(prefix); + EXPECT_STREQ(pkgname, path + offset) << "Package path should be a really long string of a's"; } @@ -369,40 +372,6 @@ TEST_F(UtilsTest, CreatePkgPath_SecondaryUser) { << "Package path should be in /data/user/"; } -TEST_F(UtilsTest, CreatePkgPathInDir_ProtectedDir) { - char path[PKG_PATH_MAX]; - - dir_rec_t dir; - dir.path = "/data/app-private/"; - dir.len = strlen(dir.path); - - EXPECT_EQ(0, create_pkg_path_in_dir(path, &dir, "com.example.package", ".apk")) - << "Should successfully create package path."; - - EXPECT_STREQ("/data/app-private/com.example.package.apk", path) - << "Package path should be in /data/app-private/"; -} - -TEST_F(UtilsTest, CreatePersonaPath_Primary) { - char path[PKG_PATH_MAX]; - - EXPECT_EQ(0, create_user_path(path, 0)) - << "Should successfully build primary user path."; - - EXPECT_STREQ("/data/data/", path) - << "Primary user should have correct path"; -} - -TEST_F(UtilsTest, CreatePersonaPath_Secondary) { - char path[PKG_PATH_MAX]; - - EXPECT_EQ(0, create_user_path(path, 1)) - << "Should successfully build primary user path."; - - EXPECT_STREQ("/data/user/1/", path) - << "Primary user should have correct path"; -} - TEST_F(UtilsTest, CreateMovePath_Primary) { char path[PKG_PATH_MAX]; @@ -432,7 +401,7 @@ TEST_F(UtilsTest, CopyAndAppend_Normal) { dir_rec_t dst; dir_rec_t src; - src.path = "/data/"; + src.path = (char*) "/data/"; src.len = strlen(src.path); EXPECT_EQ(0, copy_and_append(&dst, &src, "app/")) @@ -480,4 +449,54 @@ TEST_F(UtilsTest, AppendAndIncrement_TooBig) { << "String should fail because it's too large to fit"; } +TEST_F(UtilsTest, CreateDataPath) { + EXPECT_EQ("/data", create_data_path(nullptr)); + EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b", + create_data_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b")); +} + +TEST_F(UtilsTest, CreateDataAppPath) { + EXPECT_EQ("/data/app", create_data_app_path(nullptr)); + + EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/app", + create_data_app_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b")); +} + +TEST_F(UtilsTest, CreateDataUserPath) { + EXPECT_EQ("/data/data", create_data_user_path(nullptr, 0)); + EXPECT_EQ("/data/user/10", create_data_user_path(nullptr, 10)); + + EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/user/0", + create_data_user_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0)); + EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/user/10", + create_data_user_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 10)); +} + +TEST_F(UtilsTest, CreateDataMediaPath) { + EXPECT_EQ("/data/media/0", create_data_media_path(nullptr, 0)); + EXPECT_EQ("/data/media/10", create_data_media_path(nullptr, 10)); + + EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/media/0", + create_data_media_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0)); + EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/media/10", + create_data_media_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 10)); +} + +TEST_F(UtilsTest, CreateDataAppPackagePath) { + EXPECT_EQ("/data/app/com.example", create_data_app_package_path(nullptr, "com.example")); + + EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/app/com.example", + create_data_app_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", "com.example")); +} + +TEST_F(UtilsTest, CreateDataUserPackagePath) { + EXPECT_EQ("/data/data/com.example", create_data_user_package_path(nullptr, 0, "com.example")); + EXPECT_EQ("/data/user/10/com.example", create_data_user_package_path(nullptr, 10, "com.example")); + + EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/user/0/com.example", + create_data_user_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, "com.example")); + EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/user/10/com.example", + create_data_user_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 10, "com.example")); +} + } diff --git a/cmds/installd/utils.c b/cmds/installd/utils.cpp index e381aefe11..7db3fb90c9 100644 --- a/cmds/installd/utils.c +++ b/cmds/installd/utils.cpp @@ -16,137 +16,141 @@ #include "installd.h" -#define CACHE_NOISY(x) //x - -int create_pkg_path_in_dir(char path[PKG_PATH_MAX], - const dir_rec_t* dir, - const char* pkgname, - const char* postfix) -{ - const size_t postfix_len = strlen(postfix); +#include <base/stringprintf.h> +#include <base/logging.h> - const size_t pkgname_len = strlen(pkgname); - if (pkgname_len > PKG_NAME_MAX) { - return -1; - } - - if (is_valid_package_name(pkgname) < 0) { - return -1; - } +#define CACHE_NOISY(x) //x - if ((pkgname_len + dir->len + postfix_len) >= PKG_PATH_MAX) { - return -1; - } +using android::base::StringPrintf; - char *dst = path; - size_t dst_size = PKG_PATH_MAX; +/** + * Check that given string is valid filename, and that it attempts no + * parent or child directory traversal. + */ +static bool is_valid_filename(const std::string& name) { + if (name.empty() || (name == ".") || (name == "..") + || (name.find('/') != std::string::npos)) { + return false; + } else { + return true; + } +} - if (append_and_increment(&dst, dir->path, &dst_size) < 0 - || append_and_increment(&dst, pkgname, &dst_size) < 0 - || append_and_increment(&dst, postfix, &dst_size) < 0) { - ALOGE("Error building APK path"); - return -1; - } +/** + * Create the path name where package app contents should be stored for + * the given volume UUID and package name. An empty UUID is assumed to + * be internal storage. + */ +std::string create_data_app_package_path(const char* volume_uuid, + const char* package_name) { + CHECK(is_valid_filename(package_name)); + CHECK(is_valid_package_name(package_name) == 0); - return 0; + return StringPrintf("%s/%s", + create_data_app_path(volume_uuid).c_str(), package_name); } /** - * Create the package path name for a given package name with a postfix for - * a certain userid. Returns 0 on success, and -1 on failure. + * Create the path name where package data should be stored for the given + * volume UUID, package name, and user ID. An empty UUID is assumed to be + * internal storage. */ -int create_pkg_path(char path[PKG_PATH_MAX], - const char *pkgname, - const char *postfix, - userid_t userid) -{ - size_t userid_len; - char* userid_prefix; - if (userid == 0) { - userid_prefix = PRIMARY_USER_PREFIX; - userid_len = 0; - } else { - userid_prefix = SECONDARY_USER_PREFIX; - userid_len = snprintf(NULL, 0, "%d", userid); - } +std::string create_data_user_package_path(const char* volume_uuid, + userid_t user, const char* package_name) { + CHECK(is_valid_filename(package_name)); + CHECK(is_valid_package_name(package_name) == 0); - const size_t prefix_len = android_data_dir.len + strlen(userid_prefix) - + userid_len + 1 /*slash*/; - char prefix[prefix_len + 1]; - - char *dst = prefix; - size_t dst_size = sizeof(prefix); + return StringPrintf("%s/%s", + create_data_user_path(volume_uuid, user).c_str(), package_name); +} - if (append_and_increment(&dst, android_data_dir.path, &dst_size) < 0 - || append_and_increment(&dst, userid_prefix, &dst_size) < 0) { - ALOGE("Error building prefix for APK path"); +int create_pkg_path(char path[PKG_PATH_MAX], const char *pkgname, + const char *postfix, userid_t userid) { + if (is_valid_package_name(pkgname) != 0) { + path[0] = '\0'; return -1; } - if (userid != 0) { - int ret = snprintf(dst, dst_size, "%d/", userid); - if (ret < 0 || (size_t) ret != userid_len + 1) { - ALOGW("Error appending UID to APK path"); - return -1; - } + std::string _tmp(create_data_user_package_path(nullptr, userid, pkgname) + postfix); + const char* tmp = _tmp.c_str(); + if (strlen(tmp) >= PKG_PATH_MAX) { + path[0] = '\0'; + return -1; + } else { + strcpy(path, tmp); + return 0; } +} - dir_rec_t dir; - dir.path = prefix; - dir.len = prefix_len; +std::string create_data_path(const char* volume_uuid) { + if (volume_uuid == nullptr) { + return "/data"; + } else { + CHECK(is_valid_filename(volume_uuid)); + return StringPrintf("/mnt/expand/%s", volume_uuid); + } +} - return create_pkg_path_in_dir(path, &dir, pkgname, postfix); +/** + * Create the path name for app data. + */ +std::string create_data_app_path(const char* volume_uuid) { + return StringPrintf("%s/app", create_data_path(volume_uuid).c_str()); } /** * Create the path name for user data for a certain userid. - * Returns 0 on success, and -1 on failure. */ -int create_user_path(char path[PKG_PATH_MAX], - userid_t userid) -{ - size_t userid_len; - char* userid_prefix; - if (userid == 0) { - userid_prefix = PRIMARY_USER_PREFIX; - userid_len = 0; +std::string create_data_user_path(const char* volume_uuid, userid_t userid) { + std::string data(create_data_path(volume_uuid)); + if (volume_uuid == nullptr) { + if (userid == 0) { + return StringPrintf("%s/data", data.c_str()); + } else { + return StringPrintf("%s/user/%u", data.c_str(), userid); + } } else { - userid_prefix = SECONDARY_USER_PREFIX; - userid_len = snprintf(NULL, 0, "%d/", userid); + return StringPrintf("%s/user/%u", data.c_str(), userid); } +} + +/** + * Create the path name for media for a certain userid. + */ +std::string create_data_media_path(const char* volume_uuid, userid_t userid) { + return StringPrintf("%s/media/%u", create_data_path(volume_uuid).c_str(), userid); +} - char *dst = path; - size_t dst_size = PKG_PATH_MAX; +std::vector<userid_t> get_known_users(const char* volume_uuid) { + std::vector<userid_t> users; - if (append_and_increment(&dst, android_data_dir.path, &dst_size) < 0 - || append_and_increment(&dst, userid_prefix, &dst_size) < 0) { - ALOGE("Error building prefix for user path"); - return -1; + // We always have an owner + users.push_back(0); + + std::string path(create_data_path(volume_uuid) + "/" + SECONDARY_USER_PREFIX); + DIR* dir = opendir(path.c_str()); + if (dir == NULL) { + // Unable to discover other users, but at least return owner + PLOG(ERROR) << "Failed to opendir " << path; + return users; } - if (userid != 0) { - if (dst_size < userid_len + 1) { - ALOGE("Error building user path"); - return -1; + struct dirent* ent; + while ((ent = readdir(dir))) { + if (ent->d_type != DT_DIR) { + continue; } - int ret = snprintf(dst, dst_size, "%d/", userid); - if (ret < 0 || (size_t) ret != userid_len) { - ALOGE("Error appending userid to path"); - return -1; + + char* end; + userid_t user = strtol(ent->d_name, &end, 10); + if (*end == '\0' && user != 0) { + LOG(DEBUG) << "Found valid user " << user; + users.push_back(user); } } - return 0; -} + closedir(dir); -/** - * Create the path name for media for a certain userid. - * Returns 0 on success, and -1 on failure. - */ -int create_user_media_path(char path[PATH_MAX], userid_t userid) { - if (snprintf(path, PATH_MAX, "%s%d", android_media_dir.path, userid) > PATH_MAX) { - return -1; - } - return 0; + return users; } /** @@ -163,7 +167,7 @@ int create_user_config_path(char path[PATH_MAX], userid_t userid) { int create_move_path(char path[PKG_PATH_MAX], const char* pkgname, const char* leaf, - userid_t userid) + userid_t userid __unused) { if ((android_data_dir.len + strlen(PRIMARY_USER_PREFIX) + strlen(pkgname) + strlen(leaf) + 1) >= PKG_PATH_MAX) { @@ -182,6 +186,10 @@ int is_valid_package_name(const char* pkgname) { const char *x = pkgname; int alpha = -1; + if (strlen(pkgname) > PKG_NAME_MAX) { + return -1; + } + while (*x) { if (isalnum(*x) || (*x == '_')) { /* alphanumeric or underscore are fine */ @@ -239,7 +247,7 @@ static int _delete_dir_contents(DIR *d, } if (de->d_type == DT_DIR) { - int r, subfd; + int subfd; DIR *subdir; /* always skip "." and ".." */ @@ -472,13 +480,13 @@ int lookup_media_dir(char basepath[PATH_MAX], const char *dir) return -1; } -int64_t data_disk_free() +int64_t data_disk_free(const std::string& data_path) { struct statfs sfs; - if (statfs(android_data_dir.path, &sfs) == 0) { + if (statfs(data_path.c_str(), &sfs) == 0) { return sfs.f_bavail * sfs.f_bsize; } else { - ALOGE("Couldn't statfs %s: %s\n", android_data_dir.path, strerror(errno)); + PLOG(ERROR) << "Couldn't statfs " << data_path; return -1; } } @@ -516,7 +524,7 @@ static void* _cache_malloc(cache_t* cache, size_t len) int8_t* res = cache->curMemBlockAvail; int8_t* nextPos = res + len; if (cache->memBlocks == NULL || nextPos > cache->curMemBlockEnd) { - int8_t* newBlock = malloc(CACHE_BLOCK_SIZE); + int8_t* newBlock = (int8_t*) malloc(CACHE_BLOCK_SIZE); if (newBlock == NULL) { return NULL; } @@ -836,7 +844,7 @@ static int cache_modtime_sort(const void *lhsP, const void *rhsP) return lhs->modTime < rhs->modTime ? -1 : (lhs->modTime > rhs->modTime ? 1 : 0); } -void clear_cache_files(cache_t* cache, int64_t free_size) +void clear_cache_files(const std::string& data_path, cache_t* cache, int64_t free_size) { size_t i; int skip = 0; @@ -861,7 +869,7 @@ void clear_cache_files(cache_t* cache, int64_t free_size) for (i=0; i<cache->numFiles; i++) { skip++; if (skip > 10) { - if (data_disk_free() > free_size) { + if (data_disk_free(data_path) > free_size) { return; } skip = 0; @@ -881,7 +889,7 @@ void clear_cache_files(cache_t* cache, int64_t free_size) void finish_cache_collection(cache_t* cache) { - size_t i; + CACHE_NOISY(size_t i;) CACHE_NOISY(ALOGI("clear_cache_files: %d dirs, %d files\n", cache->numDirs, cache->numFiles)); CACHE_NOISY( @@ -910,14 +918,14 @@ void finish_cache_collection(cache_t* cache) * The path is allowed to have at most one subdirectory and no indirections * to top level directories (i.e. have ".."). */ -static int validate_path(const dir_rec_t* dir, const char* path) { +static int validate_path(const dir_rec_t* dir, const char* path, int maxSubdirs) { size_t dir_len = dir->len; const char* subdir = strchr(path + dir_len, '/'); // Only allow the path to have at most one subdirectory. if (subdir != NULL) { ++subdir; - if (strchr(subdir, '/') != NULL) { + if ((--maxSubdirs == 0) && strchr(subdir, '/') != NULL) { ALOGE("invalid apk path '%s' (subdir?)\n", path); return -1; } @@ -942,7 +950,7 @@ int validate_system_app_path(const char* path) { for (i = 0; i < android_system_dirs.count; i++) { const size_t dir_len = android_system_dirs.dirs[i].len; if (!strncmp(path, android_system_dirs.dirs[i].path, dir_len)) { - return validate_path(android_system_dirs.dirs + i, path); + return validate_path(android_system_dirs.dirs + i, path, 1); } } @@ -1000,7 +1008,7 @@ int get_path_from_string(dir_rec_t* rec, const char* path) { // Add space for slash and terminating null. size_t dst_size = path_len + 2; - rec->path = malloc(dst_size); + rec->path = (char*) malloc(dst_size); if (rec->path == NULL) { return -1; } @@ -1035,25 +1043,37 @@ int copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix) { } /** - * Check whether path points to a valid path for an APK file. Only one level of - * subdirectory names is allowed. Returns -1 when an invalid path is encountered - * and 0 when a valid path is encountered. + * Check whether path points to a valid path for an APK file. The path must + * begin with a whitelisted prefix path and must be no deeper than |maxSubdirs| within + * that path. Returns -1 when an invalid path is encountered and 0 when a valid path + * is encountered. */ -int validate_apk_path(const char *path) -{ +static int validate_apk_path_internal(const char *path, int maxSubdirs) { const dir_rec_t* dir = NULL; - if (!strncmp(path, android_app_dir.path, android_app_dir.len)) { dir = &android_app_dir; } else if (!strncmp(path, android_app_private_dir.path, android_app_private_dir.len)) { dir = &android_app_private_dir; } else if (!strncmp(path, android_asec_dir.path, android_asec_dir.len)) { dir = &android_asec_dir; + } else if (!strncmp(path, android_mnt_expand_dir.path, android_mnt_expand_dir.len)) { + dir = &android_mnt_expand_dir; + if (maxSubdirs < 2) { + maxSubdirs = 2; + } } else { return -1; } - return validate_path(dir, path); + return validate_path(dir, path, maxSubdirs); +} + +int validate_apk_path(const char* path) { + return validate_apk_path_internal(path, 1 /* maxSubdirs */); +} + +int validate_apk_path_subdirs(const char* path) { + return validate_apk_path_internal(path, 3 /* maxSubdirs */); } int append_and_increment(char** dst, const char* src, size_t* dst_size) { @@ -1066,13 +1086,13 @@ int append_and_increment(char** dst, const char* src, size_t* dst_size) { return 0; } -char *build_string2(char *s1, char *s2) { +char *build_string2(const char *s1, const char *s2) { if (s1 == NULL || s2 == NULL) return NULL; int len_s1 = strlen(s1); int len_s2 = strlen(s2); int len = len_s1 + len_s2 + 1; - char *result = malloc(len); + char *result = (char *) malloc(len); if (result == NULL) return NULL; strcpy(result, s1); @@ -1081,14 +1101,14 @@ char *build_string2(char *s1, char *s2) { return result; } -char *build_string3(char *s1, char *s2, char *s3) { +char *build_string3(const char *s1, const char *s2, const char *s3) { if (s1 == NULL || s2 == NULL || s3 == NULL) return NULL; int len_s1 = strlen(s1); int len_s2 = strlen(s2); int len_s3 = strlen(s3); int len = len_s1 + len_s2 + len_s3 + 1; - char *result = malloc(len); + char *result = (char *) malloc(len); if (result == NULL) return NULL; strcpy(result, s1); @@ -1099,13 +1119,9 @@ char *build_string3(char *s1, char *s2, char *s3) { } /* Ensure that /data/media directories are prepared for given user. */ -int ensure_media_user_dirs(userid_t userid) { - char media_user_path[PATH_MAX]; - char path[PATH_MAX]; - - // Ensure /data/media/<userid> exists - create_user_media_path(media_user_path, userid); - if (fs_prepare_dir(media_user_path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) { +int ensure_media_user_dirs(const char* uuid, userid_t userid) { + std::string media_user_path(create_data_media_path(uuid, userid)); + if (fs_prepare_dir(media_user_path.c_str(), 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) { return -1; } @@ -1114,7 +1130,6 @@ int ensure_media_user_dirs(userid_t userid) { int ensure_config_user_dirs(userid_t userid) { char config_user_path[PATH_MAX]; - char path[PATH_MAX]; // writable by system, readable by any app within the same user const int uid = multiuser_get_uid(userid, AID_SYSTEM); diff --git a/cmds/service/service.cpp b/cmds/service/service.cpp index 97fc47c544..428b87cd51 100644 --- a/cmds/service/service.cpp +++ b/cmds/service/service.cpp @@ -146,6 +146,15 @@ int main(int argc, char* const argv[]) break; } data.writeInt32(atoi(argv[optind++])); + } else if (strcmp(argv[optind], "i64") == 0) { + optind++; + if (optind >= argc) { + aerr << "service: no integer supplied for 'i64'" << endl; + wantsUsage = true; + result = 10; + break; + } + data.writeInt64(atoll(argv[optind++])); } else if (strcmp(argv[optind], "s16") == 0) { optind++; if (optind >= argc) { @@ -155,6 +164,24 @@ int main(int argc, char* const argv[]) break; } data.writeString16(String16(argv[optind++])); + } else if (strcmp(argv[optind], "f") == 0) { + optind++; + if (optind >= argc) { + aerr << "service: no number supplied for 'f'" << endl; + wantsUsage = true; + result = 10; + break; + } + data.writeFloat(atof(argv[optind++])); + } else if (strcmp(argv[optind], "d") == 0) { + optind++; + if (optind >= argc) { + aerr << "service: no number supplied for 'd'" << endl; + wantsUsage = true; + result = 10; + break; + } + data.writeDouble(atof(argv[optind++])); } else if (strcmp(argv[optind], "null") == 0) { optind++; data.writeStrongBinder(NULL); @@ -272,9 +299,12 @@ int main(int argc, char* const argv[]) aout << "Usage: service [-h|-?]\n" " service list\n" " service check SERVICE\n" - " service call SERVICE CODE [i32 INT | s16 STR] ...\n" + " service call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR ] ...\n" "Options:\n" - " i32: Write the integer INT into the send parcel.\n" + " i32: Write the 32-bit integer N into the send parcel.\n" + " i64: Write the 64-bit integer N into the send parcel.\n" + " f: Write the 32-bit single-precision number N into the send parcel.\n" + " d: Write the 64-bit double-precision number N into the send parcel.\n" " s16: Write the UTF-16 string STR into the send parcel.\n"; // " intent: Write and Intent int the send parcel. ARGS can be\n" // " action=STR data=STR type=STR launchFlags=INT component=STR categories=STR[,STR,...]\n"; diff --git a/cmds/servicemanager/bctest.c b/cmds/servicemanager/bctest.c index e02b45d103..fd91633ec7 100644 --- a/cmds/servicemanager/bctest.c +++ b/cmds/servicemanager/bctest.c @@ -3,6 +3,7 @@ #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <errno.h> #include "binder.h" diff --git a/cmds/servicemanager/binder.c b/cmds/servicemanager/binder.c index db7632d36a..6eecee1e63 100644 --- a/cmds/servicemanager/binder.c +++ b/cmds/servicemanager/binder.c @@ -4,6 +4,7 @@ #include <inttypes.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <errno.h> #include <unistd.h> #include <fcntl.h> @@ -112,7 +113,9 @@ struct binder_state *binder_open(size_t mapsize) if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) || (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) { - fprintf(stderr, "binder: driver version differs from user space\n"); + fprintf(stderr, + "binder: kernel driver version (%d) differs from user space version (%d)\n", + vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION); goto fail_open; } diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c index e20c13fa0b..031f848970 100644 --- a/cmds/servicemanager/service_manager.c +++ b/cmds/servicemanager/service_manager.c @@ -1,10 +1,12 @@ /* Copyright 2008 The Android Open Source Project */ -#include <stdio.h> -#include <stdlib.h> #include <errno.h> #include <fcntl.h> +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <cutils/multiuser.h> @@ -23,8 +25,6 @@ #include <cutils/log.h> #endif -uint32_t svcmgr_handle; - const char *str8(const uint16_t *x, size_t x_len) { static char buf[128]; @@ -176,28 +176,26 @@ uint16_t svcmgr_id[] = { uint32_t do_find_service(struct binder_state *bs, const uint16_t *s, size_t len, uid_t uid, pid_t spid) { - struct svcinfo *si; + struct svcinfo *si = find_svc(s, len); - if (!svc_can_find(s, len, spid)) { - ALOGE("find_service('%s') uid=%d - PERMISSION DENIED\n", - str8(s, len), uid); + if (!si || !si->handle) { return 0; } - si = find_svc(s, len); - //ALOGI("check_service('%s') handle = %x\n", str8(s, len), si ? si->handle : 0); - if (si && si->handle) { - if (!si->allow_isolated) { - // If this service doesn't allow access from isolated processes, - // then check the uid to see if it is isolated. - uid_t appid = uid % AID_USER; - if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) { - return 0; - } + + if (!si->allow_isolated) { + // If this service doesn't allow access from isolated processes, + // then check the uid to see if it is isolated. + uid_t appid = uid % AID_USER; + if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) { + return 0; } - return si->handle; - } else { + } + + if (!svc_can_find(s, len, spid)) { return 0; } + + return si->handle; } int do_add_service(struct binder_state *bs, @@ -262,10 +260,10 @@ int svcmgr_handler(struct binder_state *bs, uint32_t strict_policy; int allow_isolated; - //ALOGI("target=%x code=%d pid=%d uid=%d\n", - // txn->target.handle, txn->code, txn->sender_pid, txn->sender_euid); + //ALOGI("target=%p code=%d pid=%d uid=%d\n", + // (void*) txn->target.ptr, txn->code, txn->sender_pid, txn->sender_euid); - if (txn->target.handle != svcmgr_handle) + if (txn->target.ptr != BINDER_SERVICE_MANAGER) return -1; if (txn->code == PING_TRANSACTION) @@ -370,6 +368,7 @@ int main(int argc, char **argv) selinux_enabled = is_selinux_enabled(); sehandle = selinux_android_service_context_handle(); + selinux_status_open(true); if (selinux_enabled > 0) { if (sehandle == NULL) { @@ -389,7 +388,6 @@ int main(int argc, char **argv) cb.func_log = selinux_log_callback; selinux_set_callback(SELINUX_CB_LOG, cb); - svcmgr_handle = BINDER_SERVICE_MANAGER; binder_loop(bs, svcmgr_handler); return 0; diff --git a/data/etc/android.hardware.audio.pro.xml b/data/etc/android.hardware.audio.pro.xml new file mode 100644 index 0000000000..5328d415c6 --- /dev/null +++ b/data/etc/android.hardware.audio.pro.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- This is the feature indicating professional audio, as specified by the + CDD. ONLY devices that meet the CDD's requirements may declare this + feature. --> +<permissions> + <feature name="android.hardware.audio.pro" /> +</permissions> diff --git a/data/etc/android.hardware.fingerprint.xml b/data/etc/android.hardware.fingerprint.xml new file mode 100644 index 0000000000..3181e7eedd --- /dev/null +++ b/data/etc/android.hardware.fingerprint.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- This is the standard set of features for a biometric fingerprint sensor. --> +<permissions> + <feature name="android.hardware.fingerprint" /> +</permissions> diff --git a/data/etc/android.hardware.sensor.hifi_sensors.xml b/data/etc/android.hardware.sensor.hifi_sensors.xml new file mode 100644 index 0000000000..bb3901cefc --- /dev/null +++ b/data/etc/android.hardware.sensor.hifi_sensors.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2009 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 supporting hifi sensors. --> +<permissions> + <feature name="android.hardware.sensor.hifi_sensors" /> +</permissions> diff --git a/data/etc/android.software.midi.xml b/data/etc/android.software.midi.xml new file mode 100644 index 0000000000..a03cd55a94 --- /dev/null +++ b/data/etc/android.software.midi.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2015 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. +--> + +<permissions> + <feature name="android.software.midi" /> +</permissions> diff --git a/include/android/configuration.h b/include/android/configuration.h index be00066418..7573ccac33 100644 --- a/include/android/configuration.h +++ b/include/android/configuration.h @@ -78,6 +78,10 @@ enum { ACONFIGURATION_SCREENLONG_NO = 0x1, ACONFIGURATION_SCREENLONG_YES = 0x2, + ACONFIGURATION_SCREENROUND_ANY = 0x00, + ACONFIGURATION_SCREENROUND_NO = 0x1, + ACONFIGURATION_SCREENROUND_YES = 0x2, + ACONFIGURATION_UI_MODE_TYPE_ANY = 0x00, ACONFIGURATION_UI_MODE_TYPE_NORMAL = 0x01, ACONFIGURATION_UI_MODE_TYPE_DESK = 0x02, @@ -115,6 +119,7 @@ enum { ACONFIGURATION_UI_MODE = 0x1000, ACONFIGURATION_SMALLEST_SCREEN_SIZE = 0x2000, ACONFIGURATION_LAYOUTDIR = 0x4000, + ACONFIGURATION_SCREEN_ROUND = 0x8000, ACONFIGURATION_MNC_ZERO = 0xffff, }; @@ -288,6 +293,16 @@ int32_t AConfiguration_getScreenLong(AConfiguration* config); void AConfiguration_setScreenLong(AConfiguration* config, int32_t screenLong); /** + * Return the current ACONFIGURATION_SCREENROUND_* set in the configuration. + */ +int32_t AConfiguration_getScreenRound(AConfiguration* config); + +/** + * Set the current screen round in the configuration. + */ +void AConfiguration_setScreenRound(AConfiguration* config, int32_t screenRound); + +/** * Return the current ACONFIGURATION_UI_MODE_TYPE_* set in the configuration. */ int32_t AConfiguration_getUiModeType(AConfiguration* config); diff --git a/include/android/input.h b/include/android/input.h index a660761728..efbbb8558c 100644 --- a/include/android/input.h +++ b/include/android/input.h @@ -305,6 +305,12 @@ enum { /* The pointer is not down but has exited the boundaries of a window or view. */ AMOTION_EVENT_ACTION_HOVER_EXIT = 10, + + /* One or more buttons have been pressed. */ + AMOTION_EVENT_ACTION_BUTTON_PRESS = 11, + + /* One or more buttons have been released. */ + AMOTION_EVENT_ACTION_BUTTON_RELEASE = 12, }; /* @@ -405,6 +411,8 @@ enum { AMOTION_EVENT_BUTTON_TERTIARY = 1 << 2, AMOTION_EVENT_BUTTON_BACK = 1 << 3, AMOTION_EVENT_BUTTON_FORWARD = 1 << 4, + AMOTION_EVENT_BUTTON_STYLUS_PRIMARY = 1 << 5, + AMOTION_EVENT_BUTTON_STYLUS_SECONDARY = 1 << 6, }; /* @@ -445,6 +453,7 @@ enum { AINPUT_SOURCE_TOUCHSCREEN = 0x00001000 | AINPUT_SOURCE_CLASS_POINTER, AINPUT_SOURCE_MOUSE = 0x00002000 | AINPUT_SOURCE_CLASS_POINTER, AINPUT_SOURCE_STYLUS = 0x00004000 | AINPUT_SOURCE_CLASS_POINTER, + AINPUT_SOURCE_BLUETOOTH_STYLUS = 0x00008000 | AINPUT_SOURCE_STYLUS, AINPUT_SOURCE_TRACKBALL = 0x00010000 | AINPUT_SOURCE_CLASS_NAVIGATION, AINPUT_SOURCE_TOUCHPAD = 0x00100000 | AINPUT_SOURCE_CLASS_POSITION, AINPUT_SOURCE_TOUCH_NAVIGATION = 0x00200000 | AINPUT_SOURCE_CLASS_NONE, diff --git a/include/android/keycodes.h b/include/android/keycodes.h index 75d0ab69e6..de9e7354b5 100644 --- a/include/android/keycodes.h +++ b/include/android/keycodes.h @@ -302,7 +302,15 @@ enum { AKEYCODE_TV_CONTENTS_MENU = 256, AKEYCODE_TV_MEDIA_CONTEXT_MENU = 257, AKEYCODE_TV_TIMER_PROGRAMMING = 258, - AKEYCODE_HELP = 259 + AKEYCODE_HELP = 259, + AKEYCODE_NAVIGATE_PREVIOUS = 260, + AKEYCODE_NAVIGATE_NEXT = 261, + AKEYCODE_NAVIGATE_IN = 262, + AKEYCODE_NAVIGATE_OUT = 263, + AKEYCODE_MEDIA_SKIP_FORWARD = 272, + AKEYCODE_MEDIA_SKIP_BACKWARD = 273, + AKEYCODE_MEDIA_STEP_FORWARD = 274, + AKEYCODE_MEDIA_STEP_BACKWARD = 275 // NOTE: If you add a new keycode here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list. diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h new file mode 100644 index 0000000000..6c718c9037 --- /dev/null +++ b/include/android/multinetwork.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2015 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_MULTINETWORK_H +#define ANDROID_MULTINETWORK_H + +#include <netdb.h> +#include <stdlib.h> +#include <sys/cdefs.h> + +__BEGIN_DECLS + +/** + * The corresponding C type for android.net.Network#getNetworkHandle() return + * values. The Java signed long value can be safely cast to a net_handle_t: + * + * [C] ((net_handle_t) java_long_network_handle) + * [C++] static_cast<net_handle_t>(java_long_network_handle) + * + * as appropriate. + */ +typedef uint64_t net_handle_t; + +/** + * The value NETWORK_UNSPECIFIED indicates no specific network. + * + * For some functions (documented below), a previous binding may be cleared + * by an invocation with NETWORK_UNSPECIFIED. + * + * Depending on the context it may indicate an error. It is expressly + * not used to indicate some notion of the "current default network". + */ +#define NETWORK_UNSPECIFIED ((net_handle_t)0) + + +/** + * All functions below that return an int return 0 on success or -1 + * on failure with an appropriate errno value set. + */ + + +/** + * Set the network to be used by the given socket file descriptor. + * + * To clear a previous socket binding invoke with NETWORK_UNSPECIFIED. + * + * This is the equivalent of: + * + * [ android.net.Network#bindSocket() ] + * https://developer.android.com/reference/android/net/Network.html#bindSocket(java.net.Socket) + */ +int android_setsocknetwork(net_handle_t network, int fd); + + +/** + * Binds the current process to |network|. All sockets created in the future + * (and not explicitly bound via android_setsocknetwork()) will be bound to + * |network|. All host name resolutions will be limited to |network| as well. + * Note that if the network identified by |network| ever disconnects, all + * sockets created in this way will cease to work and all host name + * resolutions will fail. This is by design so an application doesn't + * accidentally use sockets it thinks are still bound to a particular network. + * + * To clear a previous process binding invoke with NETWORK_UNSPECIFIED. + * + * This is the equivalent of: + * + * [ android.net.ConnectivityManager#setProcessDefaultNetwork() ] + * https://developer.android.com/reference/android/net/ConnectivityManager.html#setProcessDefaultNetwork(android.net.Network) + */ +int android_setprocnetwork(net_handle_t network); + + +/** + * Perform hostname resolution via the DNS servers associated with |network|. + * + * All arguments (apart from |network|) are used identically as those passed + * to getaddrinfo(3). Return and error values are identical to those of + * getaddrinfo(3), and in particular gai_strerror(3) can be used as expected. + * Similar to getaddrinfo(3): + * - |hints| may be NULL (in which case man page documented defaults apply) + * - either |node| or |service| may be NULL, but not both + * - |res| must not be NULL + * + * This is the equivalent of: + * + * [ android.net.Network#getAllByName() ] + * https://developer.android.com/reference/android/net/Network.html#getAllByName(java.lang.String) + */ +int android_getaddrinfofornetwork(net_handle_t network, + const char *node, const char *service, + const struct addrinfo *hints, struct addrinfo **res); + +__END_DECLS + +#endif // ANDROID_MULTINETWORK_H diff --git a/include/android/sensor.h b/include/android/sensor.h index d58c4608c4..1be623221f 100644 --- a/include/android/sensor.h +++ b/include/android/sensor.h @@ -193,15 +193,28 @@ typedef ASensorRef const* ASensorList; /*****************************************************************************/ /* - * Get a reference to the sensor manager. ASensorManager is a singleton. + * Get a reference to the sensor manager. ASensorManager is a singleton + * per package as different packages may have access to different sensors. + * + * Deprecated: Use ASensorManager_getInstanceForPackage(const char*) instead. * * Example: * * ASensorManager* sensorManager = ASensorManager_getInstance(); * */ -ASensorManager* ASensorManager_getInstance(); +__attribute__ ((deprecated)) ASensorManager* ASensorManager_getInstance(); +/* + * Get a reference to the sensor manager. ASensorManager is a singleton + * per package as different packages may have access to different sensors. + * + * Example: + * + * ASensorManager* sensorManager = ASensorManager_getInstanceForPackage("foo.bar.baz"); + * + */ +ASensorManager* ASensorManager_getInstanceForPackage(const char* packageName); /* * Returns the list of available sensors. diff --git a/include/android/trace.h b/include/android/trace.h new file mode 100644 index 0000000000..e42e334102 --- /dev/null +++ b/include/android/trace.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2015 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_NATIVE_TRACE_H +#define ANDROID_NATIVE_TRACE_H + +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Returns true if tracing is enabled. Use this signal to avoid expensive computation only necessary + * when tracing is enabled. + */ +bool ATrace_isEnabled(); + +/** + * Writes a tracing message to indicate that the given section of code has begun. This call must be + * followed by a corresponding call to endSection() on the same thread. + * + * Note: At this time the vertical bar character '|' and newline character '\n' are used internally + * by the tracing mechanism. If sectionName contains these characters they will be replaced with a + * space character in the trace. + */ +void ATrace_beginSection(const char* sectionName); + +/** + * Writes a tracing message to indicate that a given section of code has ended. This call must be + * preceeded by a corresponding call to beginSection(char*) on the same thread. Calling this method + * will mark the end of the most recently begun section of code, so care must be taken to ensure + * that beginSection / endSection pairs are properly nested and called from the same thread. + */ +void ATrace_endSection(); + +#ifdef __cplusplus +}; +#endif + +#endif // ANDROID_NATIVE_TRACE_H diff --git a/include/binder/AppOpsManager.h b/include/binder/AppOpsManager.h index 256cb949bb..042927c176 100644 --- a/include/binder/AppOpsManager.h +++ b/include/binder/AppOpsManager.h @@ -63,7 +63,35 @@ public: OP_ACCESS_NOTIFICATIONS = 25, OP_CAMERA = 26, OP_RECORD_AUDIO = 27, - OP_PLAY_AUDIO = 28 + OP_PLAY_AUDIO = 28, + OP_READ_CLIPBOARD = 29, + OP_WRITE_CLIPBOARD = 30, + OP_TAKE_MEDIA_BUTTONS = 31, + OP_TAKE_AUDIO_FOCUS = 32, + OP_AUDIO_MASTER_VOLUME = 33, + OP_AUDIO_VOICE_VOLUME = 34, + OP_AUDIO_RING_VOLUME = 35, + OP_AUDIO_MEDIA_VOLUME = 36, + OP_AUDIO_ALARM_VOLUME = 37, + OP_AUDIO_NOTIFICATION_VOLUME = 38, + OP_AUDIO_BLUETOOTH_VOLUME = 39, + OP_WAKE_LOCK = 40, + OP_MONITOR_LOCATION = 41, + OP_MONITOR_HIGH_POWER_LOCATION = 42, + OP_GET_USAGE_STATS = 43, + OP_MUTE_MICROPHONE = 44, + OP_TOAST_WINDOW = 45, + OP_PROJECT_MEDIA = 46, + OP_ACTIVATE_VPN = 47, + OP_WRITE_WALLPAPER = 48, + OP_ASSIST_STRUCTURE = 49, + OP_ASSIST_SCREENSHOT = 50, + OP_READ_PHONE_STATE = 51, + OP_ADD_VOICEMAIL = 52, + OP_USE_SIP = 53, + OP_PROCESS_OUTGOING_CALLS = 54, + OP_USE_FINGERPRINT = 55, + OP_BODY_SENSORS = 56 }; AppOpsManager(); @@ -75,6 +103,7 @@ public: void startWatchingMode(int32_t op, const String16& packageName, const sp<IAppOpsCallback>& callback); void stopWatchingMode(const sp<IAppOpsCallback>& callback); + int32_t permissionToOpCode(const String16& permission); private: Mutex mLock; diff --git a/include/binder/IAppOpsService.h b/include/binder/IAppOpsService.h index 193e9cc0ec..cd81efa363 100644 --- a/include/binder/IAppOpsService.h +++ b/include/binder/IAppOpsService.h @@ -40,6 +40,7 @@ public: const sp<IAppOpsCallback>& callback) = 0; virtual void stopWatchingMode(const sp<IAppOpsCallback>& callback) = 0; virtual sp<IBinder> getToken(const sp<IBinder>& clientToken) = 0; + virtual int32_t permissionToOpCode(const String16& permission) = 0; enum { CHECK_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, @@ -49,6 +50,7 @@ public: START_WATCHING_MODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+4, STOP_WATCHING_MODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+5, GET_TOKEN_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+6, + PERMISSION_TO_OP_CODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+7, }; enum { diff --git a/include/binder/IBatteryStats.h b/include/binder/IBatteryStats.h index 7ddac574b2..5f3818652b 100644 --- a/include/binder/IBatteryStats.h +++ b/include/binder/IBatteryStats.h @@ -36,6 +36,12 @@ public: virtual void noteStopAudio(int uid) = 0; virtual void noteResetVideo() = 0; virtual void noteResetAudio() = 0; + virtual void noteFlashlightOn(int uid) = 0; + virtual void noteFlashlightOff(int uid) = 0; + virtual void noteStartCamera(int uid) = 0; + virtual void noteStopCamera(int uid) = 0; + virtual void noteResetCamera() = 0; + virtual void noteResetFlashlight() = 0; enum { NOTE_START_SENSOR_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, @@ -46,6 +52,12 @@ public: NOTE_STOP_AUDIO_TRANSACTION, NOTE_RESET_VIDEO_TRANSACTION, NOTE_RESET_AUDIO_TRANSACTION, + NOTE_FLASHLIGHT_ON_TRANSACTION, + NOTE_FLASHLIGHT_OFF_TRANSACTION, + NOTE_START_CAMERA_TRANSACTION, + NOTE_STOP_CAMERA_TRANSACTION, + NOTE_RESET_CAMERA_TRANSACTION, + NOTE_RESET_FLASHLIGHT_TRANSACTION }; }; diff --git a/include/binder/IInterface.h b/include/binder/IInterface.h index 5f9f69c042..4ce361380d 100644 --- a/include/binder/IInterface.h +++ b/include/binder/IInterface.h @@ -28,9 +28,9 @@ class IInterface : public virtual RefBase { public: IInterface(); - sp<IBinder> asBinder(); - sp<const IBinder> asBinder() const; - + static sp<IBinder> asBinder(const IInterface*); + static sp<IBinder> asBinder(const sp<IInterface>&); + protected: virtual ~IInterface(); virtual IBinder* onAsBinder() = 0; diff --git a/include/binder/IPCThreadState.h b/include/binder/IPCThreadState.h index 6e0c01beac..1853cff235 100644 --- a/include/binder/IPCThreadState.h +++ b/include/binder/IPCThreadState.h @@ -22,7 +22,7 @@ #include <binder/ProcessState.h> #include <utils/Vector.h> -#ifdef HAVE_WIN32_PROC +#if defined(_WIN32) typedef int uid_t; #endif @@ -39,8 +39,8 @@ public: status_t clearLastError(); - int getCallingPid() const; - int getCallingUid() const; + pid_t getCallingPid() const; + uid_t getCallingUid() const; void setStrictModePolicy(int32_t policy); int32_t getStrictModePolicy() const; @@ -76,14 +76,18 @@ public: BpBinder* proxy); static void shutdown(); - + // Call this to disable switching threads to background scheduling when // receiving incoming IPC calls. This is specifically here for the // Android system process, since it expects to have background apps calling // in to it but doesn't want to acquire locks in its services while in // the background. static void disableBackgroundScheduling(bool disable); - + + // Call blocks until the number of executing binder threads is less than + // the maximum number of binder threads threads allowed for this process. + void blockUntilThreadAvailable(); + private: IPCThreadState(); ~IPCThreadState(); @@ -101,9 +105,9 @@ private: status_t getAndExecuteCommand(); status_t executeCommand(int32_t command); void processPendingDerefs(); - + void clearCaller(); - + static void threadDestructor(void *st); static void freeBuffer(Parcel* parcel, const uint8_t* data, size_t dataSize, @@ -114,7 +118,7 @@ private: const pid_t mMyThreadId; Vector<BBinder*> mPendingStrongDerefs; Vector<RefBase::weakref_type*> mPendingWeakDerefs; - + Parcel mIn; Parcel mOut; status_t mLastError; diff --git a/include/binder/IPermissionController.h b/include/binder/IPermissionController.h index f9d371bd15..4e5fb34838 100644 --- a/include/binder/IPermissionController.h +++ b/include/binder/IPermissionController.h @@ -19,6 +19,7 @@ #define ANDROID_IPERMISSION_CONTROLLER_H #include <binder/IInterface.h> +#include <stdlib.h> namespace android { @@ -29,11 +30,16 @@ class IPermissionController : public IInterface public: DECLARE_META_INTERFACE(PermissionController); - virtual bool checkPermission(const String16& permission, - int32_t pid, int32_t uid) = 0; - + virtual bool checkPermission(const String16& permission, int32_t pid, int32_t uid) = 0; + + virtual void getPackagesForUid(const uid_t uid, Vector<String16> &packages) = 0; + + virtual bool isRuntimePermission(const String16& permission) = 0; + enum { - CHECK_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + CHECK_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, + GET_PACKAGES_FOR_UID_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 1, + IS_RUNTIME_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 2 }; }; diff --git a/include/binder/IProcessInfoService.h b/include/binder/IProcessInfoService.h new file mode 100644 index 0000000000..dc62f457c7 --- /dev/null +++ b/include/binder/IProcessInfoService.h @@ -0,0 +1,53 @@ +/* + * Copyright 2015 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_I_PROCESS_INFO_SERVICE_H +#define ANDROID_I_PROCESS_INFO_SERVICE_H + +#include <binder/IInterface.h> + +namespace android { + +// ---------------------------------------------------------------------- + +class IProcessInfoService : public IInterface { +public: + DECLARE_META_INTERFACE(ProcessInfoService); + + virtual status_t getProcessStatesFromPids( size_t length, + /*in*/ int32_t* pids, + /*out*/ int32_t* states) = 0; + + enum { + GET_PROCESS_STATES_FROM_PIDS = IBinder::FIRST_CALL_TRANSACTION, + }; +}; + +// ---------------------------------------------------------------------- + +class BnProcessInfoService : public BnInterface<IProcessInfoService> { +public: + virtual status_t onTransact( uint32_t code, + const Parcel& data, + Parcel* reply, + uint32_t flags = 0); +}; + +// ---------------------------------------------------------------------- + +}; // namespace android + +#endif // ANDROID_I_PROCESS_INFO_SERVICE_H diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h index 6a69761cf3..3ada1e9096 100644 --- a/include/binder/Parcel.h +++ b/include/binder/Parcel.h @@ -60,6 +60,7 @@ public: status_t appendFrom(const Parcel *parcel, size_t start, size_t len); + bool allowFds() const; bool pushAllowFds(bool allowFds); void restoreAllowFds(bool lastValue); @@ -94,7 +95,9 @@ public: void* writeInplace(size_t len); status_t writeUnpadded(const void* data, size_t len); status_t writeInt32(int32_t val); + status_t writeUint32(uint32_t val); status_t writeInt64(int64_t val); + status_t writeUint64(uint64_t val); status_t writeFloat(float val); status_t writeDouble(double val); status_t writeCString(const char* str); @@ -128,16 +131,18 @@ public: // will be closed once the parcel is destroyed. status_t writeDupFileDescriptor(int fd); - // Writes a raw fd and optional comm channel fd to the parcel as a ParcelFileDescriptor. - // A dup's of the fds are made, which will be closed once the parcel is destroyed. - // Null values are passed as -1. - status_t writeParcelFileDescriptor(int fd, int commChannel = -1); - // Writes a blob to the parcel. // If the blob is small, then it is stored in-place, otherwise it is - // transferred by way of an anonymous shared memory region. + // transferred by way of an anonymous shared memory region. Prefer sending + // immutable blobs if possible since they may be subsequently transferred between + // processes without further copying whereas mutable blobs always need to be copied. // The caller should call release() on the blob after writing its contents. - status_t writeBlob(size_t len, WritableBlob* outBlob); + status_t writeBlob(size_t len, bool mutableCopy, WritableBlob* outBlob); + + // Write an existing immutable blob file descriptor to the parcel. + // This allows the client to send the same blob to multiple processes + // as long as it keeps a dup of the blob file descriptor handy for later. + status_t writeDupImmutableBlobFileDescriptor(int fd); status_t writeObject(const flat_binder_object& val, bool nullMetaData); @@ -152,8 +157,12 @@ public: const void* readInplace(size_t len) const; int32_t readInt32() const; status_t readInt32(int32_t *pArg) const; + uint32_t readUint32() const; + status_t readUint32(uint32_t *pArg) const; int64_t readInt64() const; status_t readInt64(int64_t *pArg) const; + uint64_t readUint64() const; + status_t readUint64(uint64_t *pArg) const; float readFloat() const; status_t readFloat(float *pArg) const; double readDouble() const; @@ -192,11 +201,6 @@ public: // in the parcel, which you do not own -- use dup() to get your own copy. int readFileDescriptor() const; - // Reads a ParcelFileDescriptor from the parcel. Returns the raw fd as - // the result, and the optional comm channel fd in outCommChannel. - // Null values are returned as -1. - int readParcelFileDescriptor(int& outCommChannel) const; - // Reads a blob from the parcel. // The caller should call release() on the blob after reading its contents. status_t readBlob(size_t len, ReadableBlob* outBlob) const; @@ -274,16 +278,19 @@ private: Blob(); ~Blob(); + void clear(); void release(); inline size_t size() const { return mSize; } + inline int fd() const { return mFd; }; + inline bool isMutable() const { return mMutable; } protected: - void init(bool mapped, void* data, size_t size); - void clear(); + void init(int fd, void* data, size_t size, bool isMutable); - bool mMapped; + int mFd; // owned by parcel so not closed when released void* mData; size_t mSize; + bool mMutable; }; class FlattenableHelperInterface { @@ -324,6 +331,7 @@ public: friend class Parcel; public: inline const void* data() const { return mData; } + inline void* mutableData() { return isMutable() ? mData : NULL; } }; class WritableBlob : public Blob { @@ -331,6 +339,12 @@ public: public: inline void* data() { return mData; } }; + +private: + size_t mBlobAshmemSize; + +public: + size_t getBlobAshmemSize() const; }; // --------------------------------------------------------------------------- diff --git a/include/binder/ProcessInfoService.h b/include/binder/ProcessInfoService.h new file mode 100644 index 0000000000..c5ead20676 --- /dev/null +++ b/include/binder/ProcessInfoService.h @@ -0,0 +1,65 @@ +/* + * Copyright 2015 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_PROCESS_INFO_SERVICE_H +#define ANDROID_PROCESS_INFO_SERVICE_H + +#include <binder/IProcessInfoService.h> +#include <utils/Errors.h> +#include <utils/Singleton.h> +#include <sys/types.h> + +namespace android { + +// ---------------------------------------------------------------------- + +class ProcessInfoService : public Singleton<ProcessInfoService> { + + friend class Singleton<ProcessInfoService>; + sp<IProcessInfoService> mProcessInfoService; + Mutex mProcessInfoLock; + + ProcessInfoService(); + + status_t getProcessStatesImpl(size_t length, /*in*/ int32_t* pids, /*out*/ int32_t* states); + void updateBinderLocked(); + + static const int BINDER_ATTEMPT_LIMIT = 5; + +public: + + /** + * For each PID in the given "pids" input array, write the current process state + * for that process into the "states" output array, or + * ActivityManager.PROCESS_STATE_NONEXISTENT * to indicate that no process with the given PID + * exists. + * + * Returns NO_ERROR if this operation was successful, or a negative error code otherwise. + */ + static status_t getProcessStatesFromPids(size_t length, /*in*/ int32_t* pids, + /*out*/ int32_t* states) { + return ProcessInfoService::getInstance().getProcessStatesImpl(length, /*in*/ pids, + /*out*/ states); + } + +}; + +// ---------------------------------------------------------------------- + +}; // namespace android + +#endif // ANDROID_PROCESS_INFO_SERVICE_H + diff --git a/include/binder/ProcessState.h b/include/binder/ProcessState.h index 3bc978d9e9..f9edc2a691 100644 --- a/include/binder/ProcessState.h +++ b/include/binder/ProcessState.h @@ -24,6 +24,8 @@ #include <utils/threads.h> +#include <pthread.h> + // --------------------------------------------------------------------------- namespace android { @@ -71,25 +73,33 @@ private: ProcessState(const ProcessState& o); ProcessState& operator=(const ProcessState& o); String8 makeBinderThreadName(); - + struct handle_entry { IBinder* binder; RefBase::weakref_type* refs; }; - + handle_entry* lookupHandleLocked(int32_t handle); int mDriverFD; void* mVMStart; - + + // Protects thread count variable below. + pthread_mutex_t mThreadCountLock; + pthread_cond_t mThreadCountDecrement; + // Number of binder threads current executing a command. + size_t mExecutingThreadsCount; + // Maximum number for binder threads allowed for this process. + size_t mMaxThreads; + mutable Mutex mLock; // protects everything below. - + Vector<handle_entry>mHandleToObject; bool mManagesContexts; context_check_func mBinderContextCheckFunc; void* mBinderContextUserData; - + KeyedVector<String16, sp<IBinder> > mContexts; diff --git a/include/gui/BufferItem.h b/include/gui/BufferItem.h index 01b6ff4b54..145efe6f60 100644 --- a/include/gui/BufferItem.h +++ b/include/gui/BufferItem.h @@ -20,9 +20,10 @@ #include <EGL/egl.h> #include <EGL/eglext.h> -#include <gui/IGraphicBufferConsumer.h> - #include <ui/Rect.h> +#include <ui/Region.h> + +#include <system/graphics.h> #include <utils/Flattenable.h> #include <utils/StrongPointer.h> @@ -45,7 +46,6 @@ class BufferItem : public Flattenable<BufferItem> { enum { INVALID_BUFFER_SLOT = -1 }; BufferItem(); ~BufferItem(); - operator IGraphicBufferConsumer::BufferItem() const; static const char* scalingModeName(uint32_t scalingMode); @@ -72,17 +72,39 @@ class BufferItem : public Flattenable<BufferItem> { // to set by queueBuffer each time this slot is queued. This value // is guaranteed to be monotonically increasing for each newly // acquired buffer. - int64_t mTimestamp; + union { + int64_t mTimestamp; + struct { + uint32_t mTimestampLo; + uint32_t mTimestampHi; + }; + }; // mIsAutoTimestamp indicates whether mTimestamp was generated // automatically when the buffer was queued. bool mIsAutoTimestamp; - // mFrameNumber is the number of the queued frame for this slot. - uint64_t mFrameNumber; + // mDataSpace is the current dataSpace value for this buffer slot. This gets + // set by queueBuffer each time this slot is queued. The meaning of the + // dataSpace is format-dependent. + android_dataspace mDataSpace; - // mSlot is the slot index of this buffer (default INVALID_BUFFER_SLOT). - int mSlot; + // mFrameNumber is the number of the queued frame for this slot. + union { + uint64_t mFrameNumber; + struct { + uint32_t mFrameNumberLo; + uint32_t mFrameNumberHi; + }; + }; + + union { + // mSlot is the slot index of this buffer (default INVALID_BUFFER_SLOT). + int mSlot; + + // mBuf is the former name for mSlot + int mBuf; + }; // mIsDroppable whether this buffer was queued with the // property that it can be replaced by a new buffer for the purpose of @@ -97,6 +119,10 @@ class BufferItem : public Flattenable<BufferItem> { // Indicates this buffer must be transformed by the inverse transform of the screen // it is displayed onto. This is applied after mTransform. bool mTransformToDisplayInverse; + + // Describes the portion of the surface that has been modified since the + // previous frame + Region mSurfaceDamage; }; } // namespace android diff --git a/include/gui/BufferItemConsumer.h b/include/gui/BufferItemConsumer.h index 5494ff1f30..56c7a3f463 100644 --- a/include/gui/BufferItemConsumer.h +++ b/include/gui/BufferItemConsumer.h @@ -42,8 +42,6 @@ class BufferItemConsumer: public ConsumerBase public: typedef ConsumerBase::FrameAvailableListener FrameAvailableListener; - typedef BufferQueue::BufferItem BufferItem; - enum { DEFAULT_MAX_BUFFERS = -1 }; enum { INVALID_BUFFER_SLOT = BufferQueue::INVALID_BUFFER_SLOT }; enum { NO_BUFFER_AVAILABLE = BufferQueue::NO_BUFFER_AVAILABLE }; @@ -76,8 +74,8 @@ class BufferItemConsumer: public ConsumerBase // // If waitForFence is true, and the acquired BufferItem has a valid fence object, // acquireBuffer will wait on the fence with no timeout before returning. - status_t acquireBuffer(BufferItem *item, nsecs_t presentWhen, - bool waitForFence = true); + status_t acquireBuffer(BufferItem* item, nsecs_t presentWhen, + bool waitForFence = true); // Returns an acquired buffer to the queue, allowing it to be reused. Since // only a fixed number of buffers may be acquired at a time, old buffers @@ -88,14 +86,6 @@ class BufferItemConsumer: public ConsumerBase status_t releaseBuffer(const BufferItem &item, const sp<Fence>& releaseFence = Fence::NO_FENCE); - // setDefaultBufferSize is used to set the size of buffers returned by - // requestBuffers when a with and height of zero is requested. - status_t setDefaultBufferSize(uint32_t w, uint32_t h); - - // setDefaultBufferFormat allows the BufferQueue to create - // GraphicBuffers of a defaultFormat if no format is specified - // in dequeueBuffer - status_t setDefaultBufferFormat(uint32_t defaultFormat); }; } // namespace android diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h index 1188837456..09300a20c9 100644 --- a/include/gui/BufferQueue.h +++ b/include/gui/BufferQueue.h @@ -17,6 +17,7 @@ #ifndef ANDROID_GUI_BUFFERQUEUE_H #define ANDROID_GUI_BUFFERQUEUE_H +#include <gui/BufferItem.h> #include <gui/BufferQueueDefs.h> #include <gui/IGraphicBufferConsumer.h> #include <gui/IGraphicBufferProducer.h> @@ -34,7 +35,7 @@ public: // Attempts at runtime to increase the number of buffers past this will fail. enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS }; // Used as a placeholder slot# when the value isn't pointing to an existing buffer. - enum { INVALID_BUFFER_SLOT = IGraphicBufferConsumer::BufferItem::INVALID_BUFFER_SLOT }; + enum { INVALID_BUFFER_SLOT = BufferItem::INVALID_BUFFER_SLOT }; // Alias to <IGraphicBufferConsumer.h> -- please scope from there in future code! enum { NO_BUFFER_AVAILABLE = IGraphicBufferConsumer::NO_BUFFER_AVAILABLE, @@ -47,7 +48,6 @@ public: // for backward source compatibility typedef ::android::ConsumerListener ConsumerListener; - typedef IGraphicBufferConsumer::BufferItem BufferItem; // ProxyConsumerListener is a ConsumerListener implementation that keeps a weak // reference to the actual consumer object. It forwards all calls to that @@ -62,9 +62,10 @@ public: public: ProxyConsumerListener(const wp<ConsumerListener>& consumerListener); virtual ~ProxyConsumerListener(); - virtual void onFrameAvailable(const android::BufferItem& item); - virtual void onBuffersReleased(); - virtual void onSidebandStreamChanged(); + virtual void onFrameAvailable(const BufferItem& item) override; + virtual void onFrameReplaced(const BufferItem& item) override; + virtual void onBuffersReleased() override; + virtual void onSidebandStreamChanged() override; private: // mConsumerListener is a weak reference to the IConsumerListener. This is // the raison d'etre of ProxyConsumerListener. diff --git a/include/gui/BufferQueueConsumer.h b/include/gui/BufferQueueConsumer.h index 1912ed03da..cde302f8a6 100644 --- a/include/gui/BufferQueueConsumer.h +++ b/include/gui/BufferQueueConsumer.h @@ -47,7 +47,7 @@ public: // returned. The presentation time is in nanoseconds, and the time base // is CLOCK_MONOTONIC. virtual status_t acquireBuffer(BufferItem* outBuffer, - nsecs_t expectedPresent); + nsecs_t expectedPresent, uint64_t maxFrameNumber = 0) override; // See IGraphicBufferConsumer::detachBuffer virtual status_t detachBuffer(int slot); @@ -125,9 +125,15 @@ public: // setDefaultBufferFormat allows the BufferQueue to create // GraphicBuffers of a defaultFormat if no format is specified - // in dequeueBuffer. Formats are enumerated in graphics.h; the - // initial default is HAL_PIXEL_FORMAT_RGBA_8888. - virtual status_t setDefaultBufferFormat(uint32_t defaultFormat); + // in dequeueBuffer. The initial default is HAL_PIXEL_FORMAT_RGBA_8888. + virtual status_t setDefaultBufferFormat(PixelFormat defaultFormat); + + // setDefaultBufferDataSpace allows the BufferQueue to create + // GraphicBuffers of a defaultDataSpace if no data space is specified + // in queueBuffer. + // The initial default is HAL_DATASPACE_UNKNOWN + virtual status_t setDefaultBufferDataSpace( + android_dataspace defaultDataSpace); // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer. // These are merged with the bits passed to dequeueBuffer. The values are diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h index 1050e3b6ca..99134ea501 100644 --- a/include/gui/BufferQueueCore.h +++ b/include/gui/BufferQueueCore.h @@ -17,6 +17,7 @@ #ifndef ANDROID_GUI_BUFFERQUEUECORE_H #define ANDROID_GUI_BUFFERQUEUECORE_H +#include <gui/BufferItem.h> #include <gui/BufferQueueDefs.h> #include <gui/BufferSlot.h> @@ -29,11 +30,14 @@ #include <utils/Trace.h> #include <utils/Vector.h> -#define BQ_LOGV(x, ...) ALOGV("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) -#define BQ_LOGD(x, ...) ALOGD("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) -#define BQ_LOGI(x, ...) ALOGI("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) -#define BQ_LOGW(x, ...) ALOGW("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) -#define BQ_LOGE(x, ...) ALOGE("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) +#include <list> +#include <set> + +#define BQ_LOGV(x, ...) ALOGV("[%s] " x, mConsumerName.string(), ##__VA_ARGS__) +#define BQ_LOGD(x, ...) ALOGD("[%s] " x, mConsumerName.string(), ##__VA_ARGS__) +#define BQ_LOGI(x, ...) ALOGI("[%s] " x, mConsumerName.string(), ##__VA_ARGS__) +#define BQ_LOGW(x, ...) ALOGW("[%s] " x, mConsumerName.string(), ##__VA_ARGS__) +#define BQ_LOGE(x, ...) ALOGE("[%s] " x, mConsumerName.string(), ##__VA_ARGS__) #define ATRACE_BUFFER_INDEX(index) \ if (ATRACE_ENABLED()) { \ @@ -45,7 +49,6 @@ namespace android { -class BufferItem; class IConsumerListener; class IGraphicBufferAlloc; class IProducerListener; @@ -58,7 +61,7 @@ class BufferQueueCore : public virtual RefBase { public: // Used as a placeholder slot number when the value isn't pointing to an // existing buffer. - enum { INVALID_BUFFER_SLOT = -1 }; // TODO: Extract from IGBC::BufferItem + enum { INVALID_BUFFER_SLOT = BufferItem::INVALID_BUFFER_SLOT }; // We reserve two slots in order to guarantee that the producer and // consumer can run asynchronously. @@ -123,6 +126,10 @@ private: // waitWhileAllocatingLocked blocks until mIsAllocating is false. void waitWhileAllocatingLocked() const; + // validateConsistencyLocked ensures that the free lists are in sync with + // the information stored in mSlots + void validateConsistencyLocked() const; + // mAllocator is the connection to SurfaceFlinger that is used to allocate // new GraphicBuffer objects. sp<IGraphicBufferAlloc> mAllocator; @@ -177,6 +184,14 @@ private: // mQueue is a FIFO of queued buffers used in synchronous mode. Fifo mQueue; + // mFreeSlots contains all of the slots which are FREE and do not currently + // have a buffer attached + std::set<int> mFreeSlots; + + // mFreeBuffers contains all of the slots which are FREE and currently have + // a buffer attached + std::list<int> mFreeBuffers; + // mOverrideMaxBufferCount is the limit on the number of buffers that will // be allocated at one time. This value is set by the producer by calling // setBufferCount. The default is 0, which means that the producer doesn't @@ -199,15 +214,20 @@ private: // mDefaultBufferFormat can be set so it will override the buffer format // when it isn't specified in dequeueBuffer. - uint32_t mDefaultBufferFormat; + PixelFormat mDefaultBufferFormat; // mDefaultWidth holds the default width of allocated buffers. It is used // in dequeueBuffer if a width and height of 0 are specified. - int mDefaultWidth; + uint32_t mDefaultWidth; // mDefaultHeight holds the default height of allocated buffers. It is used // in dequeueBuffer if a width and height of 0 are specified. - int mDefaultHeight; + uint32_t mDefaultHeight; + + // mDefaultBufferDataSpace holds the default dataSpace of queued buffers. + // It is used in queueBuffer if a dataspace of 0 (HAL_DATASPACE_UNKNOWN) + // is specified. + android_dataspace mDefaultBufferDataSpace; // mDefaultMaxBufferCount is the default limit on the number of buffers that // will be allocated at one time. This default limit is set by the consumer. @@ -246,6 +266,20 @@ private: // mIsAllocatingCondition is a condition variable used by producers to wait until mIsAllocating // becomes false. mutable Condition mIsAllocatingCondition; + + // mAllowAllocation determines whether dequeueBuffer is allowed to allocate + // new buffers + bool mAllowAllocation; + + // mBufferAge tracks the age of the contents of the most recently dequeued + // buffer as the number of frames that have elapsed since it was last queued + uint64_t mBufferAge; + + // mGenerationNumber stores the current generation number of the attached + // producer. Any attempt to attach a buffer with a different generation + // number will fail. + uint32_t mGenerationNumber; + }; // class BufferQueueCore } // namespace android diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h index ed1056a59d..9754a89eac 100644 --- a/include/gui/BufferQueueProducer.h +++ b/include/gui/BufferQueueProducer.h @@ -73,9 +73,7 @@ public: // updateTexImage() is called. If width and height are both zero, the // default values specified by setDefaultBufferSize() are used instead. // - // The pixel formats are enumerated in graphics.h, e.g. - // HAL_PIXEL_FORMAT_RGBA_8888. If the format is 0, the default format - // will be used. + // If the format is 0, the default format will be used. // // The usage argument specifies gralloc buffer usage flags. The values // are enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER. These @@ -93,8 +91,9 @@ public: // // In both cases, the producer will need to call requestBuffer to get a // GraphicBuffer handle for the returned slot. - virtual status_t dequeueBuffer(int *outSlot, sp<Fence>* outFence, bool async, - uint32_t width, uint32_t height, uint32_t format, uint32_t usage); + virtual status_t dequeueBuffer(int *outSlot, sp<Fence>* outFence, + bool async, uint32_t width, uint32_t height, PixelFormat format, + uint32_t usage); // See IGraphicBufferProducer::detachBuffer virtual status_t detachBuffer(int slot); @@ -171,7 +170,16 @@ public: // See IGraphicBufferProducer::allocateBuffers virtual void allocateBuffers(bool async, uint32_t width, uint32_t height, - uint32_t format, uint32_t usage); + PixelFormat format, uint32_t usage); + + // See IGraphicBufferProducer::allowAllocation + virtual status_t allowAllocation(bool allow); + + // See IGraphicBufferProducer::setGenerationNumber + virtual status_t setGenerationNumber(uint32_t generationNumber); + + // See IGraphicBufferProducer::getConsumerName + virtual String8 getConsumerName() const override; private: // This is required by the IBinder::DeathRecipient interface diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h index f7ab5ac59b..9307a26fb3 100644 --- a/include/gui/ConsumerBase.h +++ b/include/gui/ConsumerBase.h @@ -38,15 +38,9 @@ class ConsumerBase : public virtual RefBase, protected ConsumerListener { public: struct FrameAvailableListener : public virtual RefBase { - // onFrameAvailable() is called each time an additional frame becomes - // available for consumption. This means that frames that are queued - // while in asynchronous mode only trigger the callback if no previous - // frames are pending. Frames queued while in synchronous mode always - // trigger the callback. - // - // This is called without any lock held and can be called concurrently - // by multiple threads. + // See IConsumerListener::onFrame{Available,Replaced} virtual void onFrameAvailable(const BufferItem& item) = 0; + virtual void onFrameReplaced(const BufferItem& /* item */) {} }; virtual ~ConsumerBase(); @@ -62,6 +56,9 @@ public: // or by OpenGL ES as a texture) then those buffer will remain allocated. void abandon(); + // Returns true if the ConsumerBase is in the 'abandoned' state + bool isAbandoned(); + // set the name of the ConsumerBase that will be used to identify it in // log messages. void setName(const String8& name); @@ -76,6 +73,18 @@ public: // when a new frame becomes available. void setFrameAvailableListener(const wp<FrameAvailableListener>& listener); + // See IGraphicBufferConsumer::detachBuffer + status_t detachBuffer(int slot); + + // See IGraphicBufferConsumer::setDefaultBufferSize + status_t setDefaultBufferSize(uint32_t width, uint32_t height); + + // See IGraphicBufferConsumer::setDefaultBufferFormat + status_t setDefaultBufferFormat(PixelFormat defaultFormat); + + // See IGraphicBufferConsumer::setDefaultBufferDataSpace + status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace); + private: ConsumerBase(const ConsumerBase&); void operator=(const ConsumerBase&); @@ -101,14 +110,16 @@ protected: // Implementation of the IConsumerListener interface. These // calls are used to notify the ConsumerBase of asynchronous events in the - // BufferQueue. The onFrameAvailable and onBuffersReleased methods should - // not need to be overridden by derived classes, but if they are overridden - // the ConsumerBase implementation must be called from the derived class. - // The ConsumerBase version of onSidebandStreamChanged does nothing and can - // be overriden by derived classes if they want the notification. - virtual void onFrameAvailable(const BufferItem& item); - virtual void onBuffersReleased(); - virtual void onSidebandStreamChanged(); + // BufferQueue. The onFrameAvailable, onFrameReplaced, and + // onBuffersReleased methods should not need to be overridden by derived + // classes, but if they are overridden the ConsumerBase implementation must + // be called from the derived class. The ConsumerBase version of + // onSidebandStreamChanged does nothing and can be overriden by derived + // classes if they want the notification. + virtual void onFrameAvailable(const BufferItem& item) override; + virtual void onFrameReplaced(const BufferItem& item) override; + virtual void onBuffersReleased() override; + virtual void onSidebandStreamChanged() override; // freeBufferLocked frees up the given buffer slot. If the slot has been // initialized this will release the reference to the GraphicBuffer in that @@ -153,8 +164,8 @@ protected: // initialization that must take place the first time a buffer is assigned // to a slot. If it is overridden the derived class's implementation must // call ConsumerBase::acquireBufferLocked. - virtual status_t acquireBufferLocked(IGraphicBufferConsumer::BufferItem *item, - nsecs_t presentWhen); + virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen, + uint64_t maxFrameNumber = 0); // releaseBufferLocked relinquishes control over a buffer, returning that // control to the BufferQueue. diff --git a/include/gui/CpuConsumer.h b/include/gui/CpuConsumer.h index 4c6822a096..3b07a31750 100644 --- a/include/gui/CpuConsumer.h +++ b/include/gui/CpuConsumer.h @@ -53,6 +53,7 @@ class CpuConsumer : public ConsumerBase uint32_t transform; uint32_t scalingMode; int64_t timestamp; + android_dataspace dataSpace; uint64_t frameNumber; // this is the same as format, except for formats that are compatible with // a flexible format (e.g. HAL_PIXEL_FORMAT_YCbCr_420_888). In the latter @@ -71,7 +72,7 @@ class CpuConsumer : public ConsumerBase // Create a new CPU consumer. The maxLockedBuffers parameter specifies // how many buffers can be locked for user access at the same time. CpuConsumer(const sp<IGraphicBufferConsumer>& bq, - uint32_t maxLockedBuffers, bool controlledByApp = false); + size_t maxLockedBuffers, bool controlledByApp = false); virtual ~CpuConsumer(); @@ -79,18 +80,6 @@ class CpuConsumer : public ConsumerBase // log messages. void setName(const String8& name); - // setDefaultBufferSize is used to set the size of buffers returned by - // requestBuffers when a width and height of zero is requested. - // A call to setDefaultBufferSize() may trigger requestBuffers() to - // be called from the client. Default size is 1x1. - status_t setDefaultBufferSize(uint32_t width, uint32_t height); - - // setDefaultBufferFormat allows CpuConsumer's BufferQueue to create buffers - // of a defaultFormat if no format is specified by producer. Formats are - // enumerated in graphics.h; the initial default is - // HAL_PIXEL_FORMAT_RGBA_8888. - status_t setDefaultBufferFormat(uint32_t defaultFormat); - // Gets the next graphics buffer from the producer and locks it for CPU use, // filling out the passed-in locked buffer structure with the native pointer // and metadata. Returns BAD_VALUE if no new buffer is available, and @@ -110,9 +99,9 @@ class CpuConsumer : public ConsumerBase private: // Maximum number of buffers that can be locked at a time - uint32_t mMaxLockedBuffers; + size_t mMaxLockedBuffers; - status_t releaseAcquiredBufferLocked(int lockedIdx); + status_t releaseAcquiredBufferLocked(size_t lockedIdx); virtual void freeBufferLocked(int slotIndex); @@ -133,7 +122,7 @@ class CpuConsumer : public ConsumerBase Vector<AcquiredBuffer> mAcquiredBuffers; // Count of currently locked buffers - uint32_t mCurrentLockedBuffers; + size_t mCurrentLockedBuffers; }; diff --git a/include/gui/GLConsumer.h b/include/gui/GLConsumer.h index f91fe46d93..c35c7be064 100644 --- a/include/gui/GLConsumer.h +++ b/include/gui/GLConsumer.h @@ -150,7 +150,7 @@ public: // // The frame number is an incrementing counter set to 0 at the creation of // the BufferQueue associated with this consumer. - int64_t getFrameNumber(); + uint64_t getFrameNumber(); // setDefaultBufferSize is used to set the size of buffers returned by // requestBuffers when a with and height of zero is requested. @@ -197,7 +197,8 @@ public: // These functions call the corresponding BufferQueue implementation // so the refactoring can proceed smoothly - status_t setDefaultBufferFormat(uint32_t defaultFormat); + status_t setDefaultBufferFormat(PixelFormat defaultFormat); + status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace); status_t setConsumerUsageBits(uint32_t usage); status_t setTransformHint(uint32_t hint); @@ -240,8 +241,8 @@ protected: // acquireBufferLocked overrides the ConsumerBase method to update the // mEglSlots array in addition to the ConsumerBase behavior. - virtual status_t acquireBufferLocked(BufferQueue::BufferItem *item, - nsecs_t presentWhen); + virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen, + uint64_t maxFrameNumber = 0) override; // releaseBufferLocked overrides the ConsumerBase method to update the // mEglSlots array in addition to the ConsumerBase. @@ -254,12 +255,12 @@ protected: return releaseBufferLocked(slot, graphicBuffer, mEglDisplay, eglFence); } - static bool isExternalFormat(uint32_t format); + static bool isExternalFormat(PixelFormat format); // This releases the buffer in the slot referenced by mCurrentTexture, // then updates state to refer to the BufferItem, which must be a // newly-acquired buffer. - status_t updateAndReleaseLocked(const BufferQueue::BufferItem& item); + status_t updateAndReleaseLocked(const BufferItem& item); // Binds mTexName and the current buffer to mTexTarget. Uses // mCurrentTexture if it's set, mCurrentTextureImage if not. If the @@ -391,7 +392,7 @@ private: // mCurrentFrameNumber is the frame counter for the current texture. // It gets set each time updateTexImage is called. - int64_t mCurrentFrameNumber; + uint64_t mCurrentFrameNumber; uint32_t mDefaultWidth, mDefaultHeight; diff --git a/include/gui/GraphicBufferAlloc.h b/include/gui/GraphicBufferAlloc.h index b08750c2fb..69fe51ef93 100644 --- a/include/gui/GraphicBufferAlloc.h +++ b/include/gui/GraphicBufferAlloc.h @@ -33,8 +33,9 @@ class GraphicBufferAlloc : public BnGraphicBufferAlloc { public: GraphicBufferAlloc(); virtual ~GraphicBufferAlloc(); - virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h, - PixelFormat format, uint32_t usage, status_t* error); + virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t width, + uint32_t height, PixelFormat format, uint32_t usage, + status_t* error); }; diff --git a/include/gui/IGraphicBufferAlloc.h b/include/gui/IGraphicBufferAlloc.h index cee41d9341..f3c46ec2ed 100644 --- a/include/gui/IGraphicBufferAlloc.h +++ b/include/gui/IGraphicBufferAlloc.h @@ -45,10 +45,10 @@ public: class BnGraphicBufferAlloc : public BnInterface<IGraphicBufferAlloc> { public: - virtual status_t onTransact( uint32_t code, - const Parcel& data, - Parcel* reply, - uint32_t flags = 0); + virtual status_t onTransact(uint32_t code, + const Parcel& data, + Parcel* reply, + uint32_t flags = 0); }; // ---------------------------------------------------------------------------- diff --git a/include/gui/IGraphicBufferConsumer.h b/include/gui/IGraphicBufferConsumer.h index 15f51fe8c0..60ec9cc0e9 100644 --- a/include/gui/IGraphicBufferConsumer.h +++ b/include/gui/IGraphicBufferConsumer.h @@ -25,6 +25,7 @@ #include <utils/Timers.h> #include <binder/IInterface.h> +#include <ui/PixelFormat.h> #include <ui/Rect.h> #include <EGL/egl.h> @@ -33,6 +34,7 @@ namespace android { // ---------------------------------------------------------------------------- +class BufferItem; class Fence; class GraphicBuffer; class IConsumerListener; @@ -41,71 +43,6 @@ class NativeHandle; class IGraphicBufferConsumer : public IInterface { public: - - // public facing structure for BufferSlot - class BufferItem : public Flattenable<BufferItem> { - friend class Flattenable<BufferItem>; - size_t getPodSize() const; - size_t getFlattenedSize() const; - size_t getFdCount() const; - status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const; - status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count); - - public: - // The default value of mBuf, used to indicate this doesn't correspond to a slot. - enum { INVALID_BUFFER_SLOT = -1 }; - BufferItem(); - - // mGraphicBuffer points to the buffer allocated for this slot, or is NULL - // if the buffer in this slot has been acquired in the past (see - // BufferSlot.mAcquireCalled). - sp<GraphicBuffer> mGraphicBuffer; - - // mFence is a fence that will signal when the buffer is idle. - sp<Fence> mFence; - - // mCrop is the current crop rectangle for this buffer slot. - Rect mCrop; - - // mTransform is the current transform flags for this buffer slot. - // refer to NATIVE_WINDOW_TRANSFORM_* in <window.h> - uint32_t mTransform; - - // mScalingMode is the current scaling mode for this buffer slot. - // refer to NATIVE_WINDOW_SCALING_* in <window.h> - uint32_t mScalingMode; - - // mTimestamp is the current timestamp for this buffer slot. This gets - // to set by queueBuffer each time this slot is queued. This value - // is guaranteed to be monotonically increasing for each newly - // acquired buffer. - int64_t mTimestamp; - - // mIsAutoTimestamp indicates whether mTimestamp was generated - // automatically when the buffer was queued. - bool mIsAutoTimestamp; - - // mFrameNumber is the number of the queued frame for this slot. - uint64_t mFrameNumber; - - // mBuf is the slot index of this buffer (default INVALID_BUFFER_SLOT). - int mBuf; - - // mIsDroppable whether this buffer was queued with the - // property that it can be replaced by a new buffer for the purpose of - // making sure dequeueBuffer() won't block. - // i.e.: was the BufferQueue in "mDequeueBufferCannotBlock" when this buffer - // was queued. - bool mIsDroppable; - - // Indicates whether this buffer has been seen by a consumer yet - bool mAcquireCalled; - - // Indicates this buffer must be transformed by the inverse transform of the screen - // it is displayed onto. This is applied after mTransform. - bool mTransformToDisplayInverse; - }; - enum { // Returned by releaseBuffer, after which the consumer must // free any references to the just-released buffer that it might have. @@ -132,6 +69,12 @@ public: // returned. The presentation time is in nanoseconds, and the time base // is CLOCK_MONOTONIC. // + // If maxFrameNumber is non-zero, it indicates that acquireBuffer should + // only return a buffer with a frame number less than or equal to + // maxFrameNumber. If no such frame is available (such as when a buffer has + // been replaced but the consumer has not received the onFrameReplaced + // callback), then PRESENT_LATER will be returned. + // // Return of NO_ERROR means the operation completed as normal. // // Return of a positive value means the operation could not be completed @@ -141,7 +84,8 @@ public: // // Return of a negative value means an error has occurred: // * INVALID_OPERATION - too many buffers have been acquired - virtual status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen) = 0; + virtual status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen, + uint64_t maxFrameNumber = 0) = 0; // detachBuffer attempts to remove all ownership of the buffer in the given // slot from the buffer queue. If this call succeeds, the slot will be @@ -166,7 +110,8 @@ public: // will be deallocated as stale. // // Return of a value other than NO_ERROR means an error has occurred: - // * BAD_VALUE - outSlot or buffer were NULL + // * BAD_VALUE - outSlot or buffer were NULL, or the generation number of + // the buffer did not match the buffer queue. // * INVALID_OPERATION - cannot attach the buffer because it would cause too // many buffers to be acquired. // * NO_MEMORY - no free slots available @@ -280,11 +225,19 @@ public: // setDefaultBufferFormat allows the BufferQueue to create // GraphicBuffers of a defaultFormat if no format is specified - // in dequeueBuffer. Formats are enumerated in graphics.h; the - // initial default is HAL_PIXEL_FORMAT_RGBA_8888. + // in dequeueBuffer. + // The initial default is PIXEL_FORMAT_RGBA_8888. + // + // Return of a value other than NO_ERROR means an unknown error has occurred. + virtual status_t setDefaultBufferFormat(PixelFormat defaultFormat) = 0; + + // setDefaultBufferDataSpace is a request to the producer to provide buffers + // of the indicated dataSpace. The producer may ignore this request. + // The initial default is HAL_DATASPACE_UNKNOWN. // // Return of a value other than NO_ERROR means an unknown error has occurred. - virtual status_t setDefaultBufferFormat(uint32_t defaultFormat) = 0; + virtual status_t setDefaultBufferDataSpace( + android_dataspace defaultDataSpace) = 0; // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer. // These are merged with the bits passed to dequeueBuffer. The values are diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h index 4e9e810701..9530de1aa8 100644 --- a/include/gui/IGraphicBufferProducer.h +++ b/include/gui/IGraphicBufferProducer.h @@ -28,6 +28,7 @@ #include <ui/Fence.h> #include <ui/GraphicBuffer.h> #include <ui/Rect.h> +#include <ui/Region.h> namespace android { // ---------------------------------------------------------------------------- @@ -134,9 +135,7 @@ public: // updateTexImage() is called. If width and height are both zero, the // default values specified by setDefaultBufferSize() are used instead. // - // The pixel formats are enumerated in <graphics.h>, e.g. - // HAL_PIXEL_FORMAT_RGBA_8888. If the format is 0, the default format - // will be used. + // If the format is 0, the default format will be used. // // The usage argument specifies gralloc buffer usage flags. The values // are enumerated in <gralloc.h>, e.g. GRALLOC_USAGE_HW_RENDER. These @@ -167,7 +166,7 @@ public: // All other negative values are an unknown error returned downstream // from the graphics allocator (typically errno). virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, bool async, - uint32_t w, uint32_t h, uint32_t format, uint32_t usage) = 0; + uint32_t w, uint32_t h, PixelFormat format, uint32_t usage) = 0; // detachBuffer attempts to remove all ownership of the buffer in the given // slot from the buffer queue. If this call succeeds, the slot will be @@ -219,8 +218,9 @@ public: // // Return of a negative value means an error has occurred: // * NO_INIT - the buffer queue has been abandoned. - // * BAD_VALUE - outSlot or buffer were NULL or invalid combination of - // async mode and buffer count override. + // * BAD_VALUE - outSlot or buffer were NULL, invalid combination of + // async mode and buffer count override, or the generation + // number of the buffer did not match the buffer queue. // * INVALID_OPERATION - cannot attach the buffer because it would cause // too many buffers to be dequeued, either because // the producer already has a single buffer dequeued @@ -267,6 +267,7 @@ public: inline QueueBufferInput(const Parcel& parcel); // timestamp - a monotonically increasing value in nanoseconds // isAutoTimestamp - if the timestamp was synthesized at queue time + // dataSpace - description of the contents, interpretation depends on format // crop - a crop rectangle that's used as a hint to the consumer // scalingMode - a set of flags from NATIVE_WINDOW_SCALING_* in <window.h> // transform - a set of flags from NATIVE_WINDOW_TRANSFORM_* in <window.h> @@ -276,17 +277,21 @@ public: // sticky - the sticky transform set in Surface (only used by the LEGACY // camera mode). inline QueueBufferInput(int64_t timestamp, bool isAutoTimestamp, - const Rect& crop, int scalingMode, uint32_t transform, bool async, - const sp<Fence>& fence, uint32_t sticky = 0) - : timestamp(timestamp), isAutoTimestamp(isAutoTimestamp), crop(crop), - scalingMode(scalingMode), transform(transform), stickyTransform(sticky), - async(async), fence(fence) { } + android_dataspace dataSpace, const Rect& crop, int scalingMode, + uint32_t transform, bool async, const sp<Fence>& fence, + uint32_t sticky = 0) + : timestamp(timestamp), isAutoTimestamp(isAutoTimestamp), + dataSpace(dataSpace), crop(crop), scalingMode(scalingMode), + transform(transform), stickyTransform(sticky), + async(async), fence(fence), surfaceDamage() { } inline void deflate(int64_t* outTimestamp, bool* outIsAutoTimestamp, - Rect* outCrop, int* outScalingMode, uint32_t* outTransform, - bool* outAsync, sp<Fence>* outFence, + android_dataspace* outDataSpace, + Rect* outCrop, int* outScalingMode, + uint32_t* outTransform, bool* outAsync, sp<Fence>* outFence, uint32_t* outStickyTransform = NULL) const { *outTimestamp = timestamp; *outIsAutoTimestamp = bool(isAutoTimestamp); + *outDataSpace = dataSpace; *outCrop = crop; *outScalingMode = scalingMode; *outTransform = transform; @@ -303,15 +308,20 @@ public: status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const; status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count); + const Region& getSurfaceDamage() const { return surfaceDamage; } + void setSurfaceDamage(const Region& damage) { surfaceDamage = damage; } + private: int64_t timestamp; int isAutoTimestamp; + android_dataspace dataSpace; Rect crop; int scalingMode; uint32_t transform; uint32_t stickyTransform; int async; sp<Fence> fence; + Region surfaceDamage; }; // QueueBufferOutput must be a POD structure @@ -448,7 +458,31 @@ public: // dequeueBuffer. If there are already the maximum number of buffers // allocated, this function has no effect. virtual void allocateBuffers(bool async, uint32_t width, uint32_t height, - uint32_t format, uint32_t usage) = 0; + PixelFormat format, uint32_t usage) = 0; + + // Sets whether dequeueBuffer is allowed to allocate new buffers. + // + // Normally dequeueBuffer does not discriminate between free slots which + // already have an allocated buffer and those which do not, and will + // allocate a new buffer if the slot doesn't have a buffer or if the slot's + // buffer doesn't match the requested size, format, or usage. This method + // allows the producer to restrict the eligible slots to those which already + // have an allocated buffer of the correct size, format, and usage. If no + // eligible slot is available, dequeueBuffer will block or return an error + // as usual. + virtual status_t allowAllocation(bool allow) = 0; + + // Sets the current generation number of the BufferQueue. + // + // This generation number will be inserted into any buffers allocated by the + // BufferQueue, and any attempts to attach a buffer with a different + // generation number will fail. Buffers already in the queue are not + // affected and will retain their current generation number. The generation + // number defaults to 0. + virtual status_t setGenerationNumber(uint32_t generationNumber) = 0; + + // Returns the name of the connected consumer. + virtual String8 getConsumerName() const = 0; }; // ---------------------------------------------------------------------------- diff --git a/include/gui/ISensorServer.h b/include/gui/ISensorServer.h index 9c8afc5a08..3dca2a3739 100644 --- a/include/gui/ISensorServer.h +++ b/include/gui/ISensorServer.h @@ -30,14 +30,17 @@ namespace android { class Sensor; class ISensorEventConnection; +class String8; class ISensorServer : public IInterface { public: DECLARE_META_INTERFACE(SensorServer); - virtual Vector<Sensor> getSensorList() = 0; - virtual sp<ISensorEventConnection> createSensorEventConnection() = 0; + virtual Vector<Sensor> getSensorList(const String16& opPackageName) = 0; + virtual sp<ISensorEventConnection> createSensorEventConnection(const String8& packageName, + int mode, const String16& opPackageName) = 0; + virtual int32_t isDataInjectionEnabled() = 0; }; // ---------------------------------------------------------------------------- diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h index 51717a412e..8c3d49e64e 100644 --- a/include/gui/ISurfaceComposer.h +++ b/include/gui/ISurfaceComposer.h @@ -28,7 +28,6 @@ #include <binder/IInterface.h> #include <ui/FrameStats.h> -#include <ui/PixelFormat.h> #include <gui/IGraphicBufferAlloc.h> #include <gui/ISurfaceComposerClient.h> @@ -39,7 +38,7 @@ namespace android { class ComposerState; class DisplayState; struct DisplayInfo; -class DisplayStatInfo; +struct DisplayStatInfo; class IDisplayEventConnection; class IMemoryHeap; class Rect; diff --git a/include/gui/Sensor.h b/include/gui/Sensor.h index 28a08e2238..8142be6352 100644 --- a/include/gui/Sensor.h +++ b/include/gui/Sensor.h @@ -67,12 +67,14 @@ public: int32_t getMinDelay() const; nsecs_t getMinDelayNs() const; int32_t getVersion() const; - int32_t getFifoReservedEventCount() const; - int32_t getFifoMaxEventCount() const; + uint32_t getFifoReservedEventCount() const; + uint32_t getFifoMaxEventCount() const; const String8& getStringType() const; const String8& getRequiredPermission() const; + bool isRequiredPermissionRuntime() const; + int32_t getRequiredAppOp() const; int32_t getMaxDelay() const; - int32_t getFlags() const; + uint32_t getFlags() const; bool isWakeUpSensor() const; int32_t getReportingMode() const; @@ -93,12 +95,14 @@ private: float mPower; int32_t mMinDelay; int32_t mVersion; - int32_t mFifoReservedEventCount; - int32_t mFifoMaxEventCount; + uint32_t mFifoReservedEventCount; + uint32_t mFifoMaxEventCount; String8 mStringType; String8 mRequiredPermission; + bool mRequiredPermissionRuntime = false; + int32_t mRequiredAppOp; int32_t mMaxDelay; - int32_t mFlags; + uint32_t mFlags; static void flattenString8(void*& buffer, size_t& size, const String8& string8); static bool unflattenString8(void const*& buffer, size_t& size, String8& outputString8); }; diff --git a/include/gui/SensorEventQueue.h b/include/gui/SensorEventQueue.h index 02b3d385bc..e5b9fc5984 100644 --- a/include/gui/SensorEventQueue.h +++ b/include/gui/SensorEventQueue.h @@ -23,6 +23,7 @@ #include <utils/Errors.h> #include <utils/RefBase.h> #include <utils/Timers.h> +#include <utils/String16.h> #include <gui/BitTube.h> @@ -52,7 +53,7 @@ public: enum { MAX_RECEIVE_BUFFER_EVENT_COUNT = 256 }; - SensorEventQueue(const sp<ISensorEventConnection>& connection); + SensorEventQueue(const sp<ISensorEventConnection>& connection); virtual ~SensorEventQueue(); virtual void onFirstRef(); @@ -77,6 +78,8 @@ public: status_t flush() const; // Send an ack for every wake_up sensor event that is set to WAKE_UP_SENSOR_EVENT_NEEDS_ACK. void sendAck(const ASensorEvent* events, int count); + + status_t injectSensorEvent(const ASensorEvent& event); private: sp<Looper> getLooper() const; sp<ISensorEventConnection> mSensorEventConnection; diff --git a/include/gui/SensorManager.h b/include/gui/SensorManager.h index 3176462db6..37960673cc 100644 --- a/include/gui/SensorManager.h +++ b/include/gui/SensorManager.h @@ -17,15 +17,20 @@ #ifndef ANDROID_GUI_SENSOR_MANAGER_H #define ANDROID_GUI_SENSOR_MANAGER_H +#include <map> + #include <stdint.h> #include <sys/types.h> #include <binder/IBinder.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> #include <utils/Errors.h> #include <utils/RefBase.h> #include <utils/Singleton.h> #include <utils/Vector.h> +#include <utils/String8.h> #include <gui/SensorEventQueue.h> @@ -40,20 +45,69 @@ namespace android { class ISensorServer; class Sensor; class SensorEventQueue; - // ---------------------------------------------------------------------------- class SensorManager : - public ASensorManager, - public Singleton<SensorManager> + public ASensorManager { public: - SensorManager(); + static SensorManager& getInstanceForPackage(const String16& packageName) { + Mutex::Autolock _l(sLock); + + SensorManager* sensorManager; + std::map<String16, SensorManager*>::iterator iterator = + sPackageInstances.find(packageName); + + if (iterator != sPackageInstances.end()) { + sensorManager = iterator->second; + } else { + String16 opPackageName = packageName; + + // It is possible that the calling code has no access to the package name. + // In this case we will get the packages for the calling UID and pick the + // first one for attributing the app op. This will work correctly for + // runtime permissions as for legacy apps we will toggle the app op for + // all packages in the UID. The caveat is that the operation may be attributed + // to the wrong package and stats based on app ops may be slightly off. + if (opPackageName.size() <= 0) { + sp<IBinder> binder = defaultServiceManager()->getService(String16("permission")); + if (binder != 0) { + const uid_t uid = IPCThreadState::self()->getCallingUid(); + Vector<String16> packages; + interface_cast<IPermissionController>(binder)->getPackagesForUid(uid, packages); + if (!packages.isEmpty()) { + opPackageName = packages[0]; + } else { + ALOGE("No packages for calling UID"); + } + } else { + ALOGE("Cannot get permission service"); + } + } + + sensorManager = new SensorManager(opPackageName); + + // If we had no package name, we looked it up from the UID and the sensor + // manager instance we created should also be mapped to the empty package + // name, to avoid looking up the packages for a UID and get the same result. + if (packageName.size() <= 0) { + sPackageInstances.insert(std::make_pair(String16(), sensorManager)); + } + + // Stash the per package sensor manager. + sPackageInstances.insert(std::make_pair(opPackageName, sensorManager)); + } + + return *sensorManager; + } + + SensorManager(const String16& opPackageName); ~SensorManager(); ssize_t getSensorList(Sensor const* const** list) const; Sensor const* getDefaultSensor(int type); - sp<SensorEventQueue> createEventQueue(); + sp<SensorEventQueue> createEventQueue(String8 packageName = String8(""), int mode = 0); + bool isDataInjectionEnabled(); private: // DeathRecipient interface @@ -62,11 +116,15 @@ private: status_t assertStateLocked() const; private: + static Mutex sLock; + static std::map<String16, SensorManager*> sPackageInstances; + mutable Mutex mLock; mutable sp<ISensorServer> mSensorServer; mutable Sensor const** mSensorList; mutable Vector<Sensor> mSensors; mutable sp<IBinder::DeathRecipient> mDeathObserver; + const String16 mOpPackageName; }; // ---------------------------------------------------------------------------- diff --git a/include/gui/Surface.h b/include/gui/Surface.h index f2cf018a9f..72f1067076 100644 --- a/include/gui/Surface.h +++ b/include/gui/Surface.h @@ -101,6 +101,14 @@ public: */ void allocateBuffers(); + /* Sets the generation number on the IGraphicBufferProducer and updates the + * generation number on any buffers attached to the Surface after this call. + * See IGBP::setGenerationNumber for more information. */ + status_t setGenerationNumber(uint32_t generationNumber); + + // See IGraphicBufferProducer::getConsumerName + String8 getConsumerName() const; + protected: virtual ~Surface(); @@ -146,6 +154,8 @@ private: int dispatchLock(va_list args); int dispatchUnlockAndPost(va_list args); int dispatchSetSidebandStream(va_list args); + int dispatchSetBuffersDataSpace(va_list args); + int dispatchSetSurfaceDamage(va_list args); protected: virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd); @@ -160,20 +170,27 @@ protected: virtual int connect(int api); virtual int disconnect(int api); virtual int setBufferCount(int bufferCount); - virtual int setBuffersDimensions(int w, int h); - virtual int setBuffersUserDimensions(int w, int h); - virtual int setBuffersFormat(int format); + virtual int setBuffersDimensions(uint32_t width, uint32_t height); + virtual int setBuffersUserDimensions(uint32_t width, uint32_t height); + virtual int setBuffersFormat(PixelFormat format); virtual int setScalingMode(int mode); - virtual int setBuffersTransform(int transform); - virtual int setBuffersStickyTransform(int transform); + virtual int setBuffersTransform(uint32_t transform); + virtual int setBuffersStickyTransform(uint32_t transform); virtual int setBuffersTimestamp(int64_t timestamp); + virtual int setBuffersDataSpace(android_dataspace dataSpace); virtual int setCrop(Rect const* rect); virtual int setUsage(uint32_t reqUsage); + virtual void setSurfaceDamage(android_native_rect_t* rects, size_t numRects); public: virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds); virtual int unlockAndPost(); + virtual int connect(int api, const sp<IProducerListener>& listener); + virtual int detachNextBuffer(sp<GraphicBuffer>* outBuffer, + sp<Fence>* outFence); + virtual int attachBuffer(ANativeWindowBuffer*); + protected: enum { NUM_BUFFER_SLOTS = BufferQueue::NUM_BUFFER_SLOTS }; enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 }; @@ -211,7 +228,7 @@ private: // mReqFormat is the buffer pixel format that will be requested at the next // deuque operation. It is initialized to PIXEL_FORMAT_RGBA_8888. - uint32_t mReqFormat; + PixelFormat mReqFormat; // mReqUsage is the set of buffer usage flags that will be requested // at the next deuque operation. It is initialized to 0. @@ -222,6 +239,11 @@ private: // a timestamp is auto-generated when queueBuffer is called. int64_t mTimestamp; + // mDataSpace is the buffer dataSpace that will be used for the next buffer + // queue operation. It defaults to HAL_DATASPACE_UNKNOWN, which + // means that the buffer contains some type of color data. + android_dataspace mDataSpace; + // mCrop is the crop rectangle that will be used for the next buffer // that gets queued. It is set by calling setCrop. Rect mCrop; @@ -240,23 +262,23 @@ private: // from being set by the compositor. uint32_t mStickyTransform; - // mDefaultWidth is default width of the buffers, regardless of the - // native_window_set_buffers_dimensions call. - uint32_t mDefaultWidth; + // mDefaultWidth is default width of the buffers, regardless of the + // native_window_set_buffers_dimensions call. + uint32_t mDefaultWidth; - // mDefaultHeight is default height of the buffers, regardless of the - // native_window_set_buffers_dimensions call. - uint32_t mDefaultHeight; + // mDefaultHeight is default height of the buffers, regardless of the + // native_window_set_buffers_dimensions call. + uint32_t mDefaultHeight; - // mUserWidth, if non-zero, is an application-specified override - // of mDefaultWidth. This is lower priority than the width set by - // native_window_set_buffers_dimensions. - uint32_t mUserWidth; + // mUserWidth, if non-zero, is an application-specified override + // of mDefaultWidth. This is lower priority than the width set by + // native_window_set_buffers_dimensions. + uint32_t mUserWidth; - // mUserHeight, if non-zero, is an application-specified override - // of mDefaultHeight. This is lower priority than the height set - // by native_window_set_buffers_dimensions. - uint32_t mUserHeight; + // mUserHeight, if non-zero, is an application-specified override + // of mDefaultHeight. This is lower priority than the height set + // by native_window_set_buffers_dimensions. + uint32_t mUserHeight; // mTransformHint is the transform probably applied to buffers of this // window. this is only a hint, actual transform may differ. @@ -284,8 +306,17 @@ private: sp<GraphicBuffer> mPostedBuffer; bool mConnectedToCpu; - // must be accessed from lock/unlock thread only + // When a CPU producer is attached, this reflects the region that the + // producer wished to update as well as whether the Surface was able to copy + // the previous buffer back to allow a partial update. + // + // When a non-CPU producer is attached, this reflects the surface damage + // (the change since the previous frame) passed in by the producer. Region mDirtyRegion; + + // Stores the current generation number. See setGenerationNumber and + // IGraphicBufferProducer::setGenerationNumber for more information. + uint32_t mGenerationNumber; }; }; // namespace android diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h index 4cbfc09951..37d953e18e 100644 --- a/include/gui/SurfaceComposerClient.h +++ b/include/gui/SurfaceComposerClient.h @@ -127,7 +127,7 @@ public: status_t show(const sp<IBinder>& id); status_t setFlags(const sp<IBinder>& id, uint32_t flags, uint32_t mask); status_t setTransparentRegionHint(const sp<IBinder>& id, const Region& transparent); - status_t setLayer(const sp<IBinder>& id, int32_t layer); + status_t setLayer(const sp<IBinder>& id, uint32_t layer); status_t setAlpha(const sp<IBinder>& id, float alpha=1.0f); status_t setMatrix(const sp<IBinder>& id, float dsdx, float dtdx, float dsdy, float dtdy); status_t setPosition(const sp<IBinder>& id, float x, float y); diff --git a/include/gui/SurfaceControl.h b/include/gui/SurfaceControl.h index 84fb9f999a..9f62f7c726 100644 --- a/include/gui/SurfaceControl.h +++ b/include/gui/SurfaceControl.h @@ -57,8 +57,8 @@ public: // release surface data from java void clear(); - status_t setLayerStack(int32_t layerStack); - status_t setLayer(int32_t layer); + status_t setLayerStack(uint32_t layerStack); + status_t setLayer(uint32_t layer); status_t setPosition(float x, float y); status_t setSize(uint32_t w, uint32_t h); status_t hide(); diff --git a/include/input/IInputFlinger.h b/include/input/IInputFlinger.h new file mode 100644 index 0000000000..629310ff2f --- /dev/null +++ b/include/input/IInputFlinger.h @@ -0,0 +1,52 @@ +/* + * 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. + */ + +#ifndef _LIBINPUT_IINPUT_FLINGER_H +#define _LIBINPUT_IINPUT_FLINGER_H + +#include <stdint.h> +#include <sys/types.h> + +#include <binder/IInterface.h> + +namespace android { + +/* + * This class defines the Binder IPC interface for accessing various + * InputFlinger features. + */ +class IInputFlinger : public IInterface { +public: + DECLARE_META_INTERFACE(InputFlinger); +}; + + +/** + * Binder implementation. + */ +class BnInputFlinger : public BnInterface<IInputFlinger> { +public: + enum { + DO_SOMETHING_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, + }; + + virtual status_t onTransact(uint32_t code, const Parcel& data, + Parcel* reply, uint32_t flags = 0); +}; + +} // namespace android + +#endif // _LIBINPUT_IINPUT_FLINGER_H diff --git a/include/input/Input.h b/include/input/Input.h index 09419c9a61..82fc6599a7 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -45,6 +45,19 @@ enum { }; enum { + + /** + * This flag indicates that the window that received this motion event is partly + * or wholly obscured by another visible window above it. This flag is set to true + * even if the event did not directly pass through the obscured area. + * A security sensitive application can check this flag to identify situations in which + * a malicious application may have covered up part of its content for the purpose + * of misleading the user or hijacking touches. An appropriate response might be + * to drop the suspect touches or to take additional precautions to confirm the user's + * actual intent. + */ + AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED = 0x2, + /* Motion event is inconsistent with previously sent motion events. */ AMOTION_EVENT_FLAG_TAINTED = 0x80000000, }; @@ -155,10 +168,22 @@ enum { * NOTE: If you want a flag to be able to set in a keylayout file, then you must add it to * InputEventLabels.h as well. */ + // Indicates that the event should wake the device. POLICY_FLAG_WAKE = 0x00000001, + + // Indicates that the key is virtual, such as a capacitive button, and should + // generate haptic feedback. Virtual keys may be suppressed for some time + // after a recent touch to prevent accidental activation of virtual keys adjacent + // to the touch screen during an edge swipe. POLICY_FLAG_VIRTUAL = 0x00000002, + + // Indicates that the key is the special function modifier. POLICY_FLAG_FUNCTION = 0x00000004, + // Indicates that the key represents a special gesture that has been detected by + // the touch firmware or driver. Causes touch events from the same device to be canceled. + POLICY_FLAG_GESTURE = 0x00000008, + POLICY_FLAG_RAW_MASK = 0x0000ffff, /* These flags are set by the input dispatcher. */ @@ -373,6 +398,12 @@ public: inline int32_t getButtonState() const { return mButtonState; } + inline int32_t setButtonState(int32_t buttonState) { mButtonState = buttonState; } + + inline int32_t getActionButton() const { return mActionButton; } + + inline void setActionButton(int32_t button) { mActionButton = button; } + inline float getXOffset() const { return mXOffset; } inline float getYOffset() const { return mYOffset; } @@ -526,6 +557,7 @@ public: int32_t deviceId, int32_t source, int32_t action, + int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, @@ -578,6 +610,7 @@ public: protected: int32_t mAction; + int32_t mActionButton; int32_t mFlags; int32_t mEdgeFlags; int32_t mMetaState; diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h index adf9fb9170..1ea69d352d 100644 --- a/include/input/InputDevice.h +++ b/include/input/InputDevice.h @@ -73,7 +73,8 @@ public: }; void initialize(int32_t id, int32_t generation, int32_t controllerNumber, - const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal); + const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal, + bool hasMic); inline int32_t getId() const { return mId; } inline int32_t getControllerNumber() const { return mControllerNumber; } @@ -84,6 +85,7 @@ public: return mAlias.isEmpty() ? mIdentifier.name : mAlias; } inline bool isExternal() const { return mIsExternal; } + inline bool hasMic() const { return mHasMic; } inline uint32_t getSources() const { return mSources; } const MotionRange* getMotionRange(int32_t axis, uint32_t source) const; @@ -121,6 +123,7 @@ private: InputDeviceIdentifier mIdentifier; String8 mAlias; bool mIsExternal; + bool mHasMic; uint32_t mSources; int32_t mKeyboardType; sp<KeyCharacterMap> mKeyCharacterMap; diff --git a/include/input/InputEventLabels.h b/include/input/InputEventLabels.h index df50237cd2..a7a93297f8 100644 --- a/include/input/InputEventLabels.h +++ b/include/input/InputEventLabels.h @@ -299,6 +299,14 @@ static const InputEventLabel KEYCODES[] = { DEFINE_KEYCODE(TV_MEDIA_CONTEXT_MENU), DEFINE_KEYCODE(TV_TIMER_PROGRAMMING), DEFINE_KEYCODE(HELP), + DEFINE_KEYCODE(NAVIGATE_PREVIOUS), + DEFINE_KEYCODE(NAVIGATE_NEXT), + DEFINE_KEYCODE(NAVIGATE_IN), + DEFINE_KEYCODE(NAVIGATE_OUT), + DEFINE_KEYCODE(MEDIA_SKIP_FORWARD), + DEFINE_KEYCODE(MEDIA_SKIP_BACKWARD), + DEFINE_KEYCODE(MEDIA_STEP_FORWARD), + DEFINE_KEYCODE(MEDIA_STEP_BACKWARD), { NULL, 0 } }; @@ -376,6 +384,7 @@ static const InputEventLabel LEDS[] = { static const InputEventLabel FLAGS[] = { DEFINE_FLAG(VIRTUAL), DEFINE_FLAG(FUNCTION), + DEFINE_FLAG(GESTURE), { NULL, 0 } }; diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index e7e383b48a..f31bceabd7 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -84,6 +84,7 @@ struct InputMessage { int32_t deviceId; int32_t source; int32_t action; + int32_t actionButton; int32_t flags; int32_t metaState; int32_t buttonState; @@ -95,7 +96,7 @@ struct InputMessage { float yPrecision; uint32_t pointerCount; // Note that PointerCoords requires 8 byte alignment. - struct Pointer{ + struct Pointer { PointerProperties properties; PointerCoords coords; } pointers[MAX_POINTERS]; @@ -232,6 +233,7 @@ public: int32_t deviceId, int32_t source, int32_t action, + int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, diff --git a/include/media/drm/DrmAPI.h b/include/media/drm/DrmAPI.h index 49939fda9b..272881b9f5 100644 --- a/include/media/drm/DrmAPI.h +++ b/include/media/drm/DrmAPI.h @@ -80,7 +80,10 @@ namespace android { kDrmPluginEventProvisionRequired = 1, kDrmPluginEventKeyNeeded, kDrmPluginEventKeyExpired, - kDrmPluginEventVendorDefined + kDrmPluginEventVendorDefined, + kDrmPluginEventSessionReclaimed, + kDrmPluginEventExpirationUpdate, + kDrmPluginEventKeysChange, }; // Drm keys can be for offline content or for online streaming. @@ -93,6 +96,33 @@ namespace android { kKeyType_Release }; + // Enumerate KeyRequestTypes to allow an app to determine the + // type of a key request returned from getKeyRequest. + enum KeyRequestType { + kKeyRequestType_Unknown, + kKeyRequestType_Initial, + kKeyRequestType_Renewal, + kKeyRequestType_Release + }; + + // Enumerate KeyStatusTypes which indicate the state of a key + enum KeyStatusType + { + kKeyStatusType_Usable, + kKeyStatusType_Expired, + kKeyStatusType_OutputNotAllowed, + kKeyStatusType_StatusPending, + kKeyStatusType_InternalError + }; + + // Used by sendKeysChange to report the usability status of each + // key to the app. + struct KeyStatus + { + Vector<uint8_t> mKeyId; + KeyStatusType mType; + }; + DrmPlugin() {} virtual ~DrmPlugin() {} @@ -135,7 +165,8 @@ namespace android { Vector<uint8_t> const &initData, String8 const &mimeType, KeyType keyType, KeyedVector<String8, String8> const &optionalParameters, - Vector<uint8_t> &request, String8 &defaultUrl) = 0; + Vector<uint8_t> &request, String8 &defaultUrl, + KeyRequestType *keyRequestType) = 0; // // After a key response is received by the app, it is provided to the @@ -315,11 +346,18 @@ namespace android { } protected: - // Plugins call sendEvent to deliver events to the java app + // Plugins call these methods to deliver events to the java app void sendEvent(EventType eventType, int extra, Vector<uint8_t> const *sessionId, Vector<uint8_t> const *data); + void sendExpirationUpdate(Vector<uint8_t> const *sessionId, + int64_t expiryTimeInMS); + + void sendKeysChange(Vector<uint8_t> const *sessionId, + Vector<DrmPlugin::KeyStatus> const *keyStatusList, + bool hasNewUsableKey); + private: Mutex mEventLock; sp<DrmPluginListener> mListener; @@ -331,14 +369,20 @@ namespace android { { public: virtual void sendEvent(DrmPlugin::EventType eventType, int extra, - Vector<uint8_t> const *sesionId, + Vector<uint8_t> const *sessionId, Vector<uint8_t> const *data) = 0; + + virtual void sendExpirationUpdate(Vector<uint8_t> const *sessionId, + int64_t expiryTimeInMS) = 0; + + virtual void sendKeysChange(Vector<uint8_t> const *sessionId, + Vector<DrmPlugin::KeyStatus> const *keyStatusList, + bool hasNewUsableKey) = 0; }; inline void DrmPlugin::sendEvent(EventType eventType, int extra, Vector<uint8_t> const *sessionId, Vector<uint8_t> const *data) { - mEventLock.lock(); sp<DrmPluginListener> listener = mListener; mEventLock.unlock(); @@ -348,6 +392,28 @@ namespace android { } } + inline void DrmPlugin::sendExpirationUpdate(Vector<uint8_t> const *sessionId, + int64_t expiryTimeInMS) { + mEventLock.lock(); + sp<DrmPluginListener> listener = mListener; + mEventLock.unlock(); + + if (listener != NULL) { + listener->sendExpirationUpdate(sessionId, expiryTimeInMS); + } + } + + inline void DrmPlugin::sendKeysChange(Vector<uint8_t> const *sessionId, + Vector<DrmPlugin::KeyStatus> const *keyStatusList, + bool hasNewUsableKey) { + mEventLock.lock(); + sp<DrmPluginListener> listener = mListener; + mEventLock.unlock(); + + if (listener != NULL) { + listener->sendKeysChange(sessionId, keyStatusList, hasNewUsableKey); + } + } } // namespace android #endif // DRM_API_H_ diff --git a/include/media/hardware/CryptoAPI.h b/include/media/hardware/CryptoAPI.h index c800825a36..3e3257f956 100644 --- a/include/media/hardware/CryptoAPI.h +++ b/include/media/hardware/CryptoAPI.h @@ -14,7 +14,9 @@ * limitations under the License. */ +#include <media/stagefright/MediaErrors.h> #include <utils/Errors.h> +#include <utils/Vector.h> #ifndef CRYPTO_API_H_ @@ -68,7 +70,18 @@ struct CryptoPlugin { // the resolution of the video being decrypted. The media player should // call this method when the resolution is determined and any time it // is subsequently changed. - virtual void notifyResolution(uint32_t width, uint32_t height) {} + + virtual void notifyResolution(uint32_t /* width */, uint32_t /* height */) {} + + // A MediaDrm session may be associated with a MediaCrypto session. The + // associated MediaDrm session is used to load decryption keys + // into the crypto/drm plugin. The keys are then referenced by key-id + // in the 'key' parameter to the decrypt() method. + // Should return NO_ERROR on success, ERROR_DRM_SESSION_NOT_OPENED if + // the session is not opened and a code from MediaErrors.h otherwise. + virtual status_t setMediaDrmSession(const Vector<uint8_t> & /*sessionId */) { + return ERROR_UNSUPPORTED; + } // If the error returned falls into the range // ERROR_DRM_VENDOR_MIN..ERROR_DRM_VENDOR_MAX, errorDetailMsg should be diff --git a/include/media/hardware/HardwareAPI.h b/include/media/hardware/HardwareAPI.h index d5f42befe6..1008c22d73 100644 --- a/include/media/hardware/HardwareAPI.h +++ b/include/media/hardware/HardwareAPI.h @@ -52,9 +52,9 @@ struct EnableAndroidNativeBuffersParams { OMX_BOOL enable; }; -// A pointer to this struct is passed to OMX_SetParameter() when the extension -// index "OMX.google.android.index.storeMetaDataInBuffers" -// is given. +// A pointer to this struct is passed to OMX_SetParameter() when the extension index +// "OMX.google.android.index.storeMetaDataInBuffers" or +// "OMX.google.android.index.storeANWBufferInMetadata" is given. // // When meta data is stored in the video buffers passed between OMX clients // and OMX components, interpretation of the buffer data is up to the @@ -62,19 +62,33 @@ struct EnableAndroidNativeBuffersParams { // some information helpful for the receiver to locate the actual data. // The buffer receiver thus needs to know how to interpret what is stored // in these buffers, with mechanisms pre-determined externally. How to -// interpret the meta data is outside of the scope of this method. +// interpret the meta data is outside of the scope of this parameter. +// +// Currently, this is used to pass meta data from video source (camera component, for instance) to +// video encoder to avoid memcpying of input video frame data, as well as to pass dynamic output +// buffer to video decoder. To do this, bStoreMetaData is set to OMX_TRUE. +// +// If bStoreMetaData is set to false, real YUV frame data will be stored in input buffers, and +// the output buffers contain either real YUV frame data, or are themselves native handles as +// directed by enable/use-android-native-buffer parameter settings. +// In addition, if no OMX_SetParameter() call is made on a port with the corresponding extension +// index, the component should not assume that the client is not using metadata mode for the port. // -// Currently, this is specifically used to pass meta data from video source -// (camera component, for instance) to video encoder to avoid memcpying of -// input video frame data. To do this, bStoreMetaData is set to OMX_TRUE. -// If bStoreMetaData is set to false, real YUV frame data will be stored -// in the buffers. In addition, if no OMX_SetParameter() call is made -// with the corresponding extension index, real YUV data is stored -// in the buffers. +// If the component supports this using the "OMX.google.android.index.storeANWBufferInMetadata" +// extension and bStoreMetaData is set to OMX_TRUE, data is passed using the VideoNativeMetadata +// layout as defined below. Each buffer will be accompanied by a fence. The fence must signal +// before the buffer can be used (e.g. read from or written into). When returning such buffer to +// the client, component must provide a new fence that must signal before the returned buffer can +// be used (e.g. read from or written into). The component owns the incoming fenceFd, and must close +// it when fence has signaled. The client will own and close the returned fence file descriptor. // -// For video decoder output port, the metadata buffer layout is defined below. +// If the component supports this using the "OMX.google.android.index.storeMetaDataInBuffers" +// extension and bStoreMetaData is set to OMX_TRUE, data is passed using VideoGrallocMetadata +// (the layout of which is the VideoGrallocMetadata defined below). Camera input can be also passed +// as "CameraSource", the layout of which is vendor dependent. // -// Metadata buffers are registered with the component using UseBuffer calls. +// Metadata buffers are registered with the component using UseBuffer calls, or can be allocated +// by the component for encoder-metadata-output buffers. struct StoreMetaDataInBuffersParams { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; @@ -84,9 +98,26 @@ struct StoreMetaDataInBuffersParams { // Meta data buffer layout used to transport output frames to the decoder for // dynamic buffer handling. -struct VideoDecoderOutputMetaData { - MetadataBufferType eType; - buffer_handle_t pHandle; +struct VideoGrallocMetadata { + MetadataBufferType eType; // must be kMetadataBufferTypeGrallocSource +#ifdef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS + OMX_PTR pHandle; +#else + buffer_handle_t pHandle; +#endif +}; + +// Legacy name for VideoGrallocMetadata struct. +struct VideoDecoderOutputMetaData : public VideoGrallocMetadata {}; + +struct VideoNativeMetadata { + MetadataBufferType eType; // must be kMetadataBufferTypeANWBuffer +#ifdef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS + OMX_PTR pBuffer; +#else + struct ANativeWindowBuffer* pBuffer; +#endif + int nFenceFd; // -1 if unused }; // A pointer to this struct is passed to OMX_SetParameter() when the extension @@ -173,17 +204,17 @@ struct MediaImage { }; Type mType; - size_t mNumPlanes; // number of planes - size_t mWidth; // width of largest plane (unpadded, as in nFrameWidth) - size_t mHeight; // height of largest plane (unpadded, as in nFrameHeight) - size_t mBitDepth; // useable bit depth + uint32_t mNumPlanes; // number of planes + uint32_t mWidth; // width of largest plane (unpadded, as in nFrameWidth) + uint32_t mHeight; // height of largest plane (unpadded, as in nFrameHeight) + uint32_t mBitDepth; // useable bit depth struct PlaneInfo { - size_t mOffset; // offset of first pixel of the plane in bytes - // from buffer offset - size_t mColInc; // column increment in bytes - size_t mRowInc; // row increment in bytes - size_t mHorizSubsampling; // subsampling compared to the largest plane - size_t mVertSubsampling; // subsampling compared to the largest plane + uint32_t mOffset; // offset of first pixel of the plane in bytes + // from buffer offset + uint32_t mColInc; // column increment in bytes + uint32_t mRowInc; // row increment in bytes + uint32_t mHorizSubsampling; // subsampling compared to the largest plane + uint32_t mVertSubsampling; // subsampling compared to the largest plane }; PlaneInfo mPlane[MAX_NUM_PLANES]; }; diff --git a/include/media/hardware/MetadataBufferType.h b/include/media/hardware/MetadataBufferType.h index 5876c40f60..b765203956 100644 --- a/include/media/hardware/MetadataBufferType.h +++ b/include/media/hardware/MetadataBufferType.h @@ -77,28 +77,43 @@ typedef enum { * GRalloc buffer. The encoder needs to interpret this GRalloc handle * and encode the frames. * -------------------------------------------------------------- - * | kMetadataBufferTypeGrallocSource | sizeof(buffer_handle_t) | + * | kMetadataBufferTypeGrallocSource | buffer_handle_t buffer | * -------------------------------------------------------------- + * + * See the VideoGrallocMetadata structure. */ kMetadataBufferTypeGrallocSource = 1, /* * kMetadataBufferTypeGraphicBuffer is used to indicate that * the payload of the metadata buffers can be interpreted as - * a GraphicBuffer. It is only to be used by software encoders. - * In this case, the metadata that the encoder receives - * will have a byte stream that consists of two parts: + * an ANativeWindowBuffer, and that a fence is provided. + * + * In this case, the metadata will have a byte stream that consists of three parts: * 1. First, there is an integer indicating that the metadata - * contains a GraphicBuffer (kMetadataBufferTypeGraphicBuffer) - * 2. This is followed by the pointer to the GraphicBuffer that - * is to be encoded. Encoder must not create a sp<> from this - * graphic buffer, or free it, as it does not actually own this - * buffer. - * -------------------------------------------------------------- - * | kMetadataBufferTypeGraphicBuffer | sizeof(GraphicBuffer *) | - * -------------------------------------------------------------- + * contains an ANativeWindowBuffer (kMetadataBufferTypeANWBuffer) + * 2. This is followed by the pointer to the ANativeWindowBuffer. + * Codec must not free this buffer as it does not actually own this buffer. + * 3. Finally, there is an integer containing a fence file descriptor. + * The codec must wait on the fence before encoding or decoding into this + * buffer. When the buffer is returned, codec must replace this file descriptor + * with a new fence, that will be waited on before the buffer is replaced + * (encoder) or read (decoder). + * --------------------------------- + * | kMetadataBufferTypeANWBuffer | + * --------------------------------- + * | ANativeWindowBuffer *buffer | + * --------------------------------- + * | int fenceFd | + * --------------------------------- + * + * See the VideoNativeMetadata structure. */ - kMetadataBufferTypeGraphicBuffer = 2, + kMetadataBufferTypeANWBuffer = 2, + + /* This value is used by framework, but is never used inside a metadata buffer */ + kMetadataBufferTypeInvalid = -1, + // Add more here... diff --git a/include/media/openmax/OMX_AsString.h b/include/media/openmax/OMX_AsString.h index 0f177a1267..ae8430d856 100644 --- a/include/media/openmax/OMX_AsString.h +++ b/include/media/openmax/OMX_AsString.h @@ -287,6 +287,7 @@ inline static const char *asString(OMX_EVENTTYPE i, const char *def = "??") { // case OMX_EventComponentResumed: return "ComponentResumed"; // case OMX_EventDynamicResourcesAvailable: return "DynamicResourcesAvailable"; // case OMX_EventPortFormatDetected: return "PortFormatDetected"; + case OMX_EventOutputRendered: return "OutputRendered"; default: return def; } } @@ -521,6 +522,9 @@ inline static const char *asString(OMX_INDEXEXTTYPE i, const char *def = "??") { case OMX_IndexParamVideoHevc: return "ParamVideoHevc"; // case OMX_IndexParamSliceSegments: return "ParamSliceSegments"; case OMX_IndexConfigAutoFramerateConversion: return "ConfigAutoFramerateConversion"; + case OMX_IndexConfigPriority: return "ConfigPriority"; + case OMX_IndexConfigOperatingRate: return "ConfigOperatingRate"; + case OMX_IndexParamConsumerUsageBits: return "ParamConsumerUsageBits"; default: return asString((OMX_INDEXTYPE)i, def); } } diff --git a/include/media/openmax/OMX_Core.h b/include/media/openmax/OMX_Core.h index 12f2b3baff..f746a69d2a 100644 --- a/include/media/openmax/OMX_Core.h +++ b/include/media/openmax/OMX_Core.h @@ -503,12 +503,28 @@ typedef enum OMX_EVENTTYPE OMX_EventResourcesAcquired, /**< component has been granted resources and is automatically starting the state change from OMX_StateWaitForResources to OMX_StateIdle. */ - OMX_EventComponentResumed, /**< Component resumed due to reacquisition of resources */ - OMX_EventDynamicResourcesAvailable, /**< Component has acquired previously unavailable dynamic resources */ - OMX_EventPortFormatDetected, /**< Component has detected a supported format. */ - OMX_EventKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ - OMX_EventVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ - OMX_EventMax = 0x7FFFFFFF + OMX_EventComponentResumed, /**< Component resumed due to reacquisition of resources */ + OMX_EventDynamicResourcesAvailable, /**< Component has acquired previously unavailable dynamic resources */ + OMX_EventPortFormatDetected, /**< Component has detected a supported format. */ + OMX_EventKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ + OMX_EventVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ + + /** Event when tunneled decoder has rendered an output or reached EOS + * nData1 must contain the number of timestamps returned + * pEventData must point to an array of the OMX_VIDEO_RENDEREVENTTYPE structs containing the + * render-timestamps of each frame. Component may batch rendered timestamps using this event, + * but must signal the event no more than 40ms after the first frame in the batch. The frames + * must be ordered by system timestamp inside and across batches. + * + * If component is doing frame-rate conversion, it must signal the render time of each + * converted frame, and must interpolate media timestamps for in-between frames. + * + * When the component reached EOS, it must signal an EOS timestamp using the same mechanism. + * This is in addition to the timestamp of the last rendered frame, and should follow that + * frame. + */ + OMX_EventOutputRendered = 0x7F000001, + OMX_EventMax = 0x7FFFFFFF } OMX_EVENTTYPE; typedef struct OMX_CALLBACKTYPE diff --git a/include/media/openmax/OMX_IVCommon.h b/include/media/openmax/OMX_IVCommon.h index a5b9d18764..f9b6f4b0fd 100644 --- a/include/media/openmax/OMX_IVCommon.h +++ b/include/media/openmax/OMX_IVCommon.h @@ -157,6 +157,7 @@ typedef enum OMX_COLOR_FORMATTYPE { * an acceptable range once that is done. * */ OMX_COLOR_FormatAndroidOpaque = 0x7F000789, + OMX_COLOR_Format32BitRGBA8888 = 0x7F00A000, /** Flexible 8-bit YUV format. Codec should report this format * as being supported if it supports any YUV420 packed planar * or semiplanar formats. When port is set to use this format, diff --git a/include/media/openmax/OMX_IndexExt.h b/include/media/openmax/OMX_IndexExt.h index ea3d0dadbc..25bea1f9cc 100644 --- a/include/media/openmax/OMX_IndexExt.h +++ b/include/media/openmax/OMX_IndexExt.h @@ -83,6 +83,9 @@ typedef enum OMX_INDEXEXTTYPE { /* Other configurations */ OMX_IndexExtOtherStartUnused = OMX_IndexKhronosExtensions + 0x00800000, OMX_IndexConfigAutoFramerateConversion, /**< reference: OMX_CONFIG_BOOLEANTYPE */ + OMX_IndexConfigPriority, /**< reference: OMX_PARAM_U32TYPE */ + OMX_IndexConfigOperatingRate, /**< reference: OMX_PARAM_U32TYPE in Q16 format for video and in Hz for audio */ + OMX_IndexParamConsumerUsageBits, /**< reference: OMX_PARAM_U32TYPE */ /* Time configurations */ OMX_IndexExtTimeStartUnused = OMX_IndexKhronosExtensions + 0x00900000, diff --git a/include/media/openmax/OMX_VideoExt.h b/include/media/openmax/OMX_VideoExt.h index 3c97e14a7c..3971bc5cc3 100644 --- a/include/media/openmax/OMX_VideoExt.h +++ b/include/media/openmax/OMX_VideoExt.h @@ -203,6 +203,19 @@ typedef struct OMX_VIDEO_SLICESEGMENTSTYPE { OMX_BOOL bEnableLoopFilterAcrossSlices; } OMX_VIDEO_SLICESEGMENTSTYPE; +/** Structure to return timestamps of rendered output frames as well as EOS + * for tunneled components. + */ +typedef struct OMX_VIDEO_RENDEREVENTTYPE { + OMX_S64 nMediaTimeUs; // timestamp of rendered video frame + OMX_S64 nSystemTimeNs; // system monotonic time at the time frame was rendered + // Use INT64_MAX for nMediaTimeUs to signal that the EOS + // has been reached. In this case, nSystemTimeNs MUST be + // the system time when the last frame was rendered. + // This MUST be done in addition to returning (and + // following) the render information for the last frame. +} OMX_VIDEO_RENDEREVENTTYPE; + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/include/private/gui/LayerState.h b/include/private/gui/LayerState.h index 2fa6ff9d92..cbe87330ed 100644 --- a/include/private/gui/LayerState.h +++ b/include/private/gui/LayerState.h @@ -39,6 +39,7 @@ struct layer_state_t { enum { eLayerHidden = 0x01, // SURFACE_HIDDEN in SurfaceControl.java eLayerOpaque = 0x02, // SURFACE_OPAQUE + eLayerSecure = 0x80, // SECURE }; enum { @@ -48,10 +49,9 @@ struct layer_state_t { eAlphaChanged = 0x00000008, eMatrixChanged = 0x00000010, eTransparentRegionChanged = 0x00000020, - eVisibilityChanged = 0x00000040, + eFlagsChanged = 0x00000040, eLayerStackChanged = 0x00000080, eCropChanged = 0x00000100, - eOpacityChanged = 0x00000200, }; layer_state_t() diff --git a/include/ui/Fence.h b/include/ui/Fence.h index 20466b616e..b431bd52aa 100644 --- a/include/ui/Fence.h +++ b/include/ui/Fence.h @@ -65,7 +65,7 @@ public: // before the fence signals then -ETIME is returned. A timeout of // TIMEOUT_NEVER may be used to indicate that the call should wait // indefinitely for the fence to signal. - status_t wait(unsigned int timeout); + status_t wait(int timeout); // waitForever is a convenience function for waiting forever for a fence to // signal (just like wait(TIMEOUT_NEVER)), but issuing an error to the diff --git a/include/ui/FramebufferNativeWindow.h b/include/ui/FramebufferNativeWindow.h index 5cd8101d30..6b66d5f66b 100644 --- a/include/ui/FramebufferNativeWindow.h +++ b/include/ui/FramebufferNativeWindow.h @@ -14,11 +14,13 @@ * limitations under the License. */ +#ifndef INCLUDED_FROM_FRAMEBUFFER_NATIVE_WINDOW_CPP +#warning "FramebufferNativeWindow is deprecated" +#endif + #ifndef ANDROID_FRAMEBUFFER_NATIVE_WINDOW_H #define ANDROID_FRAMEBUFFER_NATIVE_WINDOW_H -#warning "FramebufferNativeWindow is deprecated" - #include <stdint.h> #include <sys/types.h> diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h index 7630faa762..3da720ff37 100644 --- a/include/ui/GraphicBuffer.h +++ b/include/ui/GraphicBuffer.h @@ -49,7 +49,7 @@ public: USAGE_SW_READ_RARELY = GRALLOC_USAGE_SW_READ_RARELY, USAGE_SW_READ_OFTEN = GRALLOC_USAGE_SW_READ_OFTEN, USAGE_SW_READ_MASK = GRALLOC_USAGE_SW_READ_MASK, - + USAGE_SW_WRITE_NEVER = GRALLOC_USAGE_SW_WRITE_NEVER, USAGE_SW_WRITE_RARELY = GRALLOC_USAGE_SW_WRITE_RARELY, USAGE_SW_WRITE_OFTEN = GRALLOC_USAGE_SW_WRITE_OFTEN, @@ -72,11 +72,13 @@ public: GraphicBuffer(); // creates w * h buffer - GraphicBuffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage); + GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, + uint32_t inUsage); // create a buffer from an existing handle - GraphicBuffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage, - uint32_t stride, native_handle_t* handle, bool keepOwnership); + GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, + uint32_t inUsage, uint32_t inStride, native_handle_t* inHandle, + bool keepOwnership); // create a buffer from an existing ANativeWindowBuffer GraphicBuffer(ANativeWindowBuffer* buffer, bool keepOwnership); @@ -84,26 +86,39 @@ public: // return status status_t initCheck() const; - uint32_t getWidth() const { return width; } - uint32_t getHeight() const { return height; } - uint32_t getStride() const { return stride; } - uint32_t getUsage() const { return usage; } + uint32_t getWidth() const { return static_cast<uint32_t>(width); } + uint32_t getHeight() const { return static_cast<uint32_t>(height); } + uint32_t getStride() const { return static_cast<uint32_t>(stride); } + uint32_t getUsage() const { return static_cast<uint32_t>(usage); } PixelFormat getPixelFormat() const { return format; } Rect getBounds() const { return Rect(width, height); } uint64_t getId() const { return mId; } - status_t reallocate(uint32_t w, uint32_t h, PixelFormat f, uint32_t usage); + uint32_t getGenerationNumber() const { return mGenerationNumber; } + void setGenerationNumber(uint32_t generation) { + mGenerationNumber = generation; + } + + status_t reallocate(uint32_t inWidth, uint32_t inHeight, + PixelFormat inFormat, uint32_t inUsage); - status_t lock(uint32_t usage, void** vaddr); - status_t lock(uint32_t usage, const Rect& rect, void** vaddr); + bool needsReallocation(uint32_t inWidth, uint32_t inHeight, + PixelFormat inFormat, uint32_t inUsage); + + status_t lock(uint32_t inUsage, void** vaddr); + status_t lock(uint32_t inUsage, const Rect& rect, void** vaddr); // For HAL_PIXEL_FORMAT_YCbCr_420_888 - status_t lockYCbCr(uint32_t usage, android_ycbcr *ycbcr); - status_t lockYCbCr(uint32_t usage, const Rect& rect, android_ycbcr *ycbcr); + status_t lockYCbCr(uint32_t inUsage, android_ycbcr *ycbcr); + status_t lockYCbCr(uint32_t inUsage, const Rect& rect, + android_ycbcr *ycbcr); status_t unlock(); - status_t lockAsync(uint32_t usage, void** vaddr, int fenceFd); - status_t lockAsync(uint32_t usage, const Rect& rect, void** vaddr, int fenceFd); - status_t lockAsyncYCbCr(uint32_t usage, android_ycbcr *ycbcr, int fenceFd); - status_t lockAsyncYCbCr(uint32_t usage, const Rect& rect, android_ycbcr *ycbcr, int fenceFd); + status_t lockAsync(uint32_t inUsage, void** vaddr, int fenceFd); + status_t lockAsync(uint32_t inUsage, const Rect& rect, void** vaddr, + int fenceFd); + status_t lockAsyncYCbCr(uint32_t inUsage, android_ycbcr *ycbcr, + int fenceFd); + status_t lockAsyncYCbCr(uint32_t inUsage, const Rect& rect, + android_ycbcr *ycbcr, int fenceFd); status_t unlockAsync(int *fenceFd); ANativeWindowBuffer* getNativeBuffer() const; @@ -143,8 +158,8 @@ private: GraphicBuffer& operator = (const GraphicBuffer& rhs); const GraphicBuffer& operator = (const GraphicBuffer& rhs) const; - status_t initSize(uint32_t w, uint32_t h, PixelFormat format, - uint32_t usage); + status_t initSize(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, + uint32_t inUsage); void free_handle(); @@ -156,6 +171,11 @@ private: sp<ANativeWindowBuffer> mWrappedBuffer; uint64_t mId; + + // Stores the generation number of this buffer. If this number does not + // match the BufferQueue's internal generation number (set through + // IGBP::setGenerationNumber), attempts to attach the buffer will fail. + uint32_t mGenerationNumber; }; }; // namespace android diff --git a/include/ui/GraphicBufferAllocator.h b/include/ui/GraphicBufferAllocator.h index dffa788f46..5443f09a10 100644 --- a/include/ui/GraphicBufferAllocator.h +++ b/include/ui/GraphicBufferAllocator.h @@ -1,17 +1,17 @@ -/* +/* ** ** Copyright 2009, 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 +** 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 +** 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 +** 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. */ @@ -45,14 +45,14 @@ public: USAGE_SW_READ_RARELY = GRALLOC_USAGE_SW_READ_RARELY, USAGE_SW_READ_OFTEN = GRALLOC_USAGE_SW_READ_OFTEN, USAGE_SW_READ_MASK = GRALLOC_USAGE_SW_READ_MASK, - + USAGE_SW_WRITE_NEVER = GRALLOC_USAGE_SW_WRITE_NEVER, USAGE_SW_WRITE_RARELY = GRALLOC_USAGE_SW_WRITE_RARELY, USAGE_SW_WRITE_OFTEN = GRALLOC_USAGE_SW_WRITE_OFTEN, USAGE_SW_WRITE_MASK = GRALLOC_USAGE_SW_WRITE_MASK, - + USAGE_SOFTWARE_MASK = USAGE_SW_READ_MASK|USAGE_SW_WRITE_MASK, - + USAGE_HW_TEXTURE = GRALLOC_USAGE_HW_TEXTURE, USAGE_HW_RENDER = GRALLOC_USAGE_HW_RENDER, USAGE_HW_2D = GRALLOC_USAGE_HW_2D, @@ -60,10 +60,9 @@ public: }; static inline GraphicBufferAllocator& get() { return getInstance(); } - - status_t alloc(uint32_t w, uint32_t h, PixelFormat format, int usage, - buffer_handle_t* handle, int32_t* stride); + status_t alloc(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage, + buffer_handle_t* handle, uint32_t* stride); status_t free(buffer_handle_t handle); @@ -72,21 +71,21 @@ public: private: struct alloc_rec_t { - uint32_t w; - uint32_t h; - uint32_t s; + uint32_t width; + uint32_t height; + uint32_t stride; PixelFormat format; uint32_t usage; size_t size; }; - + static Mutex sLock; static KeyedVector<buffer_handle_t, alloc_rec_t> sAllocList; - + friend class Singleton<GraphicBufferAllocator>; GraphicBufferAllocator(); ~GraphicBufferAllocator(); - + alloc_device_t *mAllocDev; }; diff --git a/include/ui/GraphicBufferMapper.h b/include/ui/GraphicBufferMapper.h index 98fff0ef31..6099548aaf 100644 --- a/include/ui/GraphicBufferMapper.h +++ b/include/ui/GraphicBufferMapper.h @@ -41,23 +41,24 @@ public: status_t registerBuffer(buffer_handle_t handle); status_t unregisterBuffer(buffer_handle_t handle); - + status_t lock(buffer_handle_t handle, - int usage, const Rect& bounds, void** vaddr); + uint32_t usage, const Rect& bounds, void** vaddr); status_t lockYCbCr(buffer_handle_t handle, - int usage, const Rect& bounds, android_ycbcr *ycbcr); + uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr); status_t unlock(buffer_handle_t handle); status_t lockAsync(buffer_handle_t handle, - int usage, const Rect& bounds, void** vaddr, int fenceFd); + uint32_t usage, const Rect& bounds, void** vaddr, int fenceFd); status_t lockAsyncYCbCr(buffer_handle_t handle, - int usage, const Rect& bounds, android_ycbcr *ycbcr, int fenceFd); + uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr, + int fenceFd); status_t unlockAsync(buffer_handle_t handle, int *fenceFd); - + // dumps information about the mapping of this handle void dump(buffer_handle_t handle); diff --git a/include/ui/PixelFormat.h b/include/ui/PixelFormat.h index 7e469453fd..f26fecb8b1 100644 --- a/include/ui/PixelFormat.h +++ b/include/ui/PixelFormat.h @@ -25,9 +25,6 @@ #ifndef UI_PIXELFORMAT_H #define UI_PIXELFORMAT_H -#include <stdint.h> -#include <sys/types.h> -#include <utils/Errors.h> #include <hardware/hardware.h> namespace android { @@ -63,14 +60,12 @@ enum { PIXEL_FORMAT_BGRA_8888 = HAL_PIXEL_FORMAT_BGRA_8888, // 4x8-bit BGRA PIXEL_FORMAT_RGBA_5551 = 6, // 16-bit ARGB PIXEL_FORMAT_RGBA_4444 = 7, // 16-bit ARGB - PIXEL_FORMAT_sRGB_A_8888 = HAL_PIXEL_FORMAT_sRGB_A_8888, // 4x8-bit sRGB + A - PIXEL_FORMAT_sRGB_X_8888 = HAL_PIXEL_FORMAT_sRGB_X_8888, // 4x8-bit sRGB, no A }; typedef int32_t PixelFormat; -ssize_t bytesPerPixel(PixelFormat format); -ssize_t bitsPerPixel(PixelFormat format); +uint32_t bytesPerPixel(PixelFormat format); +uint32_t bitsPerPixel(PixelFormat format); }; // namespace android diff --git a/include/ui/Rect.h b/include/ui/Rect.h index 31e28d27f7..3886f93142 100644 --- a/include/ui/Rect.h +++ b/include/ui/Rect.h @@ -18,6 +18,7 @@ #define ANDROID_UI_RECT #include <utils/Flattenable.h> +#include <utils/Log.h> #include <utils/TypeHelpers.h> #include <ui/Point.h> @@ -30,6 +31,8 @@ class Rect : public ARect, public LightFlattenablePod<Rect> public: typedef ARect::value_type value_type; + static const Rect INVALID_RECT; + // we don't provide copy-ctor and operator= on purpose // because we want the compiler generated versions @@ -43,6 +46,22 @@ public: bottom = h; } + inline Rect(uint32_t w, uint32_t h) { + if (w > INT32_MAX) { + ALOG(LOG_WARN, "Rect", + "Width %u too large for Rect class, clamping", w); + w = INT32_MAX; + } + if (h > INT32_MAX) { + ALOG(LOG_WARN, "Rect", + "Height %u too large for Rect class, clamping", h); + h = INT32_MAX; + } + left = top = 0; + right = w; + bottom = h; + } + inline Rect(int32_t l, int32_t t, int32_t r, int32_t b) { left = l; top = t; diff --git a/include/ui/Region.h b/include/ui/Region.h index 0d1c68c951..2a1491837d 100644 --- a/include/ui/Region.h +++ b/include/ui/Region.h @@ -35,6 +35,8 @@ class String8; class Region : public LightFlattenable<Region> { public: + static const Region INVALID_REGION; + Region(); Region(const Region& rhs); explicit Region(const Rect& rhs); @@ -55,11 +57,12 @@ public: // the region becomes its bounds Region& makeBoundsSelf(); - + void clear(); void set(const Rect& r); + void set(int32_t w, int32_t h); void set(uint32_t w, uint32_t h); - + Region& orSelf(const Rect& rhs); Region& xorSelf(const Rect& rhs); Region& andSelf(const Rect& rhs); @@ -110,14 +113,14 @@ public: inline Region& operator -= (const Region& rhs); inline Region& operator += (const Point& pt); - + // returns true if the regions share the same underlying storage bool isTriviallyEqual(const Region& region) const; /* various ways to access the rectangle list */ - + // STL-like iterators typedef Rect const* const_iterator; const_iterator begin() const; @@ -133,7 +136,7 @@ public: SharedBuffer const* getSharedBuffer(size_t* count) const; /* no user serviceable parts here... */ - + // add a rectangle to the internal list. This rectangle must // be sorted in Y and X and must not make the region invalid. void addRectUnchecked(int l, int t, int r, int b); @@ -149,7 +152,7 @@ public: private: class rasterizer; friend class rasterizer; - + Region& operationSelf(const Rect& r, int op); Region& operationSelf(const Region& r, int op); Region& operationSelf(const Region& r, int dx, int dy, int op); @@ -172,7 +175,7 @@ private: static bool validate(const Region& reg, const char* name, bool silent = false); - + // mStorage is a (manually) sorted array of Rects describing the region // with an extra Rect as the last element which is set to the // bounds of the region. However, if the region is diff --git a/libs/binder/Android.mk b/libs/binder/Android.mk index 79decfe21f..d5860ef6ca 100644 --- a/libs/binder/Android.mk +++ b/libs/binder/Android.mk @@ -26,6 +26,8 @@ sources := \ IMemory.cpp \ IPCThreadState.cpp \ IPermissionController.cpp \ + IProcessInfoService.cpp \ + ProcessInfoService.cpp \ IServiceManager.cpp \ MemoryDealer.cpp \ MemoryBase.cpp \ diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp index 61b4f7d661..e4d82019f1 100644 --- a/libs/binder/AppOpsManager.cpp +++ b/libs/binder/AppOpsManager.cpp @@ -44,7 +44,7 @@ sp<IAppOpsService> AppOpsManager::getService() int64_t startTime = 0; mLock.lock(); sp<IAppOpsService> service = mService; - while (service == NULL || !service->asBinder()->isBinderAlive()) { + while (service == NULL || !IInterface::asBinder(service)->isBinderAlive()) { sp<IBinder> binder = defaultServiceManager()->checkService(_appops); if (binder == NULL) { // Wait for the app ops service to come back... @@ -104,4 +104,13 @@ void AppOpsManager::stopWatchingMode(const sp<IAppOpsCallback>& callback) { } } +int32_t AppOpsManager::permissionToOpCode(const String16& permission) { + sp<IAppOpsService> service = getService(); + if (service != NULL) { + return service->permissionToOpCode(permission); + } + return -1; +} + + }; // namespace android diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp index 2554351cc6..9d200fb219 100644 --- a/libs/binder/Binder.cpp +++ b/libs/binder/Binder.cpp @@ -72,7 +72,7 @@ public: BBinder::BBinder() { - atomic_init(&mExtras, 0); + atomic_init(&mExtras, static_cast<uintptr_t>(0)); } bool BBinder::isBinderAlive() const @@ -160,10 +160,18 @@ void BBinder::attachObject( e->mObjects.attach(objectID, object, cleanupCookie, func); } +// The C11 standard doesn't allow atomic loads from const fields, +// though C++11 does. Fudge it until standards get straightened out. +static inline uintptr_t load_const_atomic(const atomic_uintptr_t* p, + memory_order mo) { + atomic_uintptr_t* non_const_p = const_cast<atomic_uintptr_t*>(p); + return atomic_load_explicit(non_const_p, mo); +} + void* BBinder::findObject(const void* objectID) const { Extras* e = reinterpret_cast<Extras*>( - atomic_load_explicit(&mExtras, memory_order_acquire)); + load_const_atomic(&mExtras, memory_order_acquire)); if (!e) return NULL; AutoMutex _l(e->mLock); diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index 101de7efd6..345ba20f1b 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -220,7 +220,6 @@ status_t BpBinder::unlinkToDeath( if ((obit.recipient == recipient || (recipient == NULL && obit.cookie == cookie)) && obit.flags == flags) { - const uint32_t allFlags = obit.flags|flags; if (outRecipient != NULL) { *outRecipient = mObituaries->itemAt(i).recipient; } diff --git a/libs/binder/BufferedTextOutput.cpp b/libs/binder/BufferedTextOutput.cpp index 2d493c1511..1339a67e62 100644 --- a/libs/binder/BufferedTextOutput.cpp +++ b/libs/binder/BufferedTextOutput.cpp @@ -49,9 +49,12 @@ struct BufferedTextOutput::BufferState : public RefBase status_t append(const char* txt, size_t len) { if ((len+bufferPos) > bufferSize) { - void* b = realloc(buffer, ((len+bufferPos)*3)/2); + size_t newSize = ((len+bufferPos)*3)/2; + if (newSize < (len+bufferPos)) return NO_MEMORY; // overflow + void* b = realloc(buffer, newSize); if (!b) return NO_MEMORY; buffer = (char*)b; + bufferSize = newSize; } memcpy(buffer+bufferPos, txt, len); bufferPos += len; diff --git a/libs/binder/Debug.cpp b/libs/binder/Debug.cpp index 0ffafbbeb4..bdb7182cc0 100644 --- a/libs/binder/Debug.cpp +++ b/libs/binder/Debug.cpp @@ -220,13 +220,8 @@ void printHexData(int32_t indent, const void *buf, size_t length, for (word = 0; word < bytesPerLine; ) { -#ifdef HAVE_LITTLE_ENDIAN const size_t startIndex = word+(alignment-(alignment?1:0)); const ssize_t dir = -1; -#else - const size_t startIndex = word; - const ssize_t dir = 1; -#endif for (index = 0; index < alignment || (alignment == 0 && index < bytesPerLine); index++) { diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp index f58a352d07..9558376dbf 100644 --- a/libs/binder/IAppOpsService.cpp +++ b/libs/binder/IAppOpsService.cpp @@ -91,14 +91,14 @@ public: data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); data.writeInt32(op); data.writeString16(packageName); - data.writeStrongBinder(callback->asBinder()); + data.writeStrongBinder(IInterface::asBinder(callback)); remote()->transact(START_WATCHING_MODE_TRANSACTION, data, &reply); } virtual void stopWatchingMode(const sp<IAppOpsCallback>& callback) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); - data.writeStrongBinder(callback->asBinder()); + data.writeStrongBinder(IInterface::asBinder(callback)); remote()->transact(STOP_WATCHING_MODE_TRANSACTION, data, &reply); } @@ -111,6 +111,17 @@ public: if (reply.readExceptionCode() != 0) return NULL; return reply.readStrongBinder(); } + + + virtual int32_t permissionToOpCode(const String16& permission) { + Parcel data, reply; + data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); + data.writeString16(permission); + remote()->transact(PERMISSION_TO_OP_CODE_TRANSACTION, data, &reply); + // fail on exception + if (reply.readExceptionCode() != 0) return -1; + return reply.readInt32(); + } }; IMPLEMENT_META_INTERFACE(AppOpsService, "com.android.internal.app.IAppOpsService"); @@ -187,6 +198,14 @@ status_t BnAppOpsService::onTransact( reply->writeStrongBinder(token); return NO_ERROR; } break; + case PERMISSION_TO_OP_CODE_TRANSACTION: { + CHECK_INTERFACE(IAppOpsService, data, reply); + String16 permission = data.readString16(); + const int32_t opCode = permissionToOpCode(permission); + reply->writeNoException(); + reply->writeInt32(opCode); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/binder/IBatteryStats.cpp b/libs/binder/IBatteryStats.cpp index 8f3b7b49ad..e32c628679 100644 --- a/libs/binder/IBatteryStats.cpp +++ b/libs/binder/IBatteryStats.cpp @@ -89,6 +89,47 @@ public: data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor()); remote()->transact(NOTE_RESET_AUDIO_TRANSACTION, data, &reply); } + + virtual void noteFlashlightOn(int uid) { + Parcel data, reply; + data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor()); + data.writeInt32(uid); + remote()->transact(NOTE_FLASHLIGHT_ON_TRANSACTION, data, &reply); + } + + virtual void noteFlashlightOff(int uid) { + Parcel data, reply; + data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor()); + data.writeInt32(uid); + remote()->transact(NOTE_FLASHLIGHT_OFF_TRANSACTION, data, &reply); + } + + virtual void noteStartCamera(int uid) { + Parcel data, reply; + data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor()); + data.writeInt32(uid); + remote()->transact(NOTE_START_CAMERA_TRANSACTION, data, &reply); + } + + virtual void noteStopCamera(int uid) { + Parcel data, reply; + data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor()); + data.writeInt32(uid); + remote()->transact(NOTE_STOP_CAMERA_TRANSACTION, data, &reply); + } + + virtual void noteResetCamera() { + Parcel data, reply; + data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor()); + remote()->transact(NOTE_RESET_CAMERA_TRANSACTION, data, &reply); + } + + virtual void noteResetFlashlight() { + Parcel data, reply; + data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor()); + remote()->transact(NOTE_RESET_FLASHLIGHT_TRANSACTION, data, &reply); + } + }; IMPLEMENT_META_INTERFACE(BatteryStats, "com.android.internal.app.IBatteryStats"); @@ -155,6 +196,46 @@ status_t BnBatteryStats::onTransact( reply->writeNoException(); return NO_ERROR; } break; + case NOTE_FLASHLIGHT_ON_TRANSACTION: { + CHECK_INTERFACE(IBatteryStats, data, reply); + int uid = data.readInt32(); + noteFlashlightOn(uid); + reply->writeNoException(); + return NO_ERROR; + } break; + case NOTE_FLASHLIGHT_OFF_TRANSACTION: { + CHECK_INTERFACE(IBatteryStats, data, reply); + int uid = data.readInt32(); + noteFlashlightOff(uid); + reply->writeNoException(); + return NO_ERROR; + } break; + case NOTE_START_CAMERA_TRANSACTION: { + CHECK_INTERFACE(IBatteryStats, data, reply); + int uid = data.readInt32(); + noteStartCamera(uid); + reply->writeNoException(); + return NO_ERROR; + } break; + case NOTE_STOP_CAMERA_TRANSACTION: { + CHECK_INTERFACE(IBatteryStats, data, reply); + int uid = data.readInt32(); + noteStopCamera(uid); + reply->writeNoException(); + return NO_ERROR; + } break; + case NOTE_RESET_CAMERA_TRANSACTION: { + CHECK_INTERFACE(IBatteryStats, data, reply); + noteResetCamera(); + reply->writeNoException(); + return NO_ERROR; + } break; + case NOTE_RESET_FLASHLIGHT_TRANSACTION: { + CHECK_INTERFACE(IBatteryStats, data, reply); + noteResetFlashlight(); + reply->writeNoException(); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/binder/IInterface.cpp b/libs/binder/IInterface.cpp index 29acf5ddd1..2fcd3d92fb 100644 --- a/libs/binder/IInterface.cpp +++ b/libs/binder/IInterface.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#define LOG_TAG "IInterface" +#include <utils/Log.h> #include <binder/IInterface.h> namespace android { @@ -27,16 +29,39 @@ IInterface::IInterface() IInterface::~IInterface() { } -sp<IBinder> IInterface::asBinder() +// static +sp<IBinder> IInterface::asBinder(const IInterface* iface) { - return this ? onAsBinder() : NULL; + if (iface == NULL) return NULL; + return const_cast<IInterface*>(iface)->onAsBinder(); } -sp<const IBinder> IInterface::asBinder() const +// static +sp<IBinder> IInterface::asBinder(const sp<IInterface>& iface) { - return this ? const_cast<IInterface*>(this)->onAsBinder() : NULL; + if (iface == NULL) return NULL; + return iface->onAsBinder(); } + // --------------------------------------------------------------------------- }; // namespace android + +extern "C" { + +void _ZN7android10IInterface8asBinderEv(void *retval, void* self) { + ALOGW("deprecated asBinder call, please update your code"); + //ALOGI("self: %p, retval: %p", self, retval); + android::sp<android::IBinder> *ret = new(retval) android::sp<android::IBinder>; + *ret = android::IInterface::asBinder((android::IInterface*)self); +} + +void _ZNK7android10IInterface8asBinderEv(void *retval, void *self) { + ALOGW("deprecated asBinder call, please update your code"); + //ALOGI("self: %p, retval: %p", self, retval); + android::sp<android::IBinder> *ret = new(retval) android::sp<android::IBinder>; + *ret = android::IInterface::asBinder((android::IInterface*)self); +} + +} // extern "C" diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp index b9a8bced37..fb8d620b4c 100644 --- a/libs/binder/IMemory.cpp +++ b/libs/binder/IMemory.cpp @@ -228,7 +228,7 @@ status_t BnMemory::onTransact( CHECK_INTERFACE(IMemory, data, reply); ssize_t offset; size_t size; - reply->writeStrongBinder( getMemory(&offset, &size)->asBinder() ); + reply->writeStrongBinder( IInterface::asBinder(getMemory(&offset, &size)) ); reply->writeInt32(offset); reply->writeInt32(size); return NO_ERROR; @@ -253,7 +253,7 @@ BpMemoryHeap::~BpMemoryHeap() { if (mRealHeap) { // by construction we're the last one if (mBase != MAP_FAILED) { - sp<IBinder> binder = const_cast<BpMemoryHeap*>(this)->asBinder(); + sp<IBinder> binder = IInterface::asBinder(this); if (VERBOSE) { ALOGD("UNMAPPING binder=%p, heap=%p, size=%zu, fd=%d", @@ -265,7 +265,7 @@ BpMemoryHeap::~BpMemoryHeap() { } } else { // remove from list only if it was mapped before - sp<IBinder> binder = const_cast<BpMemoryHeap*>(this)->asBinder(); + sp<IBinder> binder = IInterface::asBinder(this); free_heap(binder); } } @@ -274,7 +274,7 @@ BpMemoryHeap::~BpMemoryHeap() { void BpMemoryHeap::assertMapped() const { if (mHeapId == -1) { - sp<IBinder> binder(const_cast<BpMemoryHeap*>(this)->asBinder()); + sp<IBinder> binder(IInterface::asBinder(const_cast<BpMemoryHeap*>(this))); sp<BpMemoryHeap> heap(static_cast<BpMemoryHeap*>(find_heap(binder).get())); heap->assertReallyMapped(); if (heap->mBase != MAP_FAILED) { @@ -309,7 +309,8 @@ void BpMemoryHeap::assertReallyMapped() const uint32_t offset = reply.readInt32(); ALOGE_IF(err, "binder=%p transaction failed fd=%d, size=%zd, err=%d (%s)", - asBinder().get(), parcel_fd, size, err, strerror(-err)); + IInterface::asBinder(this).get(), + parcel_fd, size, err, strerror(-err)); int fd = dup( parcel_fd ); ALOGE_IF(fd==-1, "cannot dup fd=%d, size=%zd, err=%d (%s)", @@ -326,7 +327,7 @@ void BpMemoryHeap::assertReallyMapped() const mBase = mmap(0, size, access, MAP_SHARED, fd, offset); if (mBase == MAP_FAILED) { ALOGE("cannot map BpMemoryHeap (binder=%p), size=%zd, fd=%d (%s)", - asBinder().get(), size, fd, strerror(errno)); + IInterface::asBinder(this).get(), size, fd, strerror(errno)); close(fd); } else { mSize = size; diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index 2296cd2b83..af18e119ab 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -29,21 +29,14 @@ #include <private/binder/binder_module.h> #include <private/binder/Static.h> -#include <sys/ioctl.h> -#include <signal.h> #include <errno.h> -#include <stdio.h> -#include <unistd.h> - -#ifdef HAVE_PTHREADS #include <pthread.h> #include <sched.h> +#include <signal.h> +#include <stdio.h> +#include <sys/ioctl.h> #include <sys/resource.h> -#endif -#ifdef HAVE_WIN32_THREADS -#include <windows.h> -#endif - +#include <unistd.h> #if LOG_NDEBUG @@ -70,13 +63,11 @@ namespace android { static const char* getReturnString(size_t idx); -static const char* getCommandString(size_t idx); static const void* printReturnCommand(TextOutput& out, const void* _cmd); static const void* printCommand(TextOutput& out, const void* _cmd); -// This will result in a missing symbol failure if the IF_LOG_COMMANDS() -// conditionals don't get stripped... but that is probably what we want. -#if !LOG_NDEBUG +// Static const and functions will be optimized out if not used, +// when LOG_NDEBUG and references in IF_LOG_COMMANDS() are optimized out. static const char *kReturnStrings[] = { "BR_ERROR", "BR_OK", @@ -126,14 +117,6 @@ static const char* getReturnString(size_t idx) return "unknown"; } -static const char* getCommandString(size_t idx) -{ - if (idx < sizeof(kCommandStrings) / sizeof(kCommandStrings[0])) - return kCommandStrings[idx]; - else - return "unknown"; -} - static const void* printBinderTransactionData(TextOutput& out, const void* data) { const binder_transaction_data* btd = @@ -145,7 +128,7 @@ static const void* printBinderTransactionData(TextOutput& out, const void* data) out << "target.ptr=" << btd->target.ptr; } out << " (cookie " << btd->cookie << ")" << endl - << "code=" << TypeCode(btd->code) << ", flags=" << (void*)btd->flags << endl + << "code=" << TypeCode(btd->code) << ", flags=" << (void*)(long)btd->flags << endl << "data=" << btd->data.ptr.buffer << " (" << (void*)btd->data_size << " bytes)" << endl << "offsets=" << btd->data.ptr.offsets << " (" << (void*)btd->offsets_size @@ -157,10 +140,10 @@ static const void* printReturnCommand(TextOutput& out, const void* _cmd) { static const size_t N = sizeof(kReturnStrings)/sizeof(kReturnStrings[0]); const int32_t* cmd = (const int32_t*)_cmd; - int32_t code = *cmd++; + uint32_t code = (uint32_t)*cmd++; size_t cmdIndex = code & 0xff; - if (code == (int32_t) BR_ERROR) { - out << "BR_ERROR: " << (void*)(*cmd++) << endl; + if (code == BR_ERROR) { + out << "BR_ERROR: " << (void*)(long)(*cmd++) << endl; return cmd; } else if (cmdIndex >= N) { out << "Unknown reply: " << code << endl; @@ -187,21 +170,21 @@ static const void* printReturnCommand(TextOutput& out, const void* _cmd) case BR_DECREFS: { const int32_t b = *cmd++; const int32_t c = *cmd++; - out << ": target=" << (void*)b << " (cookie " << (void*)c << ")"; + out << ": target=" << (void*)(long)b << " (cookie " << (void*)(long)c << ")"; } break; case BR_ATTEMPT_ACQUIRE: { const int32_t p = *cmd++; const int32_t b = *cmd++; const int32_t c = *cmd++; - out << ": target=" << (void*)b << " (cookie " << (void*)c + out << ": target=" << (void*)(long)b << " (cookie " << (void*)(long)c << "), pri=" << p; } break; case BR_DEAD_BINDER: case BR_CLEAR_DEATH_NOTIFICATION_DONE: { const int32_t c = *cmd++; - out << ": death cookie " << (void*)c; + out << ": death cookie " << (void*)(long)c; } break; default: @@ -218,7 +201,7 @@ static const void* printCommand(TextOutput& out, const void* _cmd) { static const size_t N = sizeof(kCommandStrings)/sizeof(kCommandStrings[0]); const int32_t* cmd = (const int32_t*)_cmd; - int32_t code = *cmd++; + uint32_t code = (uint32_t)*cmd++; size_t cmdIndex = code & 0xff; if (cmdIndex >= N) { @@ -242,7 +225,7 @@ static const void* printCommand(TextOutput& out, const void* _cmd) case BC_FREE_BUFFER: { const int32_t buf = *cmd++; - out << ": buffer=" << (void*)buf; + out << ": buffer=" << (void*)(long)buf; } break; case BC_INCREFS: @@ -257,7 +240,7 @@ static const void* printCommand(TextOutput& out, const void* _cmd) case BC_ACQUIRE_DONE: { const int32_t b = *cmd++; const int32_t c = *cmd++; - out << ": target=" << (void*)b << " (cookie " << (void*)c << ")"; + out << ": target=" << (void*)(long)b << " (cookie " << (void*)(long)c << ")"; } break; case BC_ATTEMPT_ACQUIRE: { @@ -270,12 +253,12 @@ static const void* printCommand(TextOutput& out, const void* _cmd) case BC_CLEAR_DEATH_NOTIFICATION: { const int32_t h = *cmd++; const int32_t c = *cmd++; - out << ": handle=" << h << " (death cookie " << (void*)c << ")"; + out << ": handle=" << h << " (death cookie " << (void*)(long)c << ")"; } break; case BC_DEAD_BINDER_DONE: { const int32_t c = *cmd++; - out << ": death cookie " << (void*)c; + out << ": death cookie " << (void*)(long)c; } break; default: @@ -287,7 +270,6 @@ static const void* printCommand(TextOutput& out, const void* _cmd) out << endl; return cmd; } -#endif static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER; static bool gHaveTLS = false; @@ -361,12 +343,12 @@ status_t IPCThreadState::clearLastError() return err; } -int IPCThreadState::getCallingPid() const +pid_t IPCThreadState::getCallingPid() const { return mCallingPid; } -int IPCThreadState::getCallingUid() const +uid_t IPCThreadState::getCallingUid() const { return mCallingUid; } @@ -417,6 +399,18 @@ void IPCThreadState::flushCommands() talkWithDriver(false); } +void IPCThreadState::blockUntilThreadAvailable() +{ + pthread_mutex_lock(&mProcess->mThreadCountLock); + while (mProcess->mExecutingThreadsCount >= mProcess->mMaxThreads) { + ALOGW("Waiting for thread to be free. mExecutingThreadsCount=%lu mMaxThreads=%lu\n", + static_cast<unsigned long>(mProcess->mExecutingThreadsCount), + static_cast<unsigned long>(mProcess->mMaxThreads)); + pthread_cond_wait(&mProcess->mThreadCountDecrement, &mProcess->mThreadCountLock); + } + pthread_mutex_unlock(&mProcess->mThreadCountLock); +} + status_t IPCThreadState::getAndExecuteCommand() { status_t result; @@ -432,8 +426,17 @@ status_t IPCThreadState::getAndExecuteCommand() << getReturnString(cmd) << endl; } + pthread_mutex_lock(&mProcess->mThreadCountLock); + mProcess->mExecutingThreadsCount++; + pthread_mutex_unlock(&mProcess->mThreadCountLock); + result = executeCommand(cmd); + pthread_mutex_lock(&mProcess->mThreadCountLock); + mProcess->mExecutingThreadsCount--; + pthread_cond_broadcast(&mProcess->mThreadCountDecrement); + pthread_mutex_unlock(&mProcess->mThreadCountLock); + // After executing the command, ensure that the thread is returned to the // foreground cgroup before rejoining the pool. The driver takes care of // restoring the priority, but doesn't do anything with cgroups so we @@ -682,7 +685,7 @@ status_t IPCThreadState::clearDeathNotification(int32_t handle, BpBinder* proxy) IPCThreadState::IPCThreadState() : mProcess(ProcessState::self()), - mMyThreadId(androidGetTid()), + mMyThreadId(gettid()), mStrictModePolicy(0), mLastTransactionBinderFlags(0) { @@ -708,7 +711,7 @@ status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags) status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult) { - int32_t cmd; + uint32_t cmd; int32_t err; while (1) { @@ -717,7 +720,7 @@ status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult) if (err < NO_ERROR) break; if (mIn.dataAvail() == 0) continue; - cmd = mIn.readInt32(); + cmd = (uint32_t)mIn.readInt32(); IF_LOG_COMMANDS() { alog << "Processing waitForResponse Command: " @@ -947,7 +950,7 @@ status_t IPCThreadState::executeCommand(int32_t cmd) RefBase::weakref_type* refs; status_t result = NO_ERROR; - switch (cmd) { + switch ((uint32_t)cmd) { case BR_ERROR: result = mIn.readInt32(); break; diff --git a/libs/binder/IPermissionController.cpp b/libs/binder/IPermissionController.cpp index 437113d446..6bba9968bc 100644 --- a/libs/binder/IPermissionController.cpp +++ b/libs/binder/IPermissionController.cpp @@ -48,6 +48,36 @@ public: if (reply.readExceptionCode() != 0) return 0; return reply.readInt32() != 0; } + + virtual void getPackagesForUid(const uid_t uid, Vector<String16>& packages) + { + Parcel data, reply; + data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor()); + data.writeInt32(uid); + remote()->transact(GET_PACKAGES_FOR_UID_TRANSACTION, data, &reply); + // fail on exception + if (reply.readExceptionCode() != 0) { + return; + } + const int32_t size = reply.readInt32(); + if (size <= 0) { + return; + } + for (int i = 0; i < size; i++) { + packages.push(reply.readString16()); + } + } + + virtual bool isRuntimePermission(const String16& permission) + { + Parcel data, reply; + data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor()); + data.writeString16(permission); + remote()->transact(IS_RUNTIME_PERMISSION_TRANSACTION, data, &reply); + // fail on exception + if (reply.readExceptionCode() != 0) return false; + return reply.readInt32() != 0; + } }; IMPLEMENT_META_INTERFACE(PermissionController, "android.os.IPermissionController"); @@ -57,7 +87,6 @@ IMPLEMENT_META_INTERFACE(PermissionController, "android.os.IPermissionController status_t BnPermissionController::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { - //printf("PermissionController received: "); data.print(); switch(code) { case CHECK_PERMISSION_TRANSACTION: { CHECK_INTERFACE(IPermissionController, data, reply); @@ -69,6 +98,30 @@ status_t BnPermissionController::onTransact( reply->writeInt32(res ? 1 : 0); return NO_ERROR; } break; + + case GET_PACKAGES_FOR_UID_TRANSACTION: { + CHECK_INTERFACE(IPermissionController, data, reply); + int32_t uid = data.readInt32(); + Vector<String16> packages; + getPackagesForUid(uid, packages); + reply->writeNoException(); + size_t size = packages.size(); + reply->writeInt32(size); + for (size_t i = 0; i < size; i++) { + reply->writeString16(packages[i]); + } + return NO_ERROR; + } break; + + case IS_RUNTIME_PERMISSION_TRANSACTION: { + CHECK_INTERFACE(IPermissionController, data, reply); + String16 permission = data.readString16(); + const bool res = isRuntimePermission(permission); + reply->writeNoException(); + reply->writeInt32(res ? 1 : 0); + return NO_ERROR; + } break; + default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/binder/IProcessInfoService.cpp b/libs/binder/IProcessInfoService.cpp new file mode 100644 index 0000000000..d86eb27b4d --- /dev/null +++ b/libs/binder/IProcessInfoService.cpp @@ -0,0 +1,94 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <binder/IProcessInfoService.h> +#include <binder/Parcel.h> +#include <utils/Errors.h> +#include <sys/types.h> + +namespace android { + +// ---------------------------------------------------------------------- + +class BpProcessInfoService : public BpInterface<IProcessInfoService> { +public: + BpProcessInfoService(const sp<IBinder>& impl) + : BpInterface<IProcessInfoService>(impl) {} + + virtual status_t getProcessStatesFromPids(size_t length, /*in*/ int32_t* pids, + /*out*/ int32_t* states) + { + Parcel data, reply; + data.writeInterfaceToken(IProcessInfoService::getInterfaceDescriptor()); + data.writeInt32Array(length, pids); + data.writeInt32(length); // write length of output array, used by java AIDL stubs + status_t err = remote()->transact(GET_PROCESS_STATES_FROM_PIDS, data, &reply); + if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) { + return err; + } + int32_t replyLen = reply.readInt32(); + if (static_cast<size_t>(replyLen) != length) { + return NOT_ENOUGH_DATA; + } + if (replyLen > 0 && (err = reply.read(states, length * sizeof(*states))) != NO_ERROR) { + return err; + } + return reply.readInt32(); + } + +}; + +IMPLEMENT_META_INTERFACE(ProcessInfoService, "android.os.IProcessInfoService"); + +// ---------------------------------------------------------------------- + +status_t BnProcessInfoService::onTransact( uint32_t code, const Parcel& data, Parcel* reply, + uint32_t flags) { + switch(code) { + case GET_PROCESS_STATES_FROM_PIDS: { + CHECK_INTERFACE(IProcessInfoService, data, reply); + int32_t arrayLen = data.readInt32(); + if (arrayLen <= 0) { + reply->writeNoException(); + reply->writeInt32(0); + reply->writeInt32(NOT_ENOUGH_DATA); + return NO_ERROR; + } + + size_t len = static_cast<size_t>(arrayLen); + int32_t pids[len]; + status_t res = data.read(pids, len * sizeof(*pids)); + + // Ignore output array length returned in the parcel here, as the states array must + // always be the same length as the input PIDs array. + int32_t states[len]; + for (size_t i = 0; i < len; i++) states[i] = -1; + if (res == NO_ERROR) { + res = getProcessStatesFromPids(len, /*in*/ pids, /*out*/ states); + } + reply->writeNoException(); + reply->writeInt32Array(len, states); + reply->writeInt32(res); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +// ---------------------------------------------------------------------- + +}; // namespace android diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index 7b1b0e7270..3c716df177 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -87,7 +87,7 @@ bool checkPermission(const String16& permission, pid_t pid, uid_t uid) } // Is this a permission failure, or did the controller go away? - if (pc->asBinder()->isBinderAlive()) { + if (IInterface::asBinder(pc)->isBinderAlive()) { ALOGW("Permission failure: %s from uid=%d pid=%d", String8(permission).string(), uid, pid); return false; diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 3100a58111..cfcf73b8d6 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -54,17 +54,24 @@ // --------------------------------------------------------------------------- -#define PAD_SIZE(s) (((s)+3)&~3) +// This macro should never be used at runtime, as a too large value +// of s could cause an integer overflow. Instead, you should always +// use the wrapper function pad_size() +#define PAD_SIZE_UNSAFE(s) (((s)+3)&~3) + +static size_t pad_size(size_t s) { + if (s > (SIZE_T_MAX - 3)) { + abort(); + } + return PAD_SIZE_UNSAFE(s); +} // Note: must be kept in sync with android/os/StrictMode.java's PENALTY_GATHER -#define STRICT_MODE_PENALTY_GATHER 0x100 +#define STRICT_MODE_PENALTY_GATHER (0x40 << 16) // Note: must be kept in sync with android/os/Parcel.java's EX_HAS_REPLY_HEADER #define EX_HAS_REPLY_HEADER -128 -// Maximum size of a blob to transfer in-place. -static const size_t IN_PLACE_BLOB_LIMIT = 40 * 1024; - // XXX This can be made public if we want to provide // support for typed data. struct small_flat_data @@ -79,6 +86,15 @@ static pthread_mutex_t gParcelGlobalAllocSizeLock = PTHREAD_MUTEX_INITIALIZER; static size_t gParcelGlobalAllocSize = 0; static size_t gParcelGlobalAllocCount = 0; +// Maximum size of a blob to transfer in-place. +static const size_t BLOB_INPLACE_LIMIT = 16 * 1024; + +enum { + BLOB_INPLACE = 0, + BLOB_ASHMEM_IMMUTABLE = 1, + BLOB_ASHMEM_MUTABLE = 2, +}; + void acquire_object(const sp<ProcessState>& proc, const flat_binder_object& obj, const void* who) { @@ -355,6 +371,12 @@ size_t Parcel::dataCapacity() const status_t Parcel::setDataSize(size_t size) { + if (size > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + status_t err; err = continueWrite(size); if (err == NO_ERROR) { @@ -366,18 +388,36 @@ status_t Parcel::setDataSize(size_t size) void Parcel::setDataPosition(size_t pos) const { + if (pos > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + abort(); + } + mDataPos = pos; mNextObjectHint = 0; } status_t Parcel::setDataCapacity(size_t size) { + if (size > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + if (size > mDataCapacity) return continueWrite(size); return NO_ERROR; } status_t Parcel::setData(const uint8_t* buffer, size_t len) { + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + status_t err = restartWrite(len); if (err == NO_ERROR) { memcpy(const_cast<uint8_t*>(data()), buffer, len); @@ -401,6 +441,12 @@ status_t Parcel::appendFrom(const Parcel *parcel, size_t offset, size_t len) return NO_ERROR; } + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + // range checks against the source parcel size if ((offset > parcel->mDataSize) || (len > parcel->mDataSize) @@ -477,6 +523,11 @@ status_t Parcel::appendFrom(const Parcel *parcel, size_t offset, size_t len) return err; } +bool Parcel::allowFds() const +{ + return mAllowFds; +} + bool Parcel::pushAllowFds(bool allowFds) { const bool origValue = mAllowFds; @@ -562,6 +613,12 @@ void Parcel::setError(status_t err) status_t Parcel::finishWrite(size_t len) { + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + //printf("Finish write of %d\n", len); mDataPos += len; ALOGV("finishWrite Setting data pos of %p to %zu", this, mDataPos); @@ -575,6 +632,12 @@ status_t Parcel::finishWrite(size_t len) status_t Parcel::writeUnpadded(const void* data, size_t len) { + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + size_t end = mDataPos + len; if (end < mDataPos) { // integer overflow @@ -594,6 +657,12 @@ restart_write: status_t Parcel::write(const void* data, size_t len) { + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + void* const d = writeInplace(len); if (d) { memcpy(d, data, len); @@ -604,7 +673,13 @@ status_t Parcel::write(const void* data, size_t len) void* Parcel::writeInplace(size_t len) { - const size_t padded = PAD_SIZE(len); + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return NULL; + } + + const size_t padded = pad_size(len); // sanity check for integer overflow if (mDataPos+padded < mDataPos) { @@ -646,21 +721,39 @@ status_t Parcel::writeInt32(int32_t val) { return writeAligned(val); } + +status_t Parcel::writeUint32(uint32_t val) +{ + return writeAligned(val); +} + status_t Parcel::writeInt32Array(size_t len, const int32_t *val) { + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + if (!val) { - return writeAligned(-1); + return writeInt32(-1); } - status_t ret = writeAligned(len); + status_t ret = writeInt32(static_cast<uint32_t>(len)); if (ret == NO_ERROR) { ret = write(val, len * sizeof(*val)); } return ret; } status_t Parcel::writeByteArray(size_t len, const uint8_t *val) { + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + if (!val) { - return writeAligned(-1); + return writeInt32(-1); } - status_t ret = writeAligned(len); + status_t ret = writeInt32(static_cast<uint32_t>(len)); if (ret == NO_ERROR) { ret = write(val, len * sizeof(*val)); } @@ -672,6 +765,11 @@ status_t Parcel::writeInt64(int64_t val) return writeAligned(val); } +status_t Parcel::writeUint64(uint64_t val) +{ + return writeAligned(val); +} + status_t Parcel::writePointer(uintptr_t val) { return writeAligned<binder_uintptr_t>(val); @@ -800,45 +898,24 @@ status_t Parcel::writeDupFileDescriptor(int fd) return err; } -// WARNING: This method must stay in sync with -// Parcelable.Creator<ParcelFileDescriptor> CREATOR -// in frameworks/base/core/java/android/os/ParcelFileDescriptor.java -status_t Parcel::writeParcelFileDescriptor(int fd, int commChannel) { - status_t status; - - if (fd < 0) { - status = writeInt32(0); // ParcelFileDescriptor is null - if (status) return status; - } else { - status = writeInt32(1); // ParcelFileDescriptor is not null - if (status) return status; - status = writeDupFileDescriptor(fd); - if (status) return status; - if (commChannel < 0) { - status = writeInt32(0); // commChannel is null - if (status) return status; - } else { - status = writeInt32(1); // commChannel is not null - if (status) return status; - status = writeDupFileDescriptor(commChannel); - } +status_t Parcel::writeBlob(size_t len, bool mutableCopy, WritableBlob* outBlob) +{ + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; } - return status; -} -status_t Parcel::writeBlob(size_t len, WritableBlob* outBlob) -{ status_t status; - - if (!mAllowFds || len <= IN_PLACE_BLOB_LIMIT) { + if (!mAllowFds || len <= BLOB_INPLACE_LIMIT) { ALOGV("writeBlob: write in place"); - status = writeInt32(0); + status = writeInt32(BLOB_INPLACE); if (status) return status; void* ptr = writeInplace(len); if (!ptr) return NO_MEMORY; - outBlob->init(false /*mapped*/, ptr, len); + outBlob->init(-1, ptr, len, false); return NO_ERROR; } @@ -846,6 +923,8 @@ status_t Parcel::writeBlob(size_t len, WritableBlob* outBlob) int fd = ashmem_create_region("Parcel Blob", len); if (fd < 0) return NO_MEMORY; + mBlobAshmemSize += len; + int result = ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE); if (result < 0) { status = result; @@ -854,15 +933,17 @@ status_t Parcel::writeBlob(size_t len, WritableBlob* outBlob) if (ptr == MAP_FAILED) { status = -errno; } else { - result = ashmem_set_prot_region(fd, PROT_READ); + if (!mutableCopy) { + result = ashmem_set_prot_region(fd, PROT_READ); + } if (result < 0) { status = result; } else { - status = writeInt32(1); + status = writeInt32(mutableCopy ? BLOB_ASHMEM_MUTABLE : BLOB_ASHMEM_IMMUTABLE); if (!status) { status = writeFileDescriptor(fd, true /*takeOwnership*/); if (!status) { - outBlob->init(true /*mapped*/, ptr, len); + outBlob->init(fd, ptr, len, mutableCopy); return NO_ERROR; } } @@ -874,6 +955,15 @@ status_t Parcel::writeBlob(size_t len, WritableBlob* outBlob) return status; } +status_t Parcel::writeDupImmutableBlobFileDescriptor(int fd) +{ + // Must match up with what's done in writeBlob. + if (!mAllowFds) return FDS_NOT_ALLOWED; + status_t status = writeInt32(BLOB_ASHMEM_IMMUTABLE); + if (status) return status; + return writeDupFileDescriptor(fd); +} + status_t Parcel::write(const FlattenableHelperInterface& val) { status_t err; @@ -882,6 +972,12 @@ status_t Parcel::write(const FlattenableHelperInterface& val) const size_t len = val.getFlattenedSize(); const size_t fd_count = val.getFdCount(); + if ((len > INT32_MAX) || (fd_count > INT32_MAX)) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + err = this->writeInt32(len); if (err) return err; @@ -889,7 +985,7 @@ status_t Parcel::write(const FlattenableHelperInterface& val) if (err) return err; // payload - void* const buf = this->writeInplace(PAD_SIZE(len)); + void* const buf = this->writeInplace(pad_size(len)); if (buf == NULL) return BAD_VALUE; @@ -918,21 +1014,22 @@ status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData) restart_write: *reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val; - // Need to write meta-data? - if (nullMetaData || val.binder != 0) { - mObjects[mObjectsSize] = mDataPos; - acquire_object(ProcessState::self(), val, this); - mObjectsSize++; - } - // remember if it's a file descriptor if (val.type == BINDER_TYPE_FD) { if (!mAllowFds) { + // fail before modifying our object index return FDS_NOT_ALLOWED; } mHasFds = mFdsKnown = true; } + // Need to write meta-data? + if (nullMetaData || val.binder != 0) { + mObjects[mObjectsSize] = mDataPos; + acquire_object(ProcessState::self(), val, this); + mObjectsSize++; + } + return finishWrite(sizeof(flat_binder_object)); } @@ -964,10 +1061,16 @@ void Parcel::remove(size_t /*start*/, size_t /*amt*/) status_t Parcel::read(void* outData, size_t len) const { - if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize - && len <= PAD_SIZE(len)) { + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + + if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize + && len <= pad_size(len)) { memcpy(outData, mData+mDataPos, len); - mDataPos += PAD_SIZE(len); + mDataPos += pad_size(len); ALOGV("read Setting data pos of %p to %zu", this, mDataPos); return NO_ERROR; } @@ -976,10 +1079,16 @@ status_t Parcel::read(void* outData, size_t len) const const void* Parcel::readInplace(size_t len) const { - if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize - && len <= PAD_SIZE(len)) { + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return NULL; + } + + if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize + && len <= pad_size(len)) { const void* data = mData+mDataPos; - mDataPos += PAD_SIZE(len); + mDataPos += pad_size(len); ALOGV("readInplace Setting data pos of %p to %zu", this, mDataPos); return data; } @@ -988,7 +1097,7 @@ const void* Parcel::readInplace(size_t len) const template<class T> status_t Parcel::readAligned(T *pArg) const { - COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T)); + COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T)); if ((mDataPos+sizeof(T)) <= mDataSize) { const void* data = mData+mDataPos; @@ -1012,7 +1121,7 @@ T Parcel::readAligned() const { template<class T> status_t Parcel::writeAligned(T val) { - COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T)); + COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T)); if ((mDataPos+sizeof(val)) <= mDataCapacity) { restart_write: @@ -1035,6 +1144,15 @@ int32_t Parcel::readInt32() const return readAligned<int32_t>(); } +status_t Parcel::readUint32(uint32_t *pArg) const +{ + return readAligned(pArg); +} + +uint32_t Parcel::readUint32() const +{ + return readAligned<uint32_t>(); +} status_t Parcel::readInt64(int64_t *pArg) const { @@ -1047,6 +1165,16 @@ int64_t Parcel::readInt64() const return readAligned<int64_t>(); } +status_t Parcel::readUint64(uint64_t *pArg) const +{ + return readAligned(pArg); +} + +uint64_t Parcel::readUint64() const +{ + return readAligned<uint64_t>(); +} + status_t Parcel::readPointer(uintptr_t *pArg) const { status_t ret; @@ -1134,7 +1262,7 @@ const char* Parcel::readCString() const const char* eos = reinterpret_cast<const char*>(memchr(str, 0, avail)); if (eos) { const size_t len = eos - str; - mDataPos += PAD_SIZE(len+1); + mDataPos += pad_size(len+1); ALOGV("readCString Setting data pos of %p to %zu", this, mDataPos); return str; } @@ -1254,46 +1382,31 @@ int Parcel::readFileDescriptor() const return BAD_TYPE; } -// WARNING: This method must stay in sync with writeToParcel() -// in frameworks/base/core/java/android/os/ParcelFileDescriptor.java -int Parcel::readParcelFileDescriptor(int& outCommChannel) const { - int fd; - outCommChannel = -1; - - if (readInt32() == 0) { - fd = -1; - } else { - fd = readFileDescriptor(); - if (fd >= 0 && readInt32() != 0) { - outCommChannel = readFileDescriptor(); - } - } - return fd; -} - status_t Parcel::readBlob(size_t len, ReadableBlob* outBlob) const { - int32_t useAshmem; - status_t status = readInt32(&useAshmem); + int32_t blobType; + status_t status = readInt32(&blobType); if (status) return status; - if (!useAshmem) { + if (blobType == BLOB_INPLACE) { ALOGV("readBlob: read in place"); const void* ptr = readInplace(len); if (!ptr) return BAD_VALUE; - outBlob->init(false /*mapped*/, const_cast<void*>(ptr), len); + outBlob->init(-1, const_cast<void*>(ptr), len, false); return NO_ERROR; } ALOGV("readBlob: read from ashmem"); + bool isMutable = (blobType == BLOB_ASHMEM_MUTABLE); int fd = readFileDescriptor(); if (fd == int(BAD_TYPE)) return BAD_VALUE; - void* ptr = ::mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0); + void* ptr = ::mmap(NULL, len, isMutable ? PROT_READ | PROT_WRITE : PROT_READ, + MAP_SHARED, fd, 0); if (ptr == MAP_FAILED) return NO_MEMORY; - outBlob->init(true /*mapped*/, ptr, len); + outBlob->init(fd, ptr, len, isMutable); return NO_ERROR; } @@ -1303,8 +1416,14 @@ status_t Parcel::read(FlattenableHelperInterface& val) const const size_t len = this->readInt32(); const size_t fd_count = this->readInt32(); + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + // payload - void const* const buf = this->readInplace(PAD_SIZE(len)); + void const* const buf = this->readInplace(pad_size(len)); if (buf == NULL) return BAD_VALUE; @@ -1450,7 +1569,7 @@ void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize, for (size_t i = 0; i < mObjectsSize; i++) { binder_size_t offset = mObjects[i]; if (offset < minOffset) { - ALOGE("%s: bad object offset %"PRIu64" < %"PRIu64"\n", + ALOGE("%s: bad object offset %" PRIu64 " < %" PRIu64 "\n", __func__, (uint64_t)offset, (uint64_t)minOffset); mObjectsSize = 0; break; @@ -1543,6 +1662,12 @@ void Parcel::freeDataNoInit() status_t Parcel::growData(size_t len) { + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + size_t newSize = ((mDataSize+len)*3)/2; return (newSize <= mDataSize) ? (status_t) NO_MEMORY @@ -1551,6 +1676,12 @@ status_t Parcel::growData(size_t len) status_t Parcel::restartWrite(size_t desired) { + if (desired > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + if (mOwner) { freeData(); return continueWrite(desired); @@ -1591,6 +1722,12 @@ status_t Parcel::restartWrite(size_t desired) status_t Parcel::continueWrite(size_t desired) { + if (desired > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + // If shrinking, first adjust for any objects that appear // after the new data size. size_t objectsSize = mObjectsSize; @@ -1623,7 +1760,7 @@ status_t Parcel::continueWrite(size_t desired) binder_size_t* objects = NULL; if (objectsSize) { - objects = (binder_size_t*)malloc(objectsSize*sizeof(binder_size_t)); + objects = (binder_size_t*)calloc(objectsSize, sizeof(binder_size_t)); if (!objects) { free(data); @@ -1759,6 +1896,7 @@ void Parcel::initState() mFdsKnown = true; mAllowFds = true; mOwner = NULL; + mBlobAshmemSize = 0; } void Parcel::scanForFds() const @@ -1776,10 +1914,15 @@ void Parcel::scanForFds() const mFdsKnown = true; } +size_t Parcel::getBlobAshmemSize() const +{ + return mBlobAshmemSize; +} + // --- Parcel::Blob --- Parcel::Blob::Blob() : - mMapped(false), mData(NULL), mSize(0) { + mFd(-1), mData(NULL), mSize(0), mMutable(false) { } Parcel::Blob::~Blob() { @@ -1787,22 +1930,24 @@ Parcel::Blob::~Blob() { } void Parcel::Blob::release() { - if (mMapped && mData) { + if (mFd != -1 && mData) { ::munmap(mData, mSize); } clear(); } -void Parcel::Blob::init(bool mapped, void* data, size_t size) { - mMapped = mapped; +void Parcel::Blob::init(int fd, void* data, size_t size, bool isMutable) { + mFd = fd; mData = data; mSize = size; + mMutable = isMutable; } void Parcel::Blob::clear() { - mMapped = false; + mFd = -1; mData = NULL; mSize = 0; + mMutable = false; } }; // namespace android diff --git a/libs/binder/ProcessInfoService.cpp b/libs/binder/ProcessInfoService.cpp new file mode 100644 index 0000000000..fb2864355d --- /dev/null +++ b/libs/binder/ProcessInfoService.cpp @@ -0,0 +1,70 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <binder/ProcessInfoService.h> +#include <binder/IServiceManager.h> + +#include <utils/Log.h> +#include <utils/String16.h> + +namespace android { + +ProcessInfoService::ProcessInfoService() { + updateBinderLocked(); +} + +status_t ProcessInfoService::getProcessStatesImpl(size_t length, /*in*/ int32_t* pids, + /*out*/ int32_t* states) { + status_t err = NO_ERROR; + sp<IProcessInfoService> pis; + mProcessInfoLock.lock(); + pis = mProcessInfoService; + mProcessInfoLock.unlock(); + + for (int i = 0; i < BINDER_ATTEMPT_LIMIT; i++) { + + if (pis != NULL) { + err = pis->getProcessStatesFromPids(length, /*in*/ pids, /*out*/ states); + if (err == NO_ERROR) return NO_ERROR; // success + if (IInterface::asBinder(pis)->isBinderAlive()) return err; + } + sleep(1); + + mProcessInfoLock.lock(); + if (pis == mProcessInfoService) { + updateBinderLocked(); + } + pis = mProcessInfoService; + mProcessInfoLock.unlock(); + } + + ALOGW("%s: Could not retrieve process states from ProcessInfoService after %d retries.", + __FUNCTION__, BINDER_ATTEMPT_LIMIT); + + return TIMED_OUT; +} + +void ProcessInfoService::updateBinderLocked() { + const sp<IServiceManager> sm(defaultServiceManager()); + if (sm != NULL) { + const String16 name("processinfo"); + mProcessInfoService = interface_cast<IProcessInfoService>(sm->checkService(name)); + } +} + +ANDROID_SINGLETON_STATIC_INSTANCE(ProcessInfoService); + +}; // namespace android diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp index 303d6cf3a2..016d3c54b0 100644 --- a/libs/binder/ProcessState.cpp +++ b/libs/binder/ProcessState.cpp @@ -42,12 +42,13 @@ #include <sys/stat.h> #define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2)) +#define DEFAULT_MAX_BINDER_THREADS 15 // --------------------------------------------------------------------------- namespace android { - + class PoolThread : public Thread { public: @@ -294,7 +295,9 @@ void ProcessState::spawnPooledThread(bool isMain) status_t ProcessState::setThreadPoolMaxThreadCount(size_t maxThreads) { status_t result = NO_ERROR; - if (ioctl(mDriverFD, BINDER_SET_MAX_THREADS, &maxThreads) == -1) { + if (ioctl(mDriverFD, BINDER_SET_MAX_THREADS, &maxThreads) != -1) { + mMaxThreads = maxThreads; + } else { result = -errno; ALOGE("Binder ioctl to set max threads failed: %s", strerror(-result)); } @@ -322,7 +325,7 @@ static int open_driver() close(fd); fd = -1; } - size_t maxThreads = 15; + size_t maxThreads = DEFAULT_MAX_BINDER_THREADS; result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads); if (result == -1) { ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno)); @@ -336,6 +339,10 @@ static int open_driver() ProcessState::ProcessState() : mDriverFD(open_driver()) , mVMStart(MAP_FAILED) + , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER) + , mThreadCountDecrement(PTHREAD_COND_INITIALIZER) + , mExecutingThreadsCount(0) + , mMaxThreads(DEFAULT_MAX_BINDER_THREADS) , mManagesContexts(false) , mBinderContextCheckFunc(NULL) , mBinderContextUserData(NULL) diff --git a/libs/binder/tests/Android.mk b/libs/binder/tests/Android.mk new file mode 100644 index 0000000000..36687296fb --- /dev/null +++ b/libs/binder/tests/Android.mk @@ -0,0 +1,34 @@ +# +# Copyright (C) 2014 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. +# + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +ifneq ($(TARGET_USES_64_BIT_BINDER),true) +ifneq ($(TARGET_IS_64_BIT),true) +LOCAL_CFLAGS += -DBINDER_IPC_32BIT=1 +endif +endif + +LOCAL_MODULE := binderDriverInterfaceTest +LOCAL_SRC_FILES := binderDriverInterfaceTest.cpp +include $(BUILD_NATIVE_TEST) + +include $(CLEAR_VARS) +LOCAL_MODULE := binderLibTest +LOCAL_SRC_FILES := binderLibTest.cpp +LOCAL_SHARED_LIBRARIES := libbinder libutils +include $(BUILD_NATIVE_TEST) diff --git a/libs/binder/tests/binderDriverInterfaceTest.cpp b/libs/binder/tests/binderDriverInterfaceTest.cpp new file mode 100644 index 0000000000..315f34956c --- /dev/null +++ b/libs/binder/tests/binderDriverInterfaceTest.cpp @@ -0,0 +1,353 @@ +/* + * Copyright (C) 2014 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 <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> + +#include <gtest/gtest.h> +#include <linux/binder.h> +#include <binder/IBinder.h> +#include <sys/mman.h> +#include <poll.h> + +#define BINDER_DEV_NAME "/dev/binder" + +testing::Environment* binder_env; + +class BinderDriverInterfaceTestEnv : public ::testing::Environment { + virtual void SetUp() { + int ret; + uint32_t max_threads = 0; + + m_binderFd = open(BINDER_DEV_NAME, O_RDWR | O_NONBLOCK); + ASSERT_GE(m_binderFd, 0); + m_buffer = mmap(NULL, 64*1024, PROT_READ, MAP_SHARED, m_binderFd, 0); + ASSERT_NE(m_buffer, (void *)NULL); + ret = ioctl(m_binderFd, BINDER_SET_MAX_THREADS, &max_threads); + EXPECT_EQ(0, ret); + EnterLooper(); + } + virtual void TearDown() { + close(m_binderFd); + } + private: + int m_binderFd; + void *m_buffer; + public: + int getBinderFd(void) { + return m_binderFd; + } + void EnterLooper(void) { + int ret; + const uint32_t bc[] = { + BC_ENTER_LOOPER, + }; + struct binder_write_read bwr = binder_write_read(); + bwr.write_buffer = (uintptr_t)bc; + bwr.write_size = sizeof(bc); + ret = ioctl(m_binderFd, BINDER_WRITE_READ, &bwr); + EXPECT_EQ(0, ret); + if (ret < 0) { + EXPECT_EQ(0, errno); + } + EXPECT_EQ(sizeof(bc), bwr.write_consumed); + } +}; + +class BinderDriverInterfaceTest : public ::testing::Test { + public: + virtual void SetUp() { + m_binderFd = static_cast<BinderDriverInterfaceTestEnv *>(binder_env)->getBinderFd(); + } + virtual void TearDown() { + } + protected: + void binderTestIoctlRetErr2(int cmd, void *arg, int expect_ret, int expect_errno, int accept_errno) { + int ret; + + ret = ioctl(m_binderFd, cmd, arg); + EXPECT_EQ(expect_ret, ret); + if (ret < 0) { + if (errno != accept_errno) + EXPECT_EQ(expect_errno, errno); + } + } + void binderTestIoctlErr2(int cmd, void *arg, int expect_errno, int accept_errno) { + binderTestIoctlRetErr2(cmd, arg, -1, expect_errno, accept_errno); + } + void binderTestIoctlErr1(int cmd, void *arg, int expect_errno) { + binderTestIoctlErr2(cmd, arg, expect_errno, expect_errno); + } + void binderTestIoctl(int cmd, void *arg) { + binderTestIoctlRetErr2(cmd, arg, 0, 0, 0); + } + void binderTestIoctlUnimplemented(int cmd, void *arg) { + int ret; + + ret = ioctl(m_binderFd, cmd, arg); + if (ret < 0) { + /* Not currently implmented. Allow ret == -1, errno == EINVAL */ + EXPECT_EQ(-1, ret); + EXPECT_EQ(EINVAL, errno); + } + } + void binderTestReadEmpty(void) { + size_t i; + uint32_t br[32]; + struct binder_write_read bwr = binder_write_read(); + SCOPED_TRACE("TestReadEmpty"); + bwr.read_buffer = (uintptr_t)br; + bwr.read_size = sizeof(br); + binderTestIoctlErr1(BINDER_WRITE_READ, &bwr, EAGAIN); + EXPECT_EQ(0u, bwr.read_consumed); + for (i = 0; i * sizeof(uint32_t) < bwr.read_consumed; i++) { + SCOPED_TRACE(testing::Message() << "i = " << i); + EXPECT_EQ(BR_NOOP, br[i]); + } + } + void binderWaitForReadData(int timeout_ms) { + int ret; + pollfd pfd = pollfd(); + + pfd.fd = m_binderFd; + pfd.events = POLLIN; + ret = poll(&pfd, 1, timeout_ms); + EXPECT_EQ(1, ret); + } + private: + int m_binderFd; +}; + +TEST_F(BinderDriverInterfaceTest, Version) { + struct binder_version version; + binderTestIoctl(BINDER_VERSION, &version); + ASSERT_EQ(BINDER_CURRENT_PROTOCOL_VERSION, version.protocol_version); +} + +TEST_F(BinderDriverInterfaceTest, WriteReadNull) { + binderTestIoctlErr1(BINDER_WRITE_READ, NULL, EFAULT); +} + +TEST_F(BinderDriverInterfaceTest, SetIdleTimeoutNull) { + binderTestIoctlErr2(BINDER_SET_IDLE_TIMEOUT, NULL, EFAULT, EINVAL); +} + +TEST_F(BinderDriverInterfaceTest, SetMaxThreadsNull) { + binderTestIoctlErr2(BINDER_SET_MAX_THREADS, NULL, EFAULT, EINVAL); /* TODO: don't accept EINVAL */ +} + +TEST_F(BinderDriverInterfaceTest, SetIdlePriorityNull) { + binderTestIoctlErr2(BINDER_SET_IDLE_PRIORITY, NULL, EFAULT, EINVAL); +} + +TEST_F(BinderDriverInterfaceTest, VersionNull) { + binderTestIoctlErr2(BINDER_VERSION, NULL, EFAULT, EINVAL); /* TODO: don't accept EINVAL */ +} + +TEST_F(BinderDriverInterfaceTest, SetIdleTimeoutNoTest) { + int64_t idle_timeout = 100000; + binderTestIoctlUnimplemented(BINDER_SET_IDLE_TIMEOUT, &idle_timeout); +} + +TEST_F(BinderDriverInterfaceTest, SetMaxThreads) { + uint32_t max_threads = 0; + binderTestIoctl(BINDER_SET_MAX_THREADS, &max_threads); +} + +TEST_F(BinderDriverInterfaceTest, SetIdlePriorityNoTest) { + int idle_priority = 0; + binderTestIoctlUnimplemented(BINDER_SET_IDLE_PRIORITY, &idle_priority); +} + +TEST_F(BinderDriverInterfaceTest, SetContextMgrBusy) { + int32_t dummy = 0; + binderTestIoctlErr1(BINDER_SET_CONTEXT_MGR, &dummy, EBUSY); +} + +TEST_F(BinderDriverInterfaceTest, ThreadExit) { + int32_t dummy = 0; + binderTestIoctl(BINDER_THREAD_EXIT, &dummy); + static_cast<BinderDriverInterfaceTestEnv *>(binder_env)->EnterLooper(); +} + +TEST_F(BinderDriverInterfaceTest, WriteReadEmpty) { + struct binder_write_read bwr = binder_write_read(); + binderTestIoctl(BINDER_WRITE_READ, &bwr); +} + +TEST_F(BinderDriverInterfaceTest, Read) { + binderTestReadEmpty(); +} + +TEST_F(BinderDriverInterfaceTest, IncRefsAcquireReleaseDecRefs) { + const uint32_t bc[] = { + BC_INCREFS, + 0, + BC_ACQUIRE, + 0, + BC_RELEASE, + 0, + BC_DECREFS, + 0, + }; + struct binder_write_read bwr = binder_write_read(); + bwr.write_buffer = (uintptr_t)bc; + bwr.write_size = sizeof(bc); + binderTestIoctl(BINDER_WRITE_READ, &bwr); + EXPECT_EQ(sizeof(bc), bwr.write_consumed); + binderTestReadEmpty(); +} + +TEST_F(BinderDriverInterfaceTest, Transaction) { + binder_uintptr_t cookie = 1234; + struct { + uint32_t cmd1; + struct binder_transaction_data arg1; + } __attribute__((packed)) bc1 = { + .cmd1 = BC_TRANSACTION, + .arg1 = { + .target = { 0 }, + .cookie = 0, + .code = android::IBinder::PING_TRANSACTION, + .flags = 0, + .sender_pid = 0, + .sender_euid = 0, + .data_size = 0, + .offsets_size = 0, + .data = {0, 0}, + }, + }; + struct { + uint32_t cmd0; + uint32_t cmd1; + uint32_t cmd2; + binder_transaction_data arg2; + uint32_t pad[16]; + } __attribute__((packed)) br; + struct binder_write_read bwr = binder_write_read(); + + bwr.write_buffer = (uintptr_t)&bc1; + bwr.write_size = sizeof(bc1); + bwr.read_buffer = (uintptr_t)&br; + bwr.read_size = sizeof(br); + + { + SCOPED_TRACE("1st WriteRead"); + binderTestIoctl(BINDER_WRITE_READ, &bwr); + } + EXPECT_EQ(sizeof(bc1), bwr.write_consumed); + if (bwr.read_consumed < offsetof(typeof(br), pad)) { + SCOPED_TRACE("2nd WriteRead"); + binderWaitForReadData(10000); + binderTestIoctl(BINDER_WRITE_READ, &bwr); + } + EXPECT_EQ(offsetof(typeof(br), pad), bwr.read_consumed); + if (bwr.read_consumed > offsetof(typeof(br), cmd0)) + EXPECT_EQ(BR_NOOP, br.cmd0); + if (bwr.read_consumed > offsetof(typeof(br), cmd1)) + EXPECT_EQ(BR_TRANSACTION_COMPLETE, br.cmd1); + if (bwr.read_consumed > offsetof(typeof(br), cmd2)) + EXPECT_EQ(BR_REPLY, br.cmd2); + if (bwr.read_consumed >= offsetof(typeof(br), pad)) { + EXPECT_EQ(0u, br.arg2.target.ptr); + EXPECT_EQ(0u, br.arg2.cookie); + EXPECT_EQ(0u, br.arg2.code); + EXPECT_EQ(0u, br.arg2.flags); + EXPECT_EQ(0u, br.arg2.data_size); + EXPECT_EQ(0u, br.arg2.offsets_size); + + SCOPED_TRACE("3rd WriteRead"); + + binderTestReadEmpty(); + + struct { + uint32_t cmd1; + binder_uintptr_t arg1; + } __attribute__((packed)) bc2 = { + .cmd1 = BC_FREE_BUFFER, + .arg1 = br.arg2.data.ptr.buffer, + }; + + bwr.write_buffer = (uintptr_t)&bc2; + bwr.write_size = sizeof(bc2); + bwr.write_consumed = 0; + bwr.read_size = 0; + + binderTestIoctl(BINDER_WRITE_READ, &bwr); + EXPECT_EQ(sizeof(bc2), bwr.write_consumed); + } + binderTestReadEmpty(); +} + +TEST_F(BinderDriverInterfaceTest, RequestDeathNotification) { + binder_uintptr_t cookie = 1234; + struct { + uint32_t cmd0; + uint32_t arg0; + uint32_t cmd1; + struct binder_handle_cookie arg1; + uint32_t cmd2; + struct binder_handle_cookie arg2; + uint32_t cmd3; + uint32_t arg3; + } __attribute__((packed)) bc = { + .cmd0 = BC_INCREFS, + .arg0 = 0, + .cmd1 = BC_REQUEST_DEATH_NOTIFICATION, + .arg1 = { + .handle = 0, + .cookie = cookie, + }, + .cmd2 = BC_CLEAR_DEATH_NOTIFICATION, + .arg2 = { + .handle = 0, + .cookie = cookie, + }, + .cmd3 = BC_DECREFS, + .arg3 = 0, + }; + struct { + uint32_t cmd0; + uint32_t cmd1; + binder_uintptr_t arg1; + uint32_t pad[16]; + } __attribute__((packed)) br; + struct binder_write_read bwr = binder_write_read(); + + bwr.write_buffer = (uintptr_t)&bc; + bwr.write_size = sizeof(bc); + bwr.read_buffer = (uintptr_t)&br; + bwr.read_size = sizeof(br); + + binderTestIoctl(BINDER_WRITE_READ, &bwr); + EXPECT_EQ(sizeof(bc), bwr.write_consumed); + EXPECT_EQ(sizeof(br) - sizeof(br.pad), bwr.read_consumed); + EXPECT_EQ(BR_NOOP, br.cmd0); + EXPECT_EQ(BR_CLEAR_DEATH_NOTIFICATION_DONE, br.cmd1); + EXPECT_EQ(cookie, br.arg1); + binderTestReadEmpty(); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + + binder_env = AddGlobalTestEnvironment(new BinderDriverInterfaceTestEnv()); + + return RUN_ALL_TESTS(); +} + diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp new file mode 100644 index 0000000000..3df3acf9db --- /dev/null +++ b/libs/binder/tests/binderLibTest.cpp @@ -0,0 +1,954 @@ +/* + * Copyright (C) 2014 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 <errno.h> +#include <fcntl.h> +#include <poll.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + +#include <gtest/gtest.h> + +#include <binder/Binder.h> +#include <binder/IBinder.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> + +#define ARRAY_SIZE(array) (sizeof array / sizeof array[0]) + +using namespace android; + +static testing::Environment* binder_env; +static char *binderservername; +static char binderserverarg[] = "--binderserver"; + +static String16 binderLibTestServiceName = String16("test.binderLib"); + +enum BinderLibTestTranscationCode { + BINDER_LIB_TEST_NOP_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, + BINDER_LIB_TEST_REGISTER_SERVER, + BINDER_LIB_TEST_ADD_SERVER, + BINDER_LIB_TEST_CALL_BACK, + BINDER_LIB_TEST_NOP_CALL_BACK, + BINDER_LIB_TEST_GET_ID_TRANSACTION, + BINDER_LIB_TEST_INDIRECT_TRANSACTION, + BINDER_LIB_TEST_SET_ERROR_TRANSACTION, + BINDER_LIB_TEST_GET_STATUS_TRANSACTION, + BINDER_LIB_TEST_ADD_STRONG_REF_TRANSACTION, + BINDER_LIB_TEST_LINK_DEATH_TRANSACTION, + BINDER_LIB_TEST_WRITE_FILE_TRANSACTION, + BINDER_LIB_TEST_PROMOTE_WEAK_REF_TRANSACTION, + BINDER_LIB_TEST_EXIT_TRANSACTION, + BINDER_LIB_TEST_DELAYED_EXIT_TRANSACTION, + BINDER_LIB_TEST_GET_PTR_SIZE_TRANSACTION, +}; + +pid_t start_server_process(int arg2) +{ + int ret; + pid_t pid; + status_t status; + int pipefd[2]; + char stri[16]; + char strpipefd1[16]; + char *childargv[] = { + binderservername, + binderserverarg, + stri, + strpipefd1, + NULL + }; + + ret = pipe(pipefd); + if (ret < 0) + return ret; + + snprintf(stri, sizeof(stri), "%d", arg2); + snprintf(strpipefd1, sizeof(strpipefd1), "%d", pipefd[1]); + + pid = fork(); + if (pid == -1) + return pid; + if (pid == 0) { + close(pipefd[0]); + execv(binderservername, childargv); + status = -errno; + write(pipefd[1], &status, sizeof(status)); + fprintf(stderr, "execv failed, %s\n", strerror(errno)); + _exit(EXIT_FAILURE); + } + close(pipefd[1]); + ret = read(pipefd[0], &status, sizeof(status)); + //printf("pipe read returned %d, status %d\n", ret, status); + close(pipefd[0]); + if (ret == sizeof(status)) { + ret = status; + } else { + kill(pid, SIGKILL); + if (ret >= 0) { + ret = NO_INIT; + } + } + if (ret < 0) { + wait(NULL); + return ret; + } + return pid; +} + +class BinderLibTestEnv : public ::testing::Environment { + public: + BinderLibTestEnv() {} + sp<IBinder> getServer(void) { + return m_server; + } + + private: + virtual void SetUp() { + m_serverpid = start_server_process(0); + //printf("m_serverpid %d\n", m_serverpid); + ASSERT_GT(m_serverpid, 0); + + sp<IServiceManager> sm = defaultServiceManager(); + //printf("%s: pid %d, get service\n", __func__, m_pid); + m_server = sm->getService(binderLibTestServiceName); + ASSERT_TRUE(m_server != NULL); + //printf("%s: pid %d, get service done\n", __func__, m_pid); + } + virtual void TearDown() { + status_t ret; + Parcel data, reply; + int exitStatus; + pid_t pid; + + //printf("%s: pid %d\n", __func__, m_pid); + if (m_server != NULL) { + ret = m_server->transact(BINDER_LIB_TEST_GET_STATUS_TRANSACTION, data, &reply); + EXPECT_EQ(0, ret); + ret = m_server->transact(BINDER_LIB_TEST_EXIT_TRANSACTION, data, &reply, TF_ONE_WAY); + EXPECT_EQ(0, ret); + } + if (m_serverpid > 0) { + //printf("wait for %d\n", m_pids[i]); + pid = wait(&exitStatus); + EXPECT_EQ(m_serverpid, pid); + EXPECT_TRUE(WIFEXITED(exitStatus)); + EXPECT_EQ(0, WEXITSTATUS(exitStatus)); + } + } + + pid_t m_serverpid; + sp<IBinder> m_server; +}; + +class BinderLibTest : public ::testing::Test { + public: + virtual void SetUp() { + m_server = static_cast<BinderLibTestEnv *>(binder_env)->getServer(); + } + virtual void TearDown() { + } + protected: + sp<IBinder> addServer(int32_t *idPtr = NULL) + { + int ret; + int32_t id; + Parcel data, reply; + sp<IBinder> binder; + + ret = m_server->transact(BINDER_LIB_TEST_ADD_SERVER, data, &reply); + EXPECT_EQ(NO_ERROR, ret); + + EXPECT_FALSE(binder != NULL); + binder = reply.readStrongBinder(); + EXPECT_TRUE(binder != NULL); + ret = reply.readInt32(&id); + EXPECT_EQ(NO_ERROR, ret); + if (idPtr) + *idPtr = id; + return binder; + } + void waitForReadData(int fd, int timeout_ms) { + int ret; + pollfd pfd = pollfd(); + + pfd.fd = fd; + pfd.events = POLLIN; + ret = poll(&pfd, 1, timeout_ms); + EXPECT_EQ(1, ret); + } + + sp<IBinder> m_server; +}; + +class BinderLibTestBundle : public Parcel +{ + public: + BinderLibTestBundle(void) {} + BinderLibTestBundle(const Parcel *source) : m_isValid(false) { + int32_t mark; + int32_t bundleLen; + size_t pos; + + if (source->readInt32(&mark)) + return; + if (mark != MARK_START) + return; + if (source->readInt32(&bundleLen)) + return; + pos = source->dataPosition(); + if (Parcel::appendFrom(source, pos, bundleLen)) + return; + source->setDataPosition(pos + bundleLen); + if (source->readInt32(&mark)) + return; + if (mark != MARK_END) + return; + m_isValid = true; + setDataPosition(0); + } + void appendTo(Parcel *dest) { + dest->writeInt32(MARK_START); + dest->writeInt32(dataSize()); + dest->appendFrom(this, 0, dataSize()); + dest->writeInt32(MARK_END); + }; + bool isValid(void) { + return m_isValid; + } + private: + enum { + MARK_START = B_PACK_CHARS('B','T','B','S'), + MARK_END = B_PACK_CHARS('B','T','B','E'), + }; + bool m_isValid; +}; + +class BinderLibTestEvent +{ + public: + BinderLibTestEvent(void) + : m_eventTriggered(false) + { + pthread_mutex_init(&m_waitMutex, NULL); + pthread_cond_init(&m_waitCond, NULL); + } + int waitEvent(int timeout_s) + { + int ret; + pthread_mutex_lock(&m_waitMutex); + if (!m_eventTriggered) { +#if defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE) + pthread_cond_timeout_np(&m_waitCond, &m_waitMutex, timeout_s * 1000); +#else + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += timeout_s; + pthread_cond_timedwait(&m_waitCond, &m_waitMutex, &ts); +#endif + } + ret = m_eventTriggered ? NO_ERROR : TIMED_OUT; + pthread_mutex_unlock(&m_waitMutex); + return ret; + } + protected: + void triggerEvent(void) { + pthread_mutex_lock(&m_waitMutex); + pthread_cond_signal(&m_waitCond); + m_eventTriggered = true; + pthread_mutex_unlock(&m_waitMutex); + }; + private: + pthread_mutex_t m_waitMutex; + pthread_cond_t m_waitCond; + bool m_eventTriggered; +}; + +class BinderLibTestCallBack : public BBinder, public BinderLibTestEvent +{ + public: + BinderLibTestCallBack() + : m_result(NOT_ENOUGH_DATA) + { + } + status_t getResult(void) + { + return m_result; + } + + private: + virtual status_t onTransact(uint32_t code, + const Parcel& data, Parcel* reply, + uint32_t flags = 0) + { + (void)reply; + (void)flags; + switch(code) { + case BINDER_LIB_TEST_CALL_BACK: + m_result = data.readInt32(); + triggerEvent(); + return NO_ERROR; + default: + return UNKNOWN_TRANSACTION; + } + } + + status_t m_result; +}; + +class TestDeathRecipient : public IBinder::DeathRecipient, public BinderLibTestEvent +{ + private: + virtual void binderDied(const wp<IBinder>& who) { + (void)who; + triggerEvent(); + }; +}; + +TEST_F(BinderLibTest, NopTransaction) { + status_t ret; + Parcel data, reply; + ret = m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply); + EXPECT_EQ(NO_ERROR, ret); +} + +TEST_F(BinderLibTest, SetError) { + int32_t testValue[] = { 0, -123, 123 }; + for (size_t i = 0; i < ARRAY_SIZE(testValue); i++) { + status_t ret; + Parcel data, reply; + data.writeInt32(testValue[i]); + ret = m_server->transact(BINDER_LIB_TEST_SET_ERROR_TRANSACTION, data, &reply); + EXPECT_EQ(testValue[i], ret); + } +} + +TEST_F(BinderLibTest, GetId) { + status_t ret; + int32_t id; + Parcel data, reply; + ret = m_server->transact(BINDER_LIB_TEST_GET_ID_TRANSACTION, data, &reply); + EXPECT_EQ(NO_ERROR, ret); + ret = reply.readInt32(&id); + EXPECT_EQ(NO_ERROR, ret); + EXPECT_EQ(0, id); +} + +TEST_F(BinderLibTest, PtrSize) { + status_t ret; + int32_t ptrsize; + Parcel data, reply; + sp<IBinder> server = addServer(); + ASSERT_TRUE(server != NULL); + ret = server->transact(BINDER_LIB_TEST_GET_PTR_SIZE_TRANSACTION, data, &reply); + EXPECT_EQ(NO_ERROR, ret); + ret = reply.readInt32(&ptrsize); + EXPECT_EQ(NO_ERROR, ret); + RecordProperty("TestPtrSize", sizeof(void *)); + RecordProperty("ServerPtrSize", sizeof(void *)); +} + +TEST_F(BinderLibTest, IndirectGetId2) +{ + status_t ret; + int32_t id; + int32_t count; + Parcel data, reply; + int32_t serverId[3]; + + data.writeInt32(ARRAY_SIZE(serverId)); + for (size_t i = 0; i < ARRAY_SIZE(serverId); i++) { + sp<IBinder> server; + BinderLibTestBundle datai; + + server = addServer(&serverId[i]); + ASSERT_TRUE(server != NULL); + data.writeStrongBinder(server); + data.writeInt32(BINDER_LIB_TEST_GET_ID_TRANSACTION); + datai.appendTo(&data); + } + + ret = m_server->transact(BINDER_LIB_TEST_INDIRECT_TRANSACTION, data, &reply); + ASSERT_EQ(NO_ERROR, ret); + + ret = reply.readInt32(&id); + ASSERT_EQ(NO_ERROR, ret); + EXPECT_EQ(0, id); + + ret = reply.readInt32(&count); + ASSERT_EQ(NO_ERROR, ret); + EXPECT_EQ(ARRAY_SIZE(serverId), count); + + for (size_t i = 0; i < (size_t)count; i++) { + BinderLibTestBundle replyi(&reply); + EXPECT_TRUE(replyi.isValid()); + ret = replyi.readInt32(&id); + EXPECT_EQ(NO_ERROR, ret); + EXPECT_EQ(serverId[i], id); + EXPECT_EQ(replyi.dataSize(), replyi.dataPosition()); + } + + EXPECT_EQ(reply.dataSize(), reply.dataPosition()); +} + +TEST_F(BinderLibTest, IndirectGetId3) +{ + status_t ret; + int32_t id; + int32_t count; + Parcel data, reply; + int32_t serverId[3]; + + data.writeInt32(ARRAY_SIZE(serverId)); + for (size_t i = 0; i < ARRAY_SIZE(serverId); i++) { + sp<IBinder> server; + BinderLibTestBundle datai; + BinderLibTestBundle datai2; + + server = addServer(&serverId[i]); + ASSERT_TRUE(server != NULL); + data.writeStrongBinder(server); + data.writeInt32(BINDER_LIB_TEST_INDIRECT_TRANSACTION); + + datai.writeInt32(1); + datai.writeStrongBinder(m_server); + datai.writeInt32(BINDER_LIB_TEST_GET_ID_TRANSACTION); + datai2.appendTo(&datai); + + datai.appendTo(&data); + } + + ret = m_server->transact(BINDER_LIB_TEST_INDIRECT_TRANSACTION, data, &reply); + ASSERT_EQ(NO_ERROR, ret); + + ret = reply.readInt32(&id); + ASSERT_EQ(NO_ERROR, ret); + EXPECT_EQ(0, id); + + ret = reply.readInt32(&count); + ASSERT_EQ(NO_ERROR, ret); + EXPECT_EQ(ARRAY_SIZE(serverId), count); + + for (size_t i = 0; i < (size_t)count; i++) { + int32_t counti; + + BinderLibTestBundle replyi(&reply); + EXPECT_TRUE(replyi.isValid()); + ret = replyi.readInt32(&id); + EXPECT_EQ(NO_ERROR, ret); + EXPECT_EQ(serverId[i], id); + + ret = replyi.readInt32(&counti); + ASSERT_EQ(NO_ERROR, ret); + EXPECT_EQ(1, counti); + + BinderLibTestBundle replyi2(&replyi); + EXPECT_TRUE(replyi2.isValid()); + ret = replyi2.readInt32(&id); + EXPECT_EQ(NO_ERROR, ret); + EXPECT_EQ(0, id); + EXPECT_EQ(replyi2.dataSize(), replyi2.dataPosition()); + + EXPECT_EQ(replyi.dataSize(), replyi.dataPosition()); + } + + EXPECT_EQ(reply.dataSize(), reply.dataPosition()); +} + +TEST_F(BinderLibTest, CallBack) +{ + status_t ret; + Parcel data, reply; + sp<BinderLibTestCallBack> callBack = new BinderLibTestCallBack(); + data.writeStrongBinder(callBack); + ret = m_server->transact(BINDER_LIB_TEST_NOP_CALL_BACK, data, &reply, TF_ONE_WAY); + EXPECT_EQ(NO_ERROR, ret); + ret = callBack->waitEvent(5); + EXPECT_EQ(NO_ERROR, ret); + ret = callBack->getResult(); + EXPECT_EQ(NO_ERROR, ret); +} + +TEST_F(BinderLibTest, AddServer) +{ + sp<IBinder> server = addServer(); + ASSERT_TRUE(server != NULL); +} + +TEST_F(BinderLibTest, DeathNotificationNoRefs) +{ + status_t ret; + + sp<TestDeathRecipient> testDeathRecipient = new TestDeathRecipient(); + + { + sp<IBinder> binder = addServer(); + ASSERT_TRUE(binder != NULL); + ret = binder->linkToDeath(testDeathRecipient); + EXPECT_EQ(NO_ERROR, ret); + } + IPCThreadState::self()->flushCommands(); + ret = testDeathRecipient->waitEvent(5); + EXPECT_EQ(NO_ERROR, ret); +#if 0 /* Is there an unlink api that does not require a strong reference? */ + ret = binder->unlinkToDeath(testDeathRecipient); + EXPECT_EQ(NO_ERROR, ret); +#endif +} + +TEST_F(BinderLibTest, DeathNotificationWeakRef) +{ + status_t ret; + wp<IBinder> wbinder; + + sp<TestDeathRecipient> testDeathRecipient = new TestDeathRecipient(); + + { + sp<IBinder> binder = addServer(); + ASSERT_TRUE(binder != NULL); + ret = binder->linkToDeath(testDeathRecipient); + EXPECT_EQ(NO_ERROR, ret); + wbinder = binder; + } + IPCThreadState::self()->flushCommands(); + ret = testDeathRecipient->waitEvent(5); + EXPECT_EQ(NO_ERROR, ret); +#if 0 /* Is there an unlink api that does not require a strong reference? */ + ret = binder->unlinkToDeath(testDeathRecipient); + EXPECT_EQ(NO_ERROR, ret); +#endif +} + +TEST_F(BinderLibTest, DeathNotificationStrongRef) +{ + status_t ret; + sp<IBinder> sbinder; + + sp<TestDeathRecipient> testDeathRecipient = new TestDeathRecipient(); + + { + sp<IBinder> binder = addServer(); + ASSERT_TRUE(binder != NULL); + ret = binder->linkToDeath(testDeathRecipient); + EXPECT_EQ(NO_ERROR, ret); + sbinder = binder; + } + { + Parcel data, reply; + ret = sbinder->transact(BINDER_LIB_TEST_EXIT_TRANSACTION, data, &reply, TF_ONE_WAY); + EXPECT_EQ(0, ret); + } + IPCThreadState::self()->flushCommands(); + ret = testDeathRecipient->waitEvent(5); + EXPECT_EQ(NO_ERROR, ret); + ret = sbinder->unlinkToDeath(testDeathRecipient); + EXPECT_EQ(DEAD_OBJECT, ret); +} + +TEST_F(BinderLibTest, DeathNotificationMultiple) +{ + status_t ret; + const int clientcount = 2; + sp<IBinder> target; + sp<IBinder> linkedclient[clientcount]; + sp<BinderLibTestCallBack> callBack[clientcount]; + sp<IBinder> passiveclient[clientcount]; + + target = addServer(); + ASSERT_TRUE(target != NULL); + for (int i = 0; i < clientcount; i++) { + { + Parcel data, reply; + + linkedclient[i] = addServer(); + ASSERT_TRUE(linkedclient[i] != NULL); + callBack[i] = new BinderLibTestCallBack(); + data.writeStrongBinder(target); + data.writeStrongBinder(callBack[i]); + ret = linkedclient[i]->transact(BINDER_LIB_TEST_LINK_DEATH_TRANSACTION, data, &reply, TF_ONE_WAY); + EXPECT_EQ(NO_ERROR, ret); + } + { + Parcel data, reply; + + passiveclient[i] = addServer(); + ASSERT_TRUE(passiveclient[i] != NULL); + data.writeStrongBinder(target); + ret = passiveclient[i]->transact(BINDER_LIB_TEST_ADD_STRONG_REF_TRANSACTION, data, &reply, TF_ONE_WAY); + EXPECT_EQ(NO_ERROR, ret); + } + } + { + Parcel data, reply; + ret = target->transact(BINDER_LIB_TEST_EXIT_TRANSACTION, data, &reply, TF_ONE_WAY); + EXPECT_EQ(0, ret); + } + + for (int i = 0; i < clientcount; i++) { + ret = callBack[i]->waitEvent(5); + EXPECT_EQ(NO_ERROR, ret); + ret = callBack[i]->getResult(); + EXPECT_EQ(NO_ERROR, ret); + } +} + +TEST_F(BinderLibTest, PassFile) { + int ret; + int pipefd[2]; + uint8_t buf[1] = { 0 }; + uint8_t write_value = 123; + + ret = pipe2(pipefd, O_NONBLOCK); + ASSERT_EQ(0, ret); + + { + Parcel data, reply; + uint8_t writebuf[1] = { write_value }; + + ret = data.writeFileDescriptor(pipefd[1], true); + EXPECT_EQ(NO_ERROR, ret); + + ret = data.writeInt32(sizeof(writebuf)); + EXPECT_EQ(NO_ERROR, ret); + + ret = data.write(writebuf, sizeof(writebuf)); + EXPECT_EQ(NO_ERROR, ret); + + ret = m_server->transact(BINDER_LIB_TEST_WRITE_FILE_TRANSACTION, data, &reply); + EXPECT_EQ(NO_ERROR, ret); + } + + ret = read(pipefd[0], buf, sizeof(buf)); + EXPECT_EQ(sizeof(buf), ret); + EXPECT_EQ(write_value, buf[0]); + + waitForReadData(pipefd[0], 5000); /* wait for other proccess to close pipe */ + + ret = read(pipefd[0], buf, sizeof(buf)); + EXPECT_EQ(0, ret); + + close(pipefd[0]); +} + +TEST_F(BinderLibTest, PromoteLocal) { + sp<IBinder> strong = new BBinder(); + wp<IBinder> weak = strong; + sp<IBinder> strong_from_weak = weak.promote(); + EXPECT_TRUE(strong != NULL); + EXPECT_EQ(strong, strong_from_weak); + strong = NULL; + strong_from_weak = NULL; + strong_from_weak = weak.promote(); + EXPECT_TRUE(strong_from_weak == NULL); +} + +TEST_F(BinderLibTest, PromoteRemote) { + int ret; + Parcel data, reply; + sp<IBinder> strong = new BBinder(); + sp<IBinder> server = addServer(); + + ASSERT_TRUE(server != NULL); + ASSERT_TRUE(strong != NULL); + + ret = data.writeWeakBinder(strong); + EXPECT_EQ(NO_ERROR, ret); + + ret = server->transact(BINDER_LIB_TEST_PROMOTE_WEAK_REF_TRANSACTION, data, &reply); + EXPECT_GE(ret, 0); +} + +class BinderLibTestService : public BBinder +{ + public: + BinderLibTestService(int32_t id) + : m_id(id) + , m_nextServerId(id + 1) + , m_serverStartRequested(false) + { + pthread_mutex_init(&m_serverWaitMutex, NULL); + pthread_cond_init(&m_serverWaitCond, NULL); + } + ~BinderLibTestService() + { + exit(EXIT_SUCCESS); + } + virtual status_t onTransact(uint32_t code, + const Parcel& data, Parcel* reply, + uint32_t flags = 0) { + //printf("%s: code %d\n", __func__, code); + (void)flags; + + if (getuid() != (uid_t)IPCThreadState::self()->getCallingUid()) { + return PERMISSION_DENIED; + } + switch (code) { + case BINDER_LIB_TEST_REGISTER_SERVER: { + int32_t id; + sp<IBinder> binder; + id = data.readInt32(); + binder = data.readStrongBinder(); + if (binder == NULL) { + return BAD_VALUE; + } + + if (m_id != 0) + return INVALID_OPERATION; + + pthread_mutex_lock(&m_serverWaitMutex); + if (m_serverStartRequested) { + m_serverStartRequested = false; + m_serverStarted = binder; + pthread_cond_signal(&m_serverWaitCond); + } + pthread_mutex_unlock(&m_serverWaitMutex); + return NO_ERROR; + } + case BINDER_LIB_TEST_ADD_SERVER: { + int ret; + uint8_t buf[1] = { 0 }; + int serverid; + + if (m_id != 0) { + return INVALID_OPERATION; + } + pthread_mutex_lock(&m_serverWaitMutex); + if (m_serverStartRequested) { + ret = -EBUSY; + } else { + serverid = m_nextServerId++; + m_serverStartRequested = true; + + pthread_mutex_unlock(&m_serverWaitMutex); + ret = start_server_process(serverid); + pthread_mutex_lock(&m_serverWaitMutex); + } + if (ret > 0) { + if (m_serverStartRequested) { +#if defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE) + ret = pthread_cond_timeout_np(&m_serverWaitCond, &m_serverWaitMutex, 5000); +#else + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += 5; + ret = pthread_cond_timedwait(&m_serverWaitCond, &m_serverWaitMutex, &ts); +#endif + } + if (m_serverStartRequested) { + m_serverStartRequested = false; + ret = -ETIMEDOUT; + } else { + reply->writeStrongBinder(m_serverStarted); + reply->writeInt32(serverid); + m_serverStarted = NULL; + ret = NO_ERROR; + } + } else if (ret >= 0) { + m_serverStartRequested = false; + ret = UNKNOWN_ERROR; + } + pthread_mutex_unlock(&m_serverWaitMutex); + return ret; + } + case BINDER_LIB_TEST_NOP_TRANSACTION: + return NO_ERROR; + case BINDER_LIB_TEST_NOP_CALL_BACK: { + Parcel data2, reply2; + sp<IBinder> binder; + binder = data.readStrongBinder(); + if (binder == NULL) { + return BAD_VALUE; + } + reply2.writeInt32(NO_ERROR); + binder->transact(BINDER_LIB_TEST_CALL_BACK, data2, &reply2); + return NO_ERROR; + } + case BINDER_LIB_TEST_GET_ID_TRANSACTION: + reply->writeInt32(m_id); + return NO_ERROR; + case BINDER_LIB_TEST_INDIRECT_TRANSACTION: { + int32_t count; + uint32_t indirect_code; + sp<IBinder> binder; + + count = data.readInt32(); + reply->writeInt32(m_id); + reply->writeInt32(count); + for (int i = 0; i < count; i++) { + binder = data.readStrongBinder(); + if (binder == NULL) { + return BAD_VALUE; + } + indirect_code = data.readInt32(); + BinderLibTestBundle data2(&data); + if (!data2.isValid()) { + return BAD_VALUE; + } + BinderLibTestBundle reply2; + binder->transact(indirect_code, data2, &reply2); + reply2.appendTo(reply); + } + return NO_ERROR; + } + case BINDER_LIB_TEST_SET_ERROR_TRANSACTION: + reply->setError(data.readInt32()); + return NO_ERROR; + case BINDER_LIB_TEST_GET_PTR_SIZE_TRANSACTION: + reply->writeInt32(sizeof(void *)); + return NO_ERROR; + case BINDER_LIB_TEST_GET_STATUS_TRANSACTION: + return NO_ERROR; + case BINDER_LIB_TEST_ADD_STRONG_REF_TRANSACTION: + m_strongRef = data.readStrongBinder(); + return NO_ERROR; + case BINDER_LIB_TEST_LINK_DEATH_TRANSACTION: { + int ret; + Parcel data2, reply2; + sp<TestDeathRecipient> testDeathRecipient = new TestDeathRecipient(); + sp<IBinder> target; + sp<IBinder> callback; + + target = data.readStrongBinder(); + if (target == NULL) { + return BAD_VALUE; + } + callback = data.readStrongBinder(); + if (callback == NULL) { + return BAD_VALUE; + } + ret = target->linkToDeath(testDeathRecipient); + if (ret == NO_ERROR) + ret = testDeathRecipient->waitEvent(5); + data2.writeInt32(ret); + callback->transact(BINDER_LIB_TEST_CALL_BACK, data2, &reply2); + return NO_ERROR; + } + case BINDER_LIB_TEST_WRITE_FILE_TRANSACTION: { + int ret; + int32_t size; + const void *buf; + int fd; + + fd = data.readFileDescriptor(); + if (fd < 0) { + return BAD_VALUE; + } + ret = data.readInt32(&size); + if (ret != NO_ERROR) { + return ret; + } + buf = data.readInplace(size); + if (buf == NULL) { + return BAD_VALUE; + } + ret = write(fd, buf, size); + if (ret != size) + return UNKNOWN_ERROR; + return NO_ERROR; + } + case BINDER_LIB_TEST_PROMOTE_WEAK_REF_TRANSACTION: { + int ret; + wp<IBinder> weak; + sp<IBinder> strong; + Parcel data2, reply2; + sp<IServiceManager> sm = defaultServiceManager(); + sp<IBinder> server = sm->getService(binderLibTestServiceName); + + weak = data.readWeakBinder(); + if (weak == NULL) { + return BAD_VALUE; + } + strong = weak.promote(); + + ret = server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data2, &reply2); + if (ret != NO_ERROR) + exit(EXIT_FAILURE); + + if (strong == NULL) { + reply->setError(1); + } + return NO_ERROR; + } + case BINDER_LIB_TEST_DELAYED_EXIT_TRANSACTION: + alarm(10); + return NO_ERROR; + case BINDER_LIB_TEST_EXIT_TRANSACTION: + while (wait(NULL) != -1 || errno != ECHILD) + ; + exit(EXIT_SUCCESS); + default: + return UNKNOWN_TRANSACTION; + }; + } + private: + int32_t m_id; + int32_t m_nextServerId; + pthread_mutex_t m_serverWaitMutex; + pthread_cond_t m_serverWaitCond; + bool m_serverStartRequested; + sp<IBinder> m_serverStarted; + sp<IBinder> m_strongRef; +}; + +int run_server(int index, int readypipefd) +{ + status_t ret; + sp<IServiceManager> sm = defaultServiceManager(); + { + sp<BinderLibTestService> testService = new BinderLibTestService(index); + if (index == 0) { + ret = sm->addService(binderLibTestServiceName, testService); + } else { + sp<IBinder> server = sm->getService(binderLibTestServiceName); + Parcel data, reply; + data.writeInt32(index); + data.writeStrongBinder(testService); + + ret = server->transact(BINDER_LIB_TEST_REGISTER_SERVER, data, &reply); + } + } + write(readypipefd, &ret, sizeof(ret)); + close(readypipefd); + //printf("%s: ret %d\n", __func__, ret); + if (ret) + return 1; + //printf("%s: joinThreadPool\n", __func__); + ProcessState::self()->startThreadPool(); + IPCThreadState::self()->joinThreadPool(); + //printf("%s: joinThreadPool returned\n", __func__); + return 1; /* joinThreadPool should not return */ +} + +int main(int argc, char **argv) { + int ret; + + if (argc == 3 && !strcmp(argv[1], "--servername")) { + binderservername = argv[2]; + } else { + binderservername = argv[0]; + } + + if (argc == 4 && !strcmp(argv[1], binderserverarg)) { + return run_server(atoi(argv[2]), atoi(argv[3])); + } + + ::testing::InitGoogleTest(&argc, argv); + binder_env = AddGlobalTestEnvironment(new BinderLibTestEnv()); + ProcessState::self()->startThreadPool(); + return RUN_ALL_TESTS(); +} + diff --git a/libs/diskusage/dirsize.c b/libs/diskusage/dirsize.c index 24e5af02ab..7576994c0f 100644 --- a/libs/diskusage/dirsize.c +++ b/libs/diskusage/dirsize.c @@ -18,6 +18,7 @@ #include <dirent.h> #include <fcntl.h> #include <sys/stat.h> +#include <unistd.h> #include <diskusage/dirsize.h> diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk index ca94aa3990..8a965dddfc 100644 --- a/libs/gui/Android.mk +++ b/libs/gui/Android.mk @@ -1,7 +1,42 @@ -LOCAL_PATH:= $(call my-dir) +# Copyright 2010 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. + +LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES:= \ +LOCAL_CLANG := true +LOCAL_CPPFLAGS := -std=c++1y -Weverything -Werror + +# The static constructors and destructors in this library have not been noted to +# introduce significant overheads +LOCAL_CPPFLAGS += -Wno-exit-time-destructors +LOCAL_CPPFLAGS += -Wno-global-constructors + +# We only care about compiling as C++14 +LOCAL_CPPFLAGS += -Wno-c++98-compat-pedantic + +# We don't need to enumerate every case in a switch as long as a default case +# is present +LOCAL_CPPFLAGS += -Wno-switch-enum + +# Allow calling variadic macros without a __VA_ARGS__ list +LOCAL_CPPFLAGS += -Wno-gnu-zero-variadic-macro-arguments + +# Don't warn about struct padding +LOCAL_CPPFLAGS += -Wno-padded + +LOCAL_SRC_FILES := \ IGraphicBufferConsumer.cpp \ IConsumerListener.cpp \ BitTube.cpp \ @@ -47,7 +82,7 @@ LOCAL_SHARED_LIBRARIES := \ liblog -LOCAL_MODULE:= libgui +LOCAL_MODULE := libgui ifeq ($(TARGET_BOARD_PLATFORM), tegra) LOCAL_CFLAGS += -DDONT_USE_FENCE_SYNC diff --git a/libs/gui/BitTube.cpp b/libs/gui/BitTube.cpp index 3ed1f370a5..b653c5b69c 100644 --- a/libs/gui/BitTube.cpp +++ b/libs/gui/BitTube.cpp @@ -149,12 +149,12 @@ ssize_t BitTube::sendObjects(const sp<BitTube>& tube, ssize_t size = tube->write(vaddr, count*objSize); // should never happen because of SOCK_SEQPACKET - LOG_ALWAYS_FATAL_IF((size >= 0) && (size % objSize), + LOG_ALWAYS_FATAL_IF((size >= 0) && (size % static_cast<ssize_t>(objSize)), "BitTube::sendObjects(count=%zu, size=%zu), res=%zd (partial events were sent!)", count, objSize, size); //ALOGE_IF(size<0, "error %d sending %d events", size, count); - return size < 0 ? size : size / objSize; + return size < 0 ? size : size / static_cast<ssize_t>(objSize); } ssize_t BitTube::recvObjects(const sp<BitTube>& tube, @@ -164,12 +164,12 @@ ssize_t BitTube::recvObjects(const sp<BitTube>& tube, ssize_t size = tube->read(vaddr, count*objSize); // should never happen because of SOCK_SEQPACKET - LOG_ALWAYS_FATAL_IF((size >= 0) && (size % objSize), + LOG_ALWAYS_FATAL_IF((size >= 0) && (size % static_cast<ssize_t>(objSize)), "BitTube::recvObjects(count=%zu, size=%zu), res=%zd (partial events were received!)", count, objSize, size); //ALOGE_IF(size<0, "error %d receiving %d events", size, count); - return size < 0 ? size : size / objSize; + return size < 0 ? size : size / static_cast<ssize_t>(objSize); } // ---------------------------------------------------------------------------- diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp index e6fc791198..8f64ae0e04 100644 --- a/libs/gui/BufferItem.cpp +++ b/libs/gui/BufferItem.cpp @@ -28,6 +28,7 @@ BufferItem::BufferItem() : mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mTimestamp(0), mIsAutoTimestamp(false), + mDataSpace(HAL_DATASPACE_UNKNOWN), mFrameNumber(0), mSlot(INVALID_BUFFER_SLOT), mIsDroppable(false), @@ -38,66 +39,67 @@ BufferItem::BufferItem() : BufferItem::~BufferItem() {} -BufferItem::operator IGraphicBufferConsumer::BufferItem() const { - IGraphicBufferConsumer::BufferItem bufferItem; - bufferItem.mGraphicBuffer = mGraphicBuffer; - bufferItem.mFence = mFence; - bufferItem.mCrop = mCrop; - bufferItem.mTransform = mTransform; - bufferItem.mScalingMode = mScalingMode; - bufferItem.mTimestamp = mTimestamp; - bufferItem.mIsAutoTimestamp = mIsAutoTimestamp; - bufferItem.mFrameNumber = mFrameNumber; - bufferItem.mBuf = mSlot; - bufferItem.mIsDroppable = mIsDroppable; - bufferItem.mAcquireCalled = mAcquireCalled; - bufferItem.mTransformToDisplayInverse = mTransformToDisplayInverse; - return bufferItem; +template <typename T> +static void addAligned(size_t& size, T /* value */) { + size = FlattenableUtils::align<sizeof(T)>(size); + size += sizeof(T); } size_t BufferItem::getPodSize() const { - size_t c = sizeof(mCrop) + - sizeof(mTransform) + - sizeof(mScalingMode) + - sizeof(mTimestamp) + - sizeof(mIsAutoTimestamp) + - sizeof(mFrameNumber) + - sizeof(mSlot) + - sizeof(mIsDroppable) + - sizeof(mAcquireCalled) + - sizeof(mTransformToDisplayInverse); - return c; + size_t size = 0; + addAligned(size, mCrop); + addAligned(size, mTransform); + addAligned(size, mScalingMode); + addAligned(size, mTimestampLo); + addAligned(size, mTimestampHi); + addAligned(size, mIsAutoTimestamp); + addAligned(size, mDataSpace); + addAligned(size, mFrameNumberLo); + addAligned(size, mFrameNumberHi); + addAligned(size, mSlot); + addAligned(size, mIsDroppable); + addAligned(size, mAcquireCalled); + addAligned(size, mTransformToDisplayInverse); + return size; } size_t BufferItem::getFlattenedSize() const { - size_t c = 0; + size_t size = sizeof(uint32_t); // Flags if (mGraphicBuffer != 0) { - c += mGraphicBuffer->getFlattenedSize(); - FlattenableUtils::align<4>(c); + size += mGraphicBuffer->getFlattenedSize(); + FlattenableUtils::align<4>(size); } if (mFence != 0) { - c += mFence->getFlattenedSize(); - FlattenableUtils::align<4>(c); + size += mFence->getFlattenedSize(); + FlattenableUtils::align<4>(size); } - return sizeof(int32_t) + c + getPodSize(); + size += mSurfaceDamage.getFlattenedSize(); + size = FlattenableUtils::align<8>(size); + return size + getPodSize(); } size_t BufferItem::getFdCount() const { - size_t c = 0; + size_t count = 0; if (mGraphicBuffer != 0) { - c += mGraphicBuffer->getFdCount(); + count += mGraphicBuffer->getFdCount(); } if (mFence != 0) { - c += mFence->getFdCount(); + count += mFence->getFdCount(); } - return c; + return count; +} + +template <typename T> +static void writeAligned(void*& buffer, size_t& size, T value) { + size -= FlattenableUtils::align<alignof(T)>(buffer); + FlattenableUtils::write(buffer, size, value); } status_t BufferItem::flatten( void*& buffer, size_t& size, int*& fds, size_t& count) const { // make sure we have enough space - if (count < BufferItem::getFlattenedSize()) { + if (size < BufferItem::getFlattenedSize()) { return NO_MEMORY; } @@ -121,30 +123,44 @@ status_t BufferItem::flatten( flags |= 2; } - // check we have enough space (in case flattening the fence/graphicbuffer lied to us) + status_t err = mSurfaceDamage.flatten(buffer, size); + if (err) return err; + FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize()); + + // Check we still have enough space if (size < getPodSize()) { return NO_MEMORY; } - FlattenableUtils::write(buffer, size, mCrop); - FlattenableUtils::write(buffer, size, mTransform); - FlattenableUtils::write(buffer, size, mScalingMode); - FlattenableUtils::write(buffer, size, mTimestamp); - FlattenableUtils::write(buffer, size, mIsAutoTimestamp); - FlattenableUtils::write(buffer, size, mFrameNumber); - FlattenableUtils::write(buffer, size, mSlot); - FlattenableUtils::write(buffer, size, mIsDroppable); - FlattenableUtils::write(buffer, size, mAcquireCalled); - FlattenableUtils::write(buffer, size, mTransformToDisplayInverse); + writeAligned(buffer, size, mCrop); + writeAligned(buffer, size, mTransform); + writeAligned(buffer, size, mScalingMode); + writeAligned(buffer, size, mTimestampLo); + writeAligned(buffer, size, mTimestampHi); + writeAligned(buffer, size, mIsAutoTimestamp); + writeAligned(buffer, size, mDataSpace); + writeAligned(buffer, size, mFrameNumberLo); + writeAligned(buffer, size, mFrameNumberHi); + writeAligned(buffer, size, mSlot); + writeAligned(buffer, size, mIsDroppable); + writeAligned(buffer, size, mAcquireCalled); + writeAligned(buffer, size, mTransformToDisplayInverse); return NO_ERROR; } +template <typename T> +static void readAligned(const void*& buffer, size_t& size, T& value) { + size -= FlattenableUtils::align<alignof(T)>(buffer); + FlattenableUtils::read(buffer, size, value); +} + status_t BufferItem::unflatten( void const*& buffer, size_t& size, int const*& fds, size_t& count) { - if (size < sizeof(uint32_t)) + if (size < sizeof(uint32_t)) { return NO_MEMORY; + } uint32_t flags = 0; FlattenableUtils::read(buffer, size, flags); @@ -163,21 +179,28 @@ status_t BufferItem::unflatten( size -= FlattenableUtils::align<4>(buffer); } - // check we have enough space + status_t err = mSurfaceDamage.unflatten(buffer, size); + if (err) return err; + FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize()); + + // Check we still have enough space if (size < getPodSize()) { return NO_MEMORY; } - FlattenableUtils::read(buffer, size, mCrop); - FlattenableUtils::read(buffer, size, mTransform); - FlattenableUtils::read(buffer, size, mScalingMode); - FlattenableUtils::read(buffer, size, mTimestamp); - FlattenableUtils::read(buffer, size, mIsAutoTimestamp); - FlattenableUtils::read(buffer, size, mFrameNumber); - FlattenableUtils::read(buffer, size, mSlot); - FlattenableUtils::read(buffer, size, mIsDroppable); - FlattenableUtils::read(buffer, size, mAcquireCalled); - FlattenableUtils::read(buffer, size, mTransformToDisplayInverse); + readAligned(buffer, size, mCrop); + readAligned(buffer, size, mTransform); + readAligned(buffer, size, mScalingMode); + readAligned(buffer, size, mTimestampLo); + readAligned(buffer, size, mTimestampHi); + readAligned(buffer, size, mIsAutoTimestamp); + readAligned(buffer, size, mDataSpace); + readAligned(buffer, size, mFrameNumberLo); + readAligned(buffer, size, mFrameNumberHi); + readAligned(buffer, size, mSlot); + readAligned(buffer, size, mIsDroppable); + readAligned(buffer, size, mAcquireCalled); + readAligned(buffer, size, mTransformToDisplayInverse); return NO_ERROR; } diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp index fe50c55f51..578b8d96b1 100644 --- a/libs/gui/BufferItemConsumer.cpp +++ b/libs/gui/BufferItemConsumer.cpp @@ -16,16 +16,17 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "BufferItemConsumer" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS +//#define ATRACE_TAG ATRACE_TAG_GRAPHICS #include <utils/Log.h> +#include <gui/BufferItem.h> #include <gui/BufferItemConsumer.h> -#define BI_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__) -#define BI_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__) -#define BI_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__) -#define BI_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__) -#define BI_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__) +//#define BI_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) +//#define BI_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) +//#define BI_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__) +//#define BI_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__) +#define BI_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__) namespace android { @@ -44,8 +45,7 @@ BufferItemConsumer::BufferItemConsumer( } } -BufferItemConsumer::~BufferItemConsumer() { -} +BufferItemConsumer::~BufferItemConsumer() {} void BufferItemConsumer::setName(const String8& name) { Mutex::Autolock _l(mMutex); @@ -100,14 +100,4 @@ status_t BufferItemConsumer::releaseBuffer(const BufferItem &item, return err; } -status_t BufferItemConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) { - Mutex::Autolock _l(mMutex); - return mConsumer->setDefaultBufferSize(w, h); -} - -status_t BufferItemConsumer::setDefaultBufferFormat(uint32_t defaultFormat) { - Mutex::Autolock _l(mMutex); - return mConsumer->setDefaultBufferFormat(defaultFormat); -} - } // namespace android diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 61fd8c42de..ccbb5a25f3 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -32,13 +32,21 @@ BufferQueue::ProxyConsumerListener::ProxyConsumerListener( BufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {} void BufferQueue::ProxyConsumerListener::onFrameAvailable( - const android::BufferItem& item) { + const BufferItem& item) { sp<ConsumerListener> listener(mConsumerListener.promote()); if (listener != NULL) { listener->onFrameAvailable(item); } } +void BufferQueue::ProxyConsumerListener::onFrameReplaced( + const BufferItem& item) { + sp<ConsumerListener> listener(mConsumerListener.promote()); + if (listener != NULL) { + listener->onFrameReplaced(item); + } +} + void BufferQueue::ProxyConsumerListener::onBuffersReleased() { sp<ConsumerListener> listener(mConsumerListener.promote()); if (listener != NULL) { diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index bc6f3f012a..7aea4bb742 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -40,142 +40,170 @@ BufferQueueConsumer::BufferQueueConsumer(const sp<BufferQueueCore>& core) : BufferQueueConsumer::~BufferQueueConsumer() {} status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, - nsecs_t expectedPresent) { + nsecs_t expectedPresent, uint64_t maxFrameNumber) { ATRACE_CALL(); - Mutex::Autolock lock(mCore->mMutex); - // Check that the consumer doesn't currently have the maximum number of - // buffers acquired. We allow the max buffer count to be exceeded by one - // buffer so that the consumer can successfully set up the newly acquired - // buffer before releasing the old one. - int numAcquiredBuffers = 0; - for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - if (mSlots[s].mBufferState == BufferSlot::ACQUIRED) { - ++numAcquiredBuffers; + int numDroppedBuffers = 0; + sp<IProducerListener> listener; + { + Mutex::Autolock lock(mCore->mMutex); + + // Check that the consumer doesn't currently have the maximum number of + // buffers acquired. We allow the max buffer count to be exceeded by one + // buffer so that the consumer can successfully set up the newly acquired + // buffer before releasing the old one. + int numAcquiredBuffers = 0; + for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { + if (mSlots[s].mBufferState == BufferSlot::ACQUIRED) { + ++numAcquiredBuffers; + } + } + if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) { + BQ_LOGE("acquireBuffer: max acquired buffer count reached: %d (max %d)", + numAcquiredBuffers, mCore->mMaxAcquiredBufferCount); + return INVALID_OPERATION; } - } - if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) { - BQ_LOGE("acquireBuffer: max acquired buffer count reached: %d (max %d)", - numAcquiredBuffers, mCore->mMaxAcquiredBufferCount); - return INVALID_OPERATION; - } - // Check if the queue is empty. - // In asynchronous mode the list is guaranteed to be one buffer deep, - // while in synchronous mode we use the oldest buffer. - if (mCore->mQueue.empty()) { - return NO_BUFFER_AVAILABLE; - } + // Check if the queue is empty. + // In asynchronous mode the list is guaranteed to be one buffer deep, + // while in synchronous mode we use the oldest buffer. + if (mCore->mQueue.empty()) { + return NO_BUFFER_AVAILABLE; + } + + BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin()); - BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin()); - - // If expectedPresent is specified, we may not want to return a buffer yet. - // If it's specified and there's more than one buffer queued, we may want - // to drop a buffer. - if (expectedPresent != 0) { - const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second - - // The 'expectedPresent' argument indicates when the buffer is expected - // to be presented on-screen. If the buffer's desired present time is - // earlier (less) than expectedPresent -- meaning it will be displayed - // on time or possibly late if we show it as soon as possible -- we - // acquire and return it. If we don't want to display it until after the - // expectedPresent time, we return PRESENT_LATER without acquiring it. - // - // To be safe, we don't defer acquisition if expectedPresent is more - // than one second in the future beyond the desired present time - // (i.e., we'd be holding the buffer for a long time). - // - // NOTE: Code assumes monotonic time values from the system clock - // are positive. - - // Start by checking to see if we can drop frames. We skip this check if - // the timestamps are being auto-generated by Surface. If the app isn't - // generating timestamps explicitly, it probably doesn't want frames to - // be discarded based on them. - while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) { - // If entry[1] is timely, drop entry[0] (and repeat). We apply an - // additional criterion here: we only drop the earlier buffer if our - // desiredPresent falls within +/- 1 second of the expected present. - // Otherwise, bogus desiredPresent times (e.g., 0 or a small - // relative timestamp), which normally mean "ignore the timestamp - // and acquire immediately", would cause us to drop frames. + // If expectedPresent is specified, we may not want to return a buffer yet. + // If it's specified and there's more than one buffer queued, we may want + // to drop a buffer. + if (expectedPresent != 0) { + const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second + + // The 'expectedPresent' argument indicates when the buffer is expected + // to be presented on-screen. If the buffer's desired present time is + // earlier (less) than expectedPresent -- meaning it will be displayed + // on time or possibly late if we show it as soon as possible -- we + // acquire and return it. If we don't want to display it until after the + // expectedPresent time, we return PRESENT_LATER without acquiring it. // - // We may want to add an additional criterion: don't drop the - // earlier buffer if entry[1]'s fence hasn't signaled yet. - const BufferItem& bufferItem(mCore->mQueue[1]); - nsecs_t desiredPresent = bufferItem.mTimestamp; - if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC || - desiredPresent > expectedPresent) { - // This buffer is set to display in the near future, or - // desiredPresent is garbage. Either way we don't want to drop - // the previous buffer just to get this on the screen sooner. - BQ_LOGV("acquireBuffer: nodrop desire=%" PRId64 " expect=%" - PRId64 " (%" PRId64 ") now=%" PRId64, - desiredPresent, expectedPresent, - desiredPresent - expectedPresent, - systemTime(CLOCK_MONOTONIC)); - break; + // To be safe, we don't defer acquisition if expectedPresent is more + // than one second in the future beyond the desired present time + // (i.e., we'd be holding the buffer for a long time). + // + // NOTE: Code assumes monotonic time values from the system clock + // are positive. + + // Start by checking to see if we can drop frames. We skip this check if + // the timestamps are being auto-generated by Surface. If the app isn't + // generating timestamps explicitly, it probably doesn't want frames to + // be discarded based on them. + while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) { + const BufferItem& bufferItem(mCore->mQueue[1]); + + // If dropping entry[0] would leave us with a buffer that the + // consumer is not yet ready for, don't drop it. + if (maxFrameNumber && bufferItem.mFrameNumber > maxFrameNumber) { + break; + } + + // If entry[1] is timely, drop entry[0] (and repeat). We apply an + // additional criterion here: we only drop the earlier buffer if our + // desiredPresent falls within +/- 1 second of the expected present. + // Otherwise, bogus desiredPresent times (e.g., 0 or a small + // relative timestamp), which normally mean "ignore the timestamp + // and acquire immediately", would cause us to drop frames. + // + // We may want to add an additional criterion: don't drop the + // earlier buffer if entry[1]'s fence hasn't signaled yet. + nsecs_t desiredPresent = bufferItem.mTimestamp; + if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC || + desiredPresent > expectedPresent) { + // This buffer is set to display in the near future, or + // desiredPresent is garbage. Either way we don't want to drop + // the previous buffer just to get this on the screen sooner. + BQ_LOGV("acquireBuffer: nodrop desire=%" PRId64 " expect=%" + PRId64 " (%" PRId64 ") now=%" PRId64, + desiredPresent, expectedPresent, + desiredPresent - expectedPresent, + systemTime(CLOCK_MONOTONIC)); + break; + } + + BQ_LOGV("acquireBuffer: drop desire=%" PRId64 " expect=%" PRId64 + " size=%zu", + desiredPresent, expectedPresent, mCore->mQueue.size()); + if (mCore->stillTracking(front)) { + // Front buffer is still in mSlots, so mark the slot as free + mSlots[front->mSlot].mBufferState = BufferSlot::FREE; + mCore->mFreeBuffers.push_back(front->mSlot); + listener = mCore->mConnectedProducerListener; + ++numDroppedBuffers; + } + mCore->mQueue.erase(front); + front = mCore->mQueue.begin(); } - BQ_LOGV("acquireBuffer: drop desire=%" PRId64 " expect=%" PRId64 - " size=%zu", - desiredPresent, expectedPresent, mCore->mQueue.size()); - if (mCore->stillTracking(front)) { - // Front buffer is still in mSlots, so mark the slot as free - mSlots[front->mSlot].mBufferState = BufferSlot::FREE; + // See if the front buffer is ready to be acquired + nsecs_t desiredPresent = front->mTimestamp; + bool bufferIsDue = desiredPresent <= expectedPresent || + desiredPresent > expectedPresent + MAX_REASONABLE_NSEC; + bool consumerIsReady = maxFrameNumber > 0 ? + front->mFrameNumber <= maxFrameNumber : true; + if (!bufferIsDue || !consumerIsReady) { + BQ_LOGV("acquireBuffer: defer desire=%" PRId64 " expect=%" PRId64 + " (%" PRId64 ") now=%" PRId64 " frame=%" PRIu64 + " consumer=%" PRIu64, + desiredPresent, expectedPresent, + desiredPresent - expectedPresent, + systemTime(CLOCK_MONOTONIC), + front->mFrameNumber, maxFrameNumber); + return PRESENT_LATER; } - mCore->mQueue.erase(front); - front = mCore->mQueue.begin(); - } - // See if the front buffer is due - nsecs_t desiredPresent = front->mTimestamp; - if (desiredPresent > expectedPresent && - desiredPresent < expectedPresent + MAX_REASONABLE_NSEC) { - BQ_LOGV("acquireBuffer: defer desire=%" PRId64 " expect=%" PRId64 - " (%" PRId64 ") now=%" PRId64, - desiredPresent, expectedPresent, + BQ_LOGV("acquireBuffer: accept desire=%" PRId64 " expect=%" PRId64 " " + "(%" PRId64 ") now=%" PRId64, desiredPresent, expectedPresent, desiredPresent - expectedPresent, systemTime(CLOCK_MONOTONIC)); - return PRESENT_LATER; } - BQ_LOGV("acquireBuffer: accept desire=%" PRId64 " expect=%" PRId64 " " - "(%" PRId64 ") now=%" PRId64, desiredPresent, expectedPresent, - desiredPresent - expectedPresent, - systemTime(CLOCK_MONOTONIC)); - } + int slot = front->mSlot; + *outBuffer = *front; + ATRACE_BUFFER_INDEX(slot); - int slot = front->mSlot; - *outBuffer = *front; - ATRACE_BUFFER_INDEX(slot); + BQ_LOGV("acquireBuffer: acquiring { slot=%d/%" PRIu64 " buffer=%p }", + slot, front->mFrameNumber, front->mGraphicBuffer->handle); + // If the front buffer is still being tracked, update its slot state + if (mCore->stillTracking(front)) { + mSlots[slot].mAcquireCalled = true; + mSlots[slot].mNeedsCleanupOnRelease = false; + mSlots[slot].mBufferState = BufferSlot::ACQUIRED; + mSlots[slot].mFence = Fence::NO_FENCE; + } - BQ_LOGV("acquireBuffer: acquiring { slot=%d/%" PRIu64 " buffer=%p }", - slot, front->mFrameNumber, front->mGraphicBuffer->handle); - // If the front buffer is still being tracked, update its slot state - if (mCore->stillTracking(front)) { - mSlots[slot].mAcquireCalled = true; - mSlots[slot].mNeedsCleanupOnRelease = false; - mSlots[slot].mBufferState = BufferSlot::ACQUIRED; - mSlots[slot].mFence = Fence::NO_FENCE; - } + // If the buffer has previously been acquired by the consumer, set + // mGraphicBuffer to NULL to avoid unnecessarily remapping this buffer + // on the consumer side + if (outBuffer->mAcquireCalled) { + outBuffer->mGraphicBuffer = NULL; + } - // If the buffer has previously been acquired by the consumer, set - // mGraphicBuffer to NULL to avoid unnecessarily remapping this buffer - // on the consumer side - if (outBuffer->mAcquireCalled) { - outBuffer->mGraphicBuffer = NULL; - } + mCore->mQueue.erase(front); - mCore->mQueue.erase(front); + // We might have freed a slot while dropping old buffers, or the producer + // may be blocked waiting for the number of buffers in the queue to + // decrease. + mCore->mDequeueCondition.broadcast(); - // We might have freed a slot while dropping old buffers, or the producer - // may be blocked waiting for the number of buffers in the queue to - // decrease. - mCore->mDequeueCondition.broadcast(); + ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size()); - ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size()); + mCore->validateConsistencyLocked(); + } + + if (listener != NULL) { + for (int i = 0; i < numDroppedBuffers; ++i) { + listener->onBufferReleased(); + } + } return NO_ERROR; } @@ -203,6 +231,7 @@ status_t BufferQueueConsumer::detachBuffer(int slot) { mCore->freeBufferLocked(slot); mCore->mDequeueCondition.broadcast(); + mCore->validateConsistencyLocked(); return NO_ERROR; } @@ -221,18 +250,11 @@ status_t BufferQueueConsumer::attachBuffer(int* outSlot, Mutex::Autolock lock(mCore->mMutex); - // Make sure we don't have too many acquired buffers and find a free slot - // to put the buffer into (the oldest if there are multiple). + // Make sure we don't have too many acquired buffers int numAcquiredBuffers = 0; - int found = BufferQueueCore::INVALID_BUFFER_SLOT; for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { if (mSlots[s].mBufferState == BufferSlot::ACQUIRED) { ++numAcquiredBuffers; - } else if (mSlots[s].mBufferState == BufferSlot::FREE) { - if (found == BufferQueueCore::INVALID_BUFFER_SLOT || - mSlots[s].mFrameNumber < mSlots[found].mFrameNumber) { - found = s; - } } } @@ -242,6 +264,24 @@ status_t BufferQueueConsumer::attachBuffer(int* outSlot, mCore->mMaxAcquiredBufferCount); return INVALID_OPERATION; } + + if (buffer->getGenerationNumber() != mCore->mGenerationNumber) { + BQ_LOGE("attachBuffer: generation number mismatch [buffer %u] " + "[queue %u]", buffer->getGenerationNumber(), + mCore->mGenerationNumber); + return BAD_VALUE; + } + + // Find a free slot to put the buffer into + int found = BufferQueueCore::INVALID_BUFFER_SLOT; + if (!mCore->mFreeSlots.empty()) { + auto slot = mCore->mFreeSlots.begin(); + found = *slot; + mCore->mFreeSlots.erase(slot); + } else if (!mCore->mFreeBuffers.empty()) { + found = mCore->mFreeBuffers.front(); + mCore->mFreeBuffers.remove(found); + } if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { BQ_LOGE("attachBuffer(P): could not find free buffer slot"); return NO_MEMORY; @@ -275,6 +315,8 @@ status_t BufferQueueConsumer::attachBuffer(int* outSlot, // for attached buffers. mSlots[*outSlot].mAcquireCalled = false; + mCore->validateConsistencyLocked(); + return NO_ERROR; } @@ -286,6 +328,8 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS || releaseFence == NULL) { + BQ_LOGE("releaseBuffer: slot %d out of range or fence %p NULL", slot, + releaseFence.get()); return BAD_VALUE; } @@ -315,6 +359,7 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, mSlots[slot].mEglFence = eglFence; mSlots[slot].mFence = releaseFence; mSlots[slot].mBufferState = BufferSlot::FREE; + mCore->mFreeBuffers.push_back(slot); listener = mCore->mConnectedProducerListener; BQ_LOGV("releaseBuffer: releasing slot %d", slot); } else if (mSlots[slot].mNeedsCleanupOnRelease) { @@ -323,12 +368,13 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, mSlots[slot].mNeedsCleanupOnRelease = false; return STALE_BUFFER_SLOT; } else { - BQ_LOGV("releaseBuffer: attempted to release buffer slot %d " + BQ_LOGE("releaseBuffer: attempted to release buffer slot %d " "but its state was %d", slot, mSlots[slot].mBufferState); return BAD_VALUE; } mCore->mDequeueCondition.broadcast(); + mCore->validateConsistencyLocked(); } // Autolock scope // Call back without lock held @@ -492,7 +538,7 @@ void BufferQueueConsumer::setConsumerName(const String8& name) { mConsumerName = name; } -status_t BufferQueueConsumer::setDefaultBufferFormat(uint32_t defaultFormat) { +status_t BufferQueueConsumer::setDefaultBufferFormat(PixelFormat defaultFormat) { ATRACE_CALL(); BQ_LOGV("setDefaultBufferFormat: %u", defaultFormat); Mutex::Autolock lock(mCore->mMutex); @@ -500,6 +546,15 @@ status_t BufferQueueConsumer::setDefaultBufferFormat(uint32_t defaultFormat) { return NO_ERROR; } +status_t BufferQueueConsumer::setDefaultBufferDataSpace( + android_dataspace defaultDataSpace) { + ATRACE_CALL(); + BQ_LOGV("setDefaultBufferDataSpace: %u", defaultDataSpace); + Mutex::Autolock lock(mCore->mMutex); + mCore->mDefaultBufferDataSpace = defaultDataSpace; + return NO_ERROR; +} + status_t BufferQueueConsumer::setConsumerUsageBits(uint32_t usage) { ATRACE_CALL(); BQ_LOGV("setConsumerUsageBits: %#x", usage); diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index ec1e63112d..851a396155 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -53,6 +53,8 @@ BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) : mConnectedProducerListener(), mSlots(), mQueue(), + mFreeSlots(), + mFreeBuffers(), mOverrideMaxBufferCount(0), mDequeueCondition(), mUseAsyncBuffer(true), @@ -60,13 +62,17 @@ BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) : mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888), mDefaultWidth(1), mDefaultHeight(1), + mDefaultBufferDataSpace(HAL_DATASPACE_UNKNOWN), mDefaultMaxBufferCount(2), mMaxAcquiredBufferCount(1), mBufferHasBeenQueued(false), mFrameCounter(0), mTransformHint(0), mIsAllocating(false), - mIsAllocatingCondition() + mIsAllocatingCondition(), + mAllowAllocation(true), + mBufferAge(0), + mGenerationNumber(0) { if (allocator == NULL) { sp<ISurfaceComposer> composer(ComposerService::getComposerService()); @@ -75,6 +81,9 @@ BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) : BQ_LOGE("createGraphicBufferAlloc failed"); } } + for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) { + mFreeSlots.insert(slot); + } } BufferQueueCore::~BufferQueueCore() {} @@ -189,13 +198,22 @@ status_t BufferQueueCore::setDefaultMaxBufferCountLocked(int count) { void BufferQueueCore::freeBufferLocked(int slot) { BQ_LOGV("freeBufferLocked: slot %d", slot); + bool hadBuffer = mSlots[slot].mGraphicBuffer != NULL; mSlots[slot].mGraphicBuffer.clear(); if (mSlots[slot].mBufferState == BufferSlot::ACQUIRED) { mSlots[slot].mNeedsCleanupOnRelease = true; } + if (mSlots[slot].mBufferState != BufferSlot::FREE) { + mFreeSlots.insert(slot); + } else if (hadBuffer) { + // If the slot was FREE, but we had a buffer, we need to move this slot + // from the free buffers list to the the free slots list + mFreeBuffers.remove(slot); + mFreeSlots.insert(slot); + } mSlots[slot].mBufferState = BufferSlot::FREE; - mSlots[slot].mFrameNumber = UINT32_MAX; mSlots[slot].mAcquireCalled = false; + mSlots[slot].mFrameNumber = 0; // Destroy fence as BufferQueue now takes ownership if (mSlots[slot].mEglFence != EGL_NO_SYNC_KHR) { @@ -203,6 +221,7 @@ void BufferQueueCore::freeBufferLocked(int slot) { mSlots[slot].mEglFence = EGL_NO_SYNC_KHR; } mSlots[slot].mFence = Fence::NO_FENCE; + validateConsistencyLocked(); } void BufferQueueCore::freeAllBuffersLocked() { @@ -235,4 +254,48 @@ void BufferQueueCore::waitWhileAllocatingLocked() const { } } +void BufferQueueCore::validateConsistencyLocked() const { + static const useconds_t PAUSE_TIME = 0; + for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) { + bool isInFreeSlots = mFreeSlots.count(slot) != 0; + bool isInFreeBuffers = + std::find(mFreeBuffers.cbegin(), mFreeBuffers.cend(), slot) != + mFreeBuffers.cend(); + if (mSlots[slot].mBufferState == BufferSlot::FREE) { + if (mSlots[slot].mGraphicBuffer == NULL) { + if (!isInFreeSlots) { + BQ_LOGE("Slot %d is FREE but is not in mFreeSlots", slot); + usleep(PAUSE_TIME); + } + if (isInFreeBuffers) { + BQ_LOGE("Slot %d is in mFreeSlots " + "but is also in mFreeBuffers", slot); + usleep(PAUSE_TIME); + } + } else { + if (!isInFreeBuffers) { + BQ_LOGE("Slot %d is FREE but is not in mFreeBuffers", slot); + usleep(PAUSE_TIME); + } + if (isInFreeSlots) { + BQ_LOGE("Slot %d is in mFreeBuffers " + "but is also in mFreeSlots", slot); + usleep(PAUSE_TIME); + } + } + } else { + if (isInFreeSlots) { + BQ_LOGE("Slot %d is in mFreeSlots but is not FREE (%d)", + slot, mSlots[slot].mBufferState); + usleep(PAUSE_TIME); + } + if (isInFreeBuffers) { + BQ_LOGE("Slot %d is in mFreeBuffers but is not FREE (%d)", + slot, mSlots[slot].mBufferState); + usleep(PAUSE_TIME); + } + } + } +} + } // namespace android diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 16b9747416..c6851c872d 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -161,8 +161,6 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller, } } - // Look for a free buffer to give to the client - *found = BufferQueueCore::INVALID_BUFFER_SLOT; int dequeuedCount = 0; int acquiredCount = 0; for (int s = 0; s < maxBufferCount; ++s) { @@ -173,15 +171,6 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller, case BufferSlot::ACQUIRED: ++acquiredCount; break; - case BufferSlot::FREE: - // We return the oldest of the free buffers to avoid - // stalling the producer if possible, since the consumer - // may still have pending reads of in-flight buffers - if (*found == BufferQueueCore::INVALID_BUFFER_SLOT || - mSlots[s].mFrameNumber < mSlots[*found].mFrameNumber) { - *found = s; - } - break; default: break; } @@ -214,6 +203,8 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller, } } + *found = BufferQueueCore::INVALID_BUFFER_SLOT; + // If we disconnect and reconnect quickly, we can be in a state where // our slots are empty but we have many buffers in the queue. This can // cause us to run out of memory if we outrun the consumer. Wait here if @@ -223,6 +214,19 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller, if (tooManyBuffers) { BQ_LOGV("%s: queue size is %zu, waiting", caller, mCore->mQueue.size()); + } else { + if (!mCore->mFreeBuffers.empty()) { + auto slot = mCore->mFreeBuffers.begin(); + *found = *slot; + mCore->mFreeBuffers.erase(slot); + } else if (mCore->mAllowAllocation && !mCore->mFreeSlots.empty()) { + auto slot = mCore->mFreeSlots.begin(); + // Only return free slots up to the max buffer count + if (*slot < maxBufferCount) { + *found = *slot; + mCore->mFreeSlots.erase(slot); + } + } } // If no buffer is found, or if the queue has too many buffers @@ -250,7 +254,7 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller, status_t BufferQueueProducer::dequeueBuffer(int *outSlot, sp<android::Fence> *outFence, bool async, - uint32_t width, uint32_t height, uint32_t format, uint32_t usage) { + uint32_t width, uint32_t height, PixelFormat format, uint32_t usage) { ATRACE_CALL(); { // Autolock scope Mutex::Autolock lock(mCore->mMutex); @@ -281,17 +285,39 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot, // Enable the usage bits the consumer requested usage |= mCore->mConsumerUsageBits; - int found; - status_t status = waitForFreeSlotThenRelock("dequeueBuffer", async, - &found, &returnFlags); - if (status != NO_ERROR) { - return status; + const bool useDefaultSize = !width && !height; + if (useDefaultSize) { + width = mCore->mDefaultWidth; + height = mCore->mDefaultHeight; } - // This should not happen - if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { - BQ_LOGE("dequeueBuffer: no available buffer slots"); - return -EBUSY; + int found = BufferItem::INVALID_BUFFER_SLOT; + while (found == BufferItem::INVALID_BUFFER_SLOT) { + status_t status = waitForFreeSlotThenRelock("dequeueBuffer", async, + &found, &returnFlags); + if (status != NO_ERROR) { + return status; + } + + // This should not happen + if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { + BQ_LOGE("dequeueBuffer: no available buffer slots"); + return -EBUSY; + } + + const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer); + + // If we are not allowed to allocate new buffers, + // waitForFreeSlotThenRelock must have returned a slot containing a + // buffer. If this buffer would require reallocation to meet the + // requested attributes, we free it and attempt to get another one. + if (!mCore->mAllowAllocation) { + if (buffer->needsReallocation(width, height, format, usage)) { + mCore->freeBufferLocked(found); + found = BufferItem::INVALID_BUFFER_SLOT; + continue; + } + } } *outSlot = found; @@ -299,20 +325,11 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot, attachedByConsumer = mSlots[found].mAttachedByConsumer; - const bool useDefaultSize = !width && !height; - if (useDefaultSize) { - width = mCore->mDefaultWidth; - height = mCore->mDefaultHeight; - } - mSlots[found].mBufferState = BufferSlot::DEQUEUED; const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer); if ((buffer == NULL) || - (static_cast<uint32_t>(buffer->width) != width) || - (static_cast<uint32_t>(buffer->height) != height) || - (static_cast<uint32_t>(buffer->format) != format) || - ((static_cast<uint32_t>(buffer->usage) & usage) != usage)) + buffer->needsReallocation(width, height, format, usage)) { mSlots[found].mAcquireCalled = false; mSlots[found].mGraphicBuffer = NULL; @@ -320,10 +337,19 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot, mSlots[found].mEglDisplay = EGL_NO_DISPLAY; mSlots[found].mEglFence = EGL_NO_SYNC_KHR; mSlots[found].mFence = Fence::NO_FENCE; + mCore->mBufferAge = 0; returnFlags |= BUFFER_NEEDS_REALLOCATION; + } else { + // We add 1 because that will be the frame number when this buffer + // is queued + mCore->mBufferAge = + mCore->mFrameCounter + 1 - mSlots[found].mFrameNumber; } + BQ_LOGV("dequeueBuffer: setting buffer age to %" PRIu64, + mCore->mBufferAge); + if (CC_UNLIKELY(mSlots[found].mFence == NULL)) { BQ_LOGE("dequeueBuffer: about to return a NULL fence - " "slot=%d w=%d h=%d format=%u", @@ -335,13 +361,15 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot, *outFence = mSlots[found].mFence; mSlots[found].mEglFence = EGL_NO_SYNC_KHR; mSlots[found].mFence = Fence::NO_FENCE; + + mCore->validateConsistencyLocked(); } // Autolock scope if (returnFlags & BUFFER_NEEDS_REALLOCATION) { status_t error; BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot); sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer( - width, height, format, usage, &error)); + width, height, format, usage, &error)); if (graphicBuffer == NULL) { BQ_LOGE("dequeueBuffer: createGraphicBuffer failed"); return error; @@ -355,7 +383,7 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot, return NO_INIT; } - mSlots[*outSlot].mFrameNumber = UINT32_MAX; + graphicBuffer->setGenerationNumber(mCore->mGenerationNumber); mSlots[*outSlot].mGraphicBuffer = graphicBuffer; } // Autolock scope } @@ -414,6 +442,7 @@ status_t BufferQueueProducer::detachBuffer(int slot) { mCore->freeBufferLocked(slot); mCore->mDequeueCondition.broadcast(); + mCore->validateConsistencyLocked(); return NO_ERROR; } @@ -438,27 +467,19 @@ status_t BufferQueueProducer::detachNextBuffer(sp<GraphicBuffer>* outBuffer, return NO_INIT; } - // Find the oldest valid slot - int found = BufferQueueCore::INVALID_BUFFER_SLOT; - for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - if (mSlots[s].mBufferState == BufferSlot::FREE && - mSlots[s].mGraphicBuffer != NULL) { - if (found == BufferQueueCore::INVALID_BUFFER_SLOT || - mSlots[s].mFrameNumber < mSlots[found].mFrameNumber) { - found = s; - } - } - } - - if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { + if (mCore->mFreeBuffers.empty()) { return NO_MEMORY; } + int found = mCore->mFreeBuffers.front(); + mCore->mFreeBuffers.remove(found); + BQ_LOGV("detachNextBuffer detached slot %d", found); *outBuffer = mSlots[found].mGraphicBuffer; *outFence = mSlots[found].mFence; mCore->freeBufferLocked(found); + mCore->validateConsistencyLocked(); return NO_ERROR; } @@ -478,6 +499,13 @@ status_t BufferQueueProducer::attachBuffer(int* outSlot, Mutex::Autolock lock(mCore->mMutex); mCore->waitWhileAllocatingLocked(); + if (buffer->getGenerationNumber() != mCore->mGenerationNumber) { + BQ_LOGE("attachBuffer: generation number mismatch [buffer %u] " + "[queue %u]", buffer->getGenerationNumber(), + mCore->mGenerationNumber); + return BAD_VALUE; + } + status_t returnFlags = NO_ERROR; int found; // TODO: Should we provide an async flag to attachBuffer? It seems @@ -506,6 +534,8 @@ status_t BufferQueueProducer::attachBuffer(int* outSlot, mSlots[*outSlot].mFence = Fence::NO_FENCE; mSlots[*outSlot].mRequestBufferCalled = true; + mCore->validateConsistencyLocked(); + return returnFlags; } @@ -516,14 +546,16 @@ status_t BufferQueueProducer::queueBuffer(int slot, int64_t timestamp; bool isAutoTimestamp; + android_dataspace dataSpace; Rect crop; int scalingMode; uint32_t transform; uint32_t stickyTransform; bool async; sp<Fence> fence; - input.deflate(×tamp, &isAutoTimestamp, &crop, &scalingMode, &transform, - &async, &fence, &stickyTransform); + input.deflate(×tamp, &isAutoTimestamp, &dataSpace, &crop, &scalingMode, + &transform, &async, &fence, &stickyTransform); + Region surfaceDamage = input.getSurfaceDamage(); if (fence == NULL) { BQ_LOGE("queueBuffer: fence is NULL"); @@ -579,11 +611,11 @@ status_t BufferQueueProducer::queueBuffer(int slot, return BAD_VALUE; } - BQ_LOGV("queueBuffer: slot=%d/%" PRIu64 " time=%" PRIu64 + BQ_LOGV("queueBuffer: slot=%d/%" PRIu64 " time=%" PRIu64 " dataSpace=%d" " crop=[%d,%d,%d,%d] transform=%#x scale=%s", - slot, mCore->mFrameCounter + 1, timestamp, - crop.left, crop.top, crop.right, crop.bottom, - transform, BufferItem::scalingModeName(scalingMode)); + slot, mCore->mFrameCounter + 1, timestamp, dataSpace, + crop.left, crop.top, crop.right, crop.bottom, transform, + BufferItem::scalingModeName(static_cast<uint32_t>(scalingMode))); const sp<GraphicBuffer>& graphicBuffer(mSlots[slot].mGraphicBuffer); Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight()); @@ -595,6 +627,11 @@ status_t BufferQueueProducer::queueBuffer(int slot, return BAD_VALUE; } + // Override UNKNOWN dataspace with consumer default + if (dataSpace == HAL_DATASPACE_UNKNOWN) { + dataSpace = mCore->mDefaultBufferDataSpace; + } + mSlots[slot].mFence = fence; mSlots[slot].mBufferState = BufferSlot::QUEUED; ++mCore->mFrameCounter; @@ -603,16 +640,19 @@ status_t BufferQueueProducer::queueBuffer(int slot, item.mAcquireCalled = mSlots[slot].mAcquireCalled; item.mGraphicBuffer = mSlots[slot].mGraphicBuffer; item.mCrop = crop; - item.mTransform = transform & ~NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; + item.mTransform = transform & + ~static_cast<uint32_t>(NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY); item.mTransformToDisplayInverse = - bool(transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY); - item.mScalingMode = scalingMode; + (transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) != 0; + item.mScalingMode = static_cast<uint32_t>(scalingMode); item.mTimestamp = timestamp; item.mIsAutoTimestamp = isAutoTimestamp; + item.mDataSpace = dataSpace; item.mFrameNumber = mCore->mFrameCounter; item.mSlot = slot; item.mFence = fence; item.mIsDroppable = mCore->mDequeueBufferCannotBlock || async; + item.mSurfaceDamage = surfaceDamage; mStickyTransform = stickyTransform; @@ -630,9 +670,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, // mark it as freed if (mCore->stillTracking(front)) { mSlots[front->mSlot].mBufferState = BufferSlot::FREE; - // Reset the frame number of the freed buffer so that it is - // the first in line to be dequeued again - mSlots[front->mSlot].mFrameNumber = 0; + mCore->mFreeBuffers.push_front(front->mSlot); } // Overwrite the droppable buffer with the incoming one *front = item; @@ -647,12 +685,15 @@ status_t BufferQueueProducer::queueBuffer(int slot, mCore->mDequeueCondition.broadcast(); output->inflate(mCore->mDefaultWidth, mCore->mDefaultHeight, - mCore->mTransformHint, mCore->mQueue.size()); + mCore->mTransformHint, + static_cast<uint32_t>(mCore->mQueue.size())); ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size()); // Take a ticket for the callback functions callbackTicket = mNextCallbackTicket++; + + mCore->validateConsistencyLocked(); } // Autolock scope // Wait without lock held @@ -713,10 +754,11 @@ void BufferQueueProducer::cancelBuffer(int slot, const sp<Fence>& fence) { return; } + mCore->mFreeBuffers.push_front(slot); mSlots[slot].mBufferState = BufferSlot::FREE; - mSlots[slot].mFrameNumber = 0; mSlots[slot].mFence = fence; mCore->mDequeueCondition.broadcast(); + mCore->validateConsistencyLocked(); } int BufferQueueProducer::query(int what, int *outValue) { @@ -736,25 +778,35 @@ int BufferQueueProducer::query(int what, int *outValue) { int value; switch (what) { case NATIVE_WINDOW_WIDTH: - value = mCore->mDefaultWidth; + value = static_cast<int32_t>(mCore->mDefaultWidth); break; case NATIVE_WINDOW_HEIGHT: - value = mCore->mDefaultHeight; + value = static_cast<int32_t>(mCore->mDefaultHeight); break; case NATIVE_WINDOW_FORMAT: - value = mCore->mDefaultBufferFormat; + value = static_cast<int32_t>(mCore->mDefaultBufferFormat); break; case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: value = mCore->getMinUndequeuedBufferCountLocked(false); break; case NATIVE_WINDOW_STICKY_TRANSFORM: - value = static_cast<int>(mStickyTransform); + value = static_cast<int32_t>(mStickyTransform); break; case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: value = (mCore->mQueue.size() > 1); break; case NATIVE_WINDOW_CONSUMER_USAGE_BITS: - value = mCore->mConsumerUsageBits; + value = static_cast<int32_t>(mCore->mConsumerUsageBits); + break; + case NATIVE_WINDOW_DEFAULT_DATASPACE: + value = static_cast<int32_t>(mCore->mDefaultBufferDataSpace); + break; + case NATIVE_WINDOW_BUFFER_AGE: + if (mCore->mBufferAge > INT32_MAX) { + value = 0; + } else { + value = static_cast<int32_t>(mCore->mBufferAge); + } break; default: return BAD_VALUE; @@ -802,13 +854,14 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener, case NATIVE_WINDOW_API_CAMERA: mCore->mConnectedApi = api; output->inflate(mCore->mDefaultWidth, mCore->mDefaultHeight, - mCore->mTransformHint, mCore->mQueue.size()); + mCore->mTransformHint, + static_cast<uint32_t>(mCore->mQueue.size())); // Set up a death notification so that we can disconnect // automatically if the remote producer dies if (listener != NULL && - listener->asBinder()->remoteBinder() != NULL) { - status = listener->asBinder()->linkToDeath( + IInterface::asBinder(listener)->remoteBinder() != NULL) { + status = IInterface::asBinder(listener)->linkToDeath( static_cast<IBinder::DeathRecipient*>(this)); if (status != NO_ERROR) { BQ_LOGE("connect(P): linkToDeath failed: %s (%d)", @@ -826,6 +879,7 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener, mCore->mBufferHasBeenQueued = false; mCore->mDequeueBufferCannotBlock = mCore->mConsumerControlledByApp && producerControlledByApp; + mCore->mAllowAllocation = true; return status; } @@ -857,7 +911,7 @@ status_t BufferQueueProducer::disconnect(int api) { // Remove our death notification callback if we have one if (mCore->mConnectedProducerListener != NULL) { sp<IBinder> token = - mCore->mConnectedProducerListener->asBinder(); + IInterface::asBinder(mCore->mConnectedProducerListener); // This can fail if we're here because of the death // notification, but we just ignore it token->unlinkToDeath( @@ -868,8 +922,8 @@ status_t BufferQueueProducer::disconnect(int api) { mCore->mSidebandStream.clear(); mCore->mDequeueCondition.broadcast(); listener = mCore->mConsumerListener; - } else { - BQ_LOGE("disconnect(P): connected to another API " + } else if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) { + BQ_LOGE("disconnect(P): still connected to another API " "(cur=%d req=%d)", mCore->mConnectedApi, api); status = BAD_VALUE; } @@ -904,19 +958,25 @@ status_t BufferQueueProducer::setSidebandStream(const sp<NativeHandle>& stream) } void BufferQueueProducer::allocateBuffers(bool async, uint32_t width, - uint32_t height, uint32_t format, uint32_t usage) { + uint32_t height, PixelFormat format, uint32_t usage) { ATRACE_CALL(); while (true) { Vector<int> freeSlots; size_t newBufferCount = 0; uint32_t allocWidth = 0; uint32_t allocHeight = 0; - uint32_t allocFormat = 0; + PixelFormat allocFormat = PIXEL_FORMAT_UNKNOWN; uint32_t allocUsage = 0; { // Autolock scope Mutex::Autolock lock(mCore->mMutex); mCore->waitWhileAllocatingLocked(); + if (!mCore->mAllowAllocation) { + BQ_LOGE("allocateBuffers: allocation is not allowed for this " + "BufferQueue"); + return; + } + int currentBufferCount = 0; for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) { if (mSlots[slot].mGraphicBuffer != NULL) { @@ -937,7 +997,8 @@ void BufferQueueProducer::allocateBuffers(bool async, uint32_t width, currentBufferCount, maxBufferCount); if (maxBufferCount <= currentBufferCount) return; - newBufferCount = maxBufferCount - currentBufferCount; + newBufferCount = + static_cast<size_t>(maxBufferCount - currentBufferCount); if (freeSlots.size() < newBufferCount) { BQ_LOGE("allocateBuffers: ran out of free slots"); return; @@ -950,7 +1011,7 @@ void BufferQueueProducer::allocateBuffers(bool async, uint32_t width, mCore->mIsAllocating = true; } // Autolock scope - Vector<sp<GraphicBuffer> > buffers; + Vector<sp<GraphicBuffer>> buffers; for (size_t i = 0; i < newBufferCount; ++i) { status_t result = NO_ERROR; sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer( @@ -970,7 +1031,8 @@ void BufferQueueProducer::allocateBuffers(bool async, uint32_t width, Mutex::Autolock lock(mCore->mMutex); uint32_t checkWidth = width > 0 ? width : mCore->mDefaultWidth; uint32_t checkHeight = height > 0 ? height : mCore->mDefaultHeight; - uint32_t checkFormat = format != 0 ? format : mCore->mDefaultBufferFormat; + PixelFormat checkFormat = format != 0 ? + format : mCore->mDefaultBufferFormat; uint32_t checkUsage = usage | mCore->mConsumerUsageBits; if (checkWidth != allocWidth || checkHeight != allocHeight || checkFormat != allocFormat || checkUsage != allocUsage) { @@ -992,17 +1054,48 @@ void BufferQueueProducer::allocateBuffers(bool async, uint32_t width, } mCore->freeBufferLocked(slot); // Clean up the slot first mSlots[slot].mGraphicBuffer = buffers[i]; - mSlots[slot].mFrameNumber = 0; mSlots[slot].mFence = Fence::NO_FENCE; + + // freeBufferLocked puts this slot on the free slots list. Since + // we then attached a buffer, move the slot to free buffer list. + mCore->mFreeSlots.erase(slot); + mCore->mFreeBuffers.push_front(slot); + BQ_LOGV("allocateBuffers: allocated a new buffer in slot %d", slot); } mCore->mIsAllocating = false; mCore->mIsAllocatingCondition.broadcast(); + mCore->validateConsistencyLocked(); } // Autolock scope } } +status_t BufferQueueProducer::allowAllocation(bool allow) { + ATRACE_CALL(); + BQ_LOGV("allowAllocation: %s", allow ? "true" : "false"); + + Mutex::Autolock lock(mCore->mMutex); + mCore->mAllowAllocation = allow; + return NO_ERROR; +} + +status_t BufferQueueProducer::setGenerationNumber(uint32_t generationNumber) { + ATRACE_CALL(); + BQ_LOGV("setGenerationNumber: %u", generationNumber); + + Mutex::Autolock lock(mCore->mMutex); + mCore->mGenerationNumber = generationNumber; + return NO_ERROR; +} + +String8 BufferQueueProducer::getConsumerName() const { + ATRACE_CALL(); + Mutex::Autolock lock(mCore->mMutex); + BQ_LOGV("getConsumerName: %s", mConsumerName.string()); + return mConsumerName; +} + void BufferQueueProducer::binderDied(const wp<android::IBinder>& /* who */) { // If we're here, it means that a producer we were connected to died. // We're guaranteed that we are still connected to it because we remove diff --git a/libs/gui/BufferSlot.cpp b/libs/gui/BufferSlot.cpp index b8877fef61..01595de448 100644 --- a/libs/gui/BufferSlot.cpp +++ b/libs/gui/BufferSlot.cpp @@ -24,8 +24,8 @@ const char* BufferSlot::bufferStateName(BufferState state) { case BufferSlot::QUEUED: return "QUEUED"; case BufferSlot::FREE: return "FREE"; case BufferSlot::ACQUIRED: return "ACQUIRED"; - default: return "Unknown"; } + return "Unknown"; } } // namespace android diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index 210e98e446..04ab06b557 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -27,6 +27,7 @@ #include <hardware/hardware.h> +#include <gui/BufferItem.h> #include <gui/IGraphicBufferAlloc.h> #include <gui/ISurfaceComposer.h> #include <gui/SurfaceComposerClient.h> @@ -39,11 +40,11 @@ #include <utils/Trace.h> // Macros for including the ConsumerBase name in log messages -#define CB_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__) -#define CB_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__) -#define CB_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__) -#define CB_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__) -#define CB_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__) +#define CB_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) +//#define CB_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) +//#define CB_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__) +//#define CB_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__) +#define CB_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__) namespace android { @@ -113,6 +114,21 @@ void ConsumerBase::onFrameAvailable(const BufferItem& item) { } } +void ConsumerBase::onFrameReplaced(const BufferItem &item) { + CB_LOGV("onFrameReplaced"); + + sp<FrameAvailableListener> listener; + { + Mutex::Autolock lock(mMutex); + listener = mFrameAvailableListener.promote(); + } + + if (listener != NULL) { + CB_LOGV("actually calling onFrameReplaced"); + listener->onFrameReplaced(item); + } +} + void ConsumerBase::onBuffersReleased() { Mutex::Autolock lock(mMutex); @@ -155,6 +171,11 @@ void ConsumerBase::abandonLocked() { mConsumer.clear(); } +bool ConsumerBase::isAbandoned() { + Mutex::Autolock _l(mMutex); + return mAbandoned; +} + void ConsumerBase::setFrameAvailableListener( const wp<FrameAvailableListener>& listener) { CB_LOGV("setFrameAvailableListener"); @@ -162,6 +183,37 @@ void ConsumerBase::setFrameAvailableListener( mFrameAvailableListener = listener; } +status_t ConsumerBase::detachBuffer(int slot) { + CB_LOGV("detachBuffer"); + Mutex::Autolock lock(mMutex); + + status_t result = mConsumer->detachBuffer(slot); + if (result != NO_ERROR) { + CB_LOGE("Failed to detach buffer: %d", result); + return result; + } + + freeBufferLocked(slot); + + return result; +} + +status_t ConsumerBase::setDefaultBufferSize(uint32_t width, uint32_t height) { + Mutex::Autolock _l(mMutex); + return mConsumer->setDefaultBufferSize(width, height); +} + +status_t ConsumerBase::setDefaultBufferFormat(PixelFormat defaultFormat) { + Mutex::Autolock _l(mMutex); + return mConsumer->setDefaultBufferFormat(defaultFormat); +} + +status_t ConsumerBase::setDefaultBufferDataSpace( + android_dataspace defaultDataSpace) { + Mutex::Autolock _l(mMutex); + return mConsumer->setDefaultBufferDataSpace(defaultDataSpace); +} + void ConsumerBase::dump(String8& result) const { dump(result, ""); } @@ -179,9 +231,9 @@ void ConsumerBase::dumpLocked(String8& result, const char* prefix) const { } } -status_t ConsumerBase::acquireBufferLocked(BufferQueue::BufferItem *item, - nsecs_t presentWhen) { - status_t err = mConsumer->acquireBuffer(item, presentWhen); +status_t ConsumerBase::acquireBufferLocked(BufferItem *item, + nsecs_t presentWhen, uint64_t maxFrameNumber) { + status_t err = mConsumer->acquireBuffer(item, presentWhen, maxFrameNumber); if (err != NO_ERROR) { return err; } diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp index c541ff4a7a..e29b740188 100644 --- a/libs/gui/CpuConsumer.cpp +++ b/libs/gui/CpuConsumer.cpp @@ -16,22 +16,23 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "CpuConsumer" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS +//#define ATRACE_TAG ATRACE_TAG_GRAPHICS #include <cutils/compiler.h> #include <utils/Log.h> +#include <gui/BufferItem.h> #include <gui/CpuConsumer.h> -#define CC_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__) -#define CC_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__) -#define CC_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__) -#define CC_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__) -#define CC_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__) +#define CC_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) +//#define CC_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) +//#define CC_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__) +#define CC_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__) +#define CC_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__) namespace android { CpuConsumer::CpuConsumer(const sp<IGraphicBufferConsumer>& bq, - uint32_t maxLockedBuffers, bool controlledByApp) : + size_t maxLockedBuffers, bool controlledByApp) : ConsumerBase(bq, controlledByApp), mMaxLockedBuffers(maxLockedBuffers), mCurrentLockedBuffers(0) @@ -40,7 +41,7 @@ CpuConsumer::CpuConsumer(const sp<IGraphicBufferConsumer>& bq, mAcquiredBuffers.insertAt(0, maxLockedBuffers); mConsumer->setConsumerUsageBits(GRALLOC_USAGE_SW_READ_OFTEN); - mConsumer->setMaxAcquiredBufferCount(maxLockedBuffers); + mConsumer->setMaxAcquiredBufferCount(static_cast<int32_t>(maxLockedBuffers)); } CpuConsumer::~CpuConsumer() { @@ -55,30 +56,16 @@ void CpuConsumer::setName(const String8& name) { mConsumer->setConsumerName(name); } -status_t CpuConsumer::setDefaultBufferSize(uint32_t width, uint32_t height) -{ - Mutex::Autolock _l(mMutex); - return mConsumer->setDefaultBufferSize(width, height); -} - -status_t CpuConsumer::setDefaultBufferFormat(uint32_t defaultFormat) -{ - Mutex::Autolock _l(mMutex); - return mConsumer->setDefaultBufferFormat(defaultFormat); -} - static bool isPossiblyYUV(PixelFormat format) { - switch ((int)format) { + switch (static_cast<int>(format)) { case HAL_PIXEL_FORMAT_RGBA_8888: case HAL_PIXEL_FORMAT_RGBX_8888: case HAL_PIXEL_FORMAT_RGB_888: case HAL_PIXEL_FORMAT_RGB_565: case HAL_PIXEL_FORMAT_BGRA_8888: - case HAL_PIXEL_FORMAT_sRGB_A_8888: - case HAL_PIXEL_FORMAT_sRGB_X_8888: case HAL_PIXEL_FORMAT_Y8: case HAL_PIXEL_FORMAT_Y16: - case HAL_PIXEL_FORMAT_RAW16: // same as HAL_PIXEL_FORMAT_RAW_SENSOR + case HAL_PIXEL_FORMAT_RAW16: case HAL_PIXEL_FORMAT_RAW10: case HAL_PIXEL_FORMAT_RAW_OPAQUE: case HAL_PIXEL_FORMAT_BLOB: @@ -100,12 +87,12 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { if (!nativeBuffer) return BAD_VALUE; if (mCurrentLockedBuffers == mMaxLockedBuffers) { - CC_LOGW("Max buffers have been locked (%d), cannot lock anymore.", + CC_LOGW("Max buffers have been locked (%zd), cannot lock anymore.", mMaxLockedBuffers); return NOT_ENOUGH_DATA; } - BufferQueue::BufferItem b; + BufferItem b; Mutex::Autolock _l(mMutex); @@ -173,7 +160,7 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { } size_t lockedIdx = 0; - for (; lockedIdx < mMaxLockedBuffers; lockedIdx++) { + for (; lockedIdx < static_cast<size_t>(mMaxLockedBuffers); lockedIdx++) { if (mAcquiredBuffers[lockedIdx].mSlot == BufferQueue::INVALID_BUFFER_SLOT) { break; @@ -193,19 +180,20 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { nativeBuffer->format = format; nativeBuffer->flexFormat = flexFormat; nativeBuffer->stride = (ycbcr.y != NULL) ? - ycbcr.ystride : + static_cast<uint32_t>(ycbcr.ystride) : mSlots[buf].mGraphicBuffer->getStride(); nativeBuffer->crop = b.mCrop; nativeBuffer->transform = b.mTransform; nativeBuffer->scalingMode = b.mScalingMode; nativeBuffer->timestamp = b.mTimestamp; + nativeBuffer->dataSpace = b.mDataSpace; nativeBuffer->frameNumber = b.mFrameNumber; nativeBuffer->dataCb = reinterpret_cast<uint8_t*>(ycbcr.cb); nativeBuffer->dataCr = reinterpret_cast<uint8_t*>(ycbcr.cr); - nativeBuffer->chromaStride = ycbcr.cstride; - nativeBuffer->chromaStep = ycbcr.chroma_step; + nativeBuffer->chromaStride = static_cast<uint32_t>(ycbcr.cstride); + nativeBuffer->chromaStep = static_cast<uint32_t>(ycbcr.chroma_step); mCurrentLockedBuffers++; @@ -215,10 +203,9 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { status_t CpuConsumer::unlockBuffer(const LockedBuffer &nativeBuffer) { Mutex::Autolock _l(mMutex); size_t lockedIdx = 0; - status_t err; void *bufPtr = reinterpret_cast<void *>(nativeBuffer.data); - for (; lockedIdx < mMaxLockedBuffers; lockedIdx++) { + for (; lockedIdx < static_cast<size_t>(mMaxLockedBuffers); lockedIdx++) { if (bufPtr == mAcquiredBuffers[lockedIdx].mBufferPointer) break; } if (lockedIdx == mMaxLockedBuffers) { @@ -229,13 +216,13 @@ status_t CpuConsumer::unlockBuffer(const LockedBuffer &nativeBuffer) { return releaseAcquiredBufferLocked(lockedIdx); } -status_t CpuConsumer::releaseAcquiredBufferLocked(int lockedIdx) { +status_t CpuConsumer::releaseAcquiredBufferLocked(size_t lockedIdx) { status_t err; int fd = -1; err = mAcquiredBuffers[lockedIdx].mGraphicBuffer->unlockAsync(&fd); if (err != OK) { - CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, + CC_LOGE("%s: Unable to unlock graphic buffer %zd", __FUNCTION__, lockedIdx); return err; } diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index 318c087887..757e08a907 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -29,6 +29,7 @@ #include <hardware/hardware.h> +#include <gui/BufferItem.h> #include <gui/GLConsumer.h> #include <gui/IGraphicBufferAlloc.h> #include <gui/ISurfaceComposer.h> @@ -47,18 +48,28 @@ EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint na namespace android { // Macros for including the GLConsumer name in log messages -#define ST_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__) -#define ST_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__) -#define ST_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__) -#define ST_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__) -#define ST_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__) +#define GLC_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) +#define GLC_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) +//#define GLC_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__) +#define GLC_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__) +#define GLC_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__) static const struct { - size_t width, height; + uint32_t width, height; char const* bits; } kDebugData = { 15, 12, - "___________________________________XX_XX_______X_X_____X_X____X_XXXXXXX_X____XXXXXXXXXXX__" - "___XX_XXX_XX_______XXXXXXX_________X___X_________X_____X__________________________________" + "_______________" + "_______________" + "_____XX_XX_____" + "__X_X_____X_X__" + "__X_XXXXXXX_X__" + "__XXXXXXXXXXX__" + "___XX_XXX_XX___" + "____XXXXXXX____" + "_____X___X_____" + "____X_____X____" + "_______________" + "_______________" }; // Transform matrices @@ -135,7 +146,7 @@ GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex, mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT), mAttached(true) { - ST_LOGV("GLConsumer"); + GLC_LOGV("GLConsumer"); memcpy(mCurrentTransformMatrix, mtxIdentity, sizeof(mCurrentTransformMatrix)); @@ -154,7 +165,7 @@ GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t texTarget, mDefaultWidth(1), mDefaultHeight(1), mFilteringEnabled(true), - mTexName(-1), + mTexName(0), mUseFenceSync(useFenceSync), mTexTarget(texTarget), mEglDisplay(EGL_NO_DISPLAY), @@ -162,7 +173,7 @@ GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t texTarget, mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT), mAttached(false) { - ST_LOGV("GLConsumer"); + GLC_LOGV("GLConsumer"); memcpy(mCurrentTransformMatrix, mtxIdentity, sizeof(mCurrentTransformMatrix)); @@ -186,11 +197,11 @@ status_t GLConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) status_t GLConsumer::updateTexImage() { ATRACE_CALL(); - ST_LOGV("updateTexImage"); + GLC_LOGV("updateTexImage"); Mutex::Autolock lock(mMutex); if (mAbandoned) { - ST_LOGE("updateTexImage: GLConsumer is abandoned!"); + GLC_LOGE("updateTexImage: GLConsumer is abandoned!"); return NO_INIT; } @@ -200,7 +211,7 @@ status_t GLConsumer::updateTexImage() { return err; } - BufferQueue::BufferItem item; + BufferItem item; // Acquire the next buffer. // In asynchronous mode the list is guaranteed to be one buffer @@ -209,11 +220,11 @@ status_t GLConsumer::updateTexImage() { if (err != NO_ERROR) { if (err == BufferQueue::NO_BUFFER_AVAILABLE) { // We always bind the texture even if we don't update its contents. - ST_LOGV("updateTexImage: no buffers were available"); + GLC_LOGV("updateTexImage: no buffers were available"); glBindTexture(mTexTarget, mTexName); err = NO_ERROR; } else { - ST_LOGE("updateTexImage: acquire failed: %s (%d)", + GLC_LOGE("updateTexImage: acquire failed: %s (%d)", strerror(-err), err); } return err; @@ -234,11 +245,11 @@ status_t GLConsumer::updateTexImage() { status_t GLConsumer::releaseTexImage() { ATRACE_CALL(); - ST_LOGV("releaseTexImage"); + GLC_LOGV("releaseTexImage"); Mutex::Autolock lock(mMutex); if (mAbandoned) { - ST_LOGE("releaseTexImage: GLConsumer is abandoned!"); + GLC_LOGE("releaseTexImage: GLConsumer is abandoned!"); return NO_INIT; } @@ -258,13 +269,13 @@ status_t GLConsumer::releaseTexImage() { int buf = mCurrentTexture; if (buf != BufferQueue::INVALID_BUFFER_SLOT) { - ST_LOGV("releaseTexImage: (slot=%d, mAttached=%d)", buf, mAttached); + GLC_LOGV("releaseTexImage: (slot=%d, mAttached=%d)", buf, mAttached); if (mAttached) { // Do whatever sync ops we need to do before releasing the slot. err = syncForReleaseLocked(mEglDisplay); if (err != NO_ERROR) { - ST_LOGE("syncForReleaseLocked failed (slot=%d), err=%d", buf, err); + GLC_LOGE("syncForReleaseLocked failed (slot=%d), err=%d", buf, err); return err; } } else { @@ -274,7 +285,7 @@ status_t GLConsumer::releaseTexImage() { err = releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR); if (err < NO_ERROR) { - ST_LOGE("releaseTexImage: failed to release buffer: %s (%d)", + GLC_LOGE("releaseTexImage: failed to release buffer: %s (%d)", strerror(-err), err); return err; } @@ -293,9 +304,9 @@ status_t GLConsumer::releaseTexImage() { if (mAttached) { // This binds a dummy buffer (mReleasedTexImage). - status_t err = bindTextureImageLocked(); - if (err != NO_ERROR) { - return err; + status_t result = bindTextureImageLocked(); + if (result != NO_ERROR) { + return result; } } else { // detached, don't touch the texture (and we may not even have an @@ -316,14 +327,15 @@ sp<GraphicBuffer> GLConsumer::getDebugTexImageBuffer() { GraphicBuffer::USAGE_SW_WRITE_RARELY); uint32_t* bits; buffer->lock(GraphicBuffer::USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&bits)); - size_t w = buffer->getStride(); - size_t h = buffer->getHeight(); - memset(bits, 0, w*h*4); - for (size_t y=0 ; y<kDebugData.height ; y++) { - for (size_t x=0 ; x<kDebugData.width ; x++) { - bits[x] = (kDebugData.bits[y*kDebugData.width+x] == 'X') ? 0xFF000000 : 0xFFFFFFFF; + uint32_t stride = buffer->getStride(); + uint32_t height = buffer->getHeight(); + memset(bits, 0, stride * height * 4); + for (uint32_t y = 0; y < kDebugData.height; y++) { + for (uint32_t x = 0; x < kDebugData.width; x++) { + bits[x] = (kDebugData.bits[y + kDebugData.width + x] == 'X') ? + 0xFF000000 : 0xFFFFFFFF; } - bits += w; + bits += stride; } buffer->unlock(); sReleasedTexImageBuffer = buffer; @@ -331,9 +343,10 @@ sp<GraphicBuffer> GLConsumer::getDebugTexImageBuffer() { return sReleasedTexImageBuffer; } -status_t GLConsumer::acquireBufferLocked(BufferQueue::BufferItem *item, - nsecs_t presentWhen) { - status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen); +status_t GLConsumer::acquireBufferLocked(BufferItem *item, + nsecs_t presentWhen, uint64_t maxFrameNumber) { + status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen, + maxFrameNumber); if (err != NO_ERROR) { return err; } @@ -362,14 +375,14 @@ status_t GLConsumer::releaseBufferLocked(int buf, return err; } -status_t GLConsumer::updateAndReleaseLocked(const BufferQueue::BufferItem& item) +status_t GLConsumer::updateAndReleaseLocked(const BufferItem& item) { status_t err = NO_ERROR; int buf = item.mBuf; if (!mAttached) { - ST_LOGE("updateAndRelease: GLConsumer is not attached to an OpenGL " + GLC_LOGE("updateAndRelease: GLConsumer is not attached to an OpenGL " "ES context"); releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR); @@ -391,7 +404,7 @@ status_t GLConsumer::updateAndReleaseLocked(const BufferQueue::BufferItem& item) // means the buffer was previously acquired). err = mEglSlots[buf].mEglImage->createIfNeeded(mEglDisplay, item.mCrop); if (err != NO_ERROR) { - ST_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d", + GLC_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d", mEglDisplay, buf); releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR); @@ -410,7 +423,7 @@ status_t GLConsumer::updateAndReleaseLocked(const BufferQueue::BufferItem& item) return err; } - ST_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", + GLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture, mCurrentTextureImage != NULL ? mCurrentTextureImage->graphicBufferHandle() : 0, buf, mSlots[buf].mGraphicBuffer->handle); @@ -421,7 +434,7 @@ status_t GLConsumer::updateAndReleaseLocked(const BufferQueue::BufferItem& item) mCurrentTexture, mCurrentTextureImage->graphicBuffer(), mEglDisplay, mEglSlots[mCurrentTexture].mEglFence); if (status < NO_ERROR) { - ST_LOGE("updateAndRelease: failed to release buffer: %s (%d)", + GLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status), status); err = status; // keep going, with error raised [?] @@ -449,22 +462,22 @@ status_t GLConsumer::bindTextureImageLocked() { return INVALID_OPERATION; } - GLint error; + GLenum error; while ((error = glGetError()) != GL_NO_ERROR) { - ST_LOGW("bindTextureImage: clearing GL error: %#04x", error); + GLC_LOGW("bindTextureImage: clearing GL error: %#04x", error); } glBindTexture(mTexTarget, mTexName); if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && mCurrentTextureImage == NULL) { - ST_LOGE("bindTextureImage: no currently-bound texture"); + GLC_LOGE("bindTextureImage: no currently-bound texture"); return NO_INIT; } status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay, mCurrentCrop); if (err != NO_ERROR) { - ST_LOGW("bindTextureImage: can't create image on display=%p slot=%d", + GLC_LOGW("bindTextureImage: can't create image on display=%p slot=%d", mEglDisplay, mCurrentTexture); return UNKNOWN_ERROR; } @@ -476,17 +489,17 @@ status_t GLConsumer::bindTextureImageLocked() { // forcing the creation of a new image. if ((error = glGetError()) != GL_NO_ERROR) { glBindTexture(mTexTarget, mTexName); - status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay, - mCurrentCrop, - true); - if (err != NO_ERROR) { - ST_LOGW("bindTextureImage: can't create image on display=%p slot=%d", + status_t result = mCurrentTextureImage->createIfNeeded(mEglDisplay, + mCurrentCrop, + true); + if (result != NO_ERROR) { + GLC_LOGW("bindTextureImage: can't create image on display=%p slot=%d", mEglDisplay, mCurrentTexture); return UNKNOWN_ERROR; } mCurrentTextureImage->bindToTextureTarget(mTexTarget); if ((error = glGetError()) != GL_NO_ERROR) { - ST_LOGE("bindTextureImage: error binding external image: %#04x", error); + GLC_LOGE("bindTextureImage: error binding external image: %#04x", error); return UNKNOWN_ERROR; } } @@ -511,12 +524,12 @@ status_t GLConsumer::checkAndUpdateEglStateLocked(bool contextCheck) { } if (mEglDisplay != dpy || dpy == EGL_NO_DISPLAY) { - ST_LOGE("checkAndUpdateEglState: invalid current EGLDisplay"); + GLC_LOGE("checkAndUpdateEglState: invalid current EGLDisplay"); return INVALID_OPERATION; } if (mEglContext != ctx || ctx == EGL_NO_CONTEXT) { - ST_LOGE("checkAndUpdateEglState: invalid current EGLContext"); + GLC_LOGE("checkAndUpdateEglState: invalid current EGLContext"); return INVALID_OPERATION; } @@ -531,7 +544,7 @@ void GLConsumer::setReleaseFence(const sp<Fence>& fence) { status_t err = addReleaseFence(mCurrentTexture, mCurrentTextureImage->graphicBuffer(), fence); if (err != OK) { - ST_LOGE("setReleaseFence: failed to add the fence: %s (%d)", + GLC_LOGE("setReleaseFence: failed to add the fence: %s (%d)", strerror(-err), err); } } @@ -539,16 +552,16 @@ void GLConsumer::setReleaseFence(const sp<Fence>& fence) { status_t GLConsumer::detachFromContext() { ATRACE_CALL(); - ST_LOGV("detachFromContext"); + GLC_LOGV("detachFromContext"); Mutex::Autolock lock(mMutex); if (mAbandoned) { - ST_LOGE("detachFromContext: abandoned GLConsumer"); + GLC_LOGE("detachFromContext: abandoned GLConsumer"); return NO_INIT; } if (!mAttached) { - ST_LOGE("detachFromContext: GLConsumer is not attached to a " + GLC_LOGE("detachFromContext: GLConsumer is not attached to a " "context"); return INVALID_OPERATION; } @@ -557,12 +570,12 @@ status_t GLConsumer::detachFromContext() { EGLContext ctx = eglGetCurrentContext(); if (mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) { - ST_LOGE("detachFromContext: invalid current EGLDisplay"); + GLC_LOGE("detachFromContext: invalid current EGLDisplay"); return INVALID_OPERATION; } if (mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) { - ST_LOGE("detachFromContext: invalid current EGLContext"); + GLC_LOGE("detachFromContext: invalid current EGLContext"); return INVALID_OPERATION; } @@ -584,16 +597,16 @@ status_t GLConsumer::detachFromContext() { status_t GLConsumer::attachToContext(uint32_t tex) { ATRACE_CALL(); - ST_LOGV("attachToContext"); + GLC_LOGV("attachToContext"); Mutex::Autolock lock(mMutex); if (mAbandoned) { - ST_LOGE("attachToContext: abandoned GLConsumer"); + GLC_LOGE("attachToContext: abandoned GLConsumer"); return NO_INIT; } if (mAttached) { - ST_LOGE("attachToContext: GLConsumer is already attached to a " + GLC_LOGE("attachToContext: GLConsumer is already attached to a " "context"); return INVALID_OPERATION; } @@ -602,12 +615,12 @@ status_t GLConsumer::attachToContext(uint32_t tex) { EGLContext ctx = eglGetCurrentContext(); if (dpy == EGL_NO_DISPLAY) { - ST_LOGE("attachToContext: invalid current EGLDisplay"); + GLC_LOGE("attachToContext: invalid current EGLDisplay"); return INVALID_OPERATION; } if (ctx == EGL_NO_CONTEXT) { - ST_LOGE("attachToContext: invalid current EGLContext"); + GLC_LOGE("attachToContext: invalid current EGLContext"); return INVALID_OPERATION; } @@ -636,14 +649,14 @@ status_t GLConsumer::attachToContext(uint32_t tex) { status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) { - ST_LOGV("syncForReleaseLocked"); + GLC_LOGV("syncForReleaseLocked"); if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { if (SyncFeatures::getInstance().useNativeFenceSync()) { EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL); if (sync == EGL_NO_SYNC_KHR) { - ST_LOGE("syncForReleaseLocked: error creating EGL fence: %#x", + GLC_LOGE("syncForReleaseLocked: error creating EGL fence: %#x", eglGetError()); return UNKNOWN_ERROR; } @@ -651,7 +664,7 @@ status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) { int fenceFd = eglDupNativeFenceFDANDROID(dpy, sync); eglDestroySyncKHR(dpy, sync); if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { - ST_LOGE("syncForReleaseLocked: error dup'ing native fence " + GLC_LOGE("syncForReleaseLocked: error dup'ing native fence " "fd: %#x", eglGetError()); return UNKNOWN_ERROR; } @@ -659,7 +672,7 @@ status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) { status_t err = addReleaseFenceLocked(mCurrentTexture, mCurrentTextureImage->graphicBuffer(), fence); if (err != OK) { - ST_LOGE("syncForReleaseLocked: error adding release fence: " + GLC_LOGE("syncForReleaseLocked: error adding release fence: " "%s (%d)", strerror(-err), err); return err; } @@ -672,11 +685,11 @@ status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) { // before the producer accesses it. EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000); if (result == EGL_FALSE) { - ST_LOGE("syncForReleaseLocked: error waiting for previous " + GLC_LOGE("syncForReleaseLocked: error waiting for previous " "fence: %#x", eglGetError()); return UNKNOWN_ERROR; } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { - ST_LOGE("syncForReleaseLocked: timeout waiting for previous " + GLC_LOGE("syncForReleaseLocked: timeout waiting for previous " "fence"); return TIMED_OUT; } @@ -687,7 +700,7 @@ status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) { // OpenGL ES context. fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL); if (fence == EGL_NO_SYNC_KHR) { - ST_LOGE("syncForReleaseLocked: error creating fence: %#x", + GLC_LOGE("syncForReleaseLocked: error creating fence: %#x", eglGetError()); return UNKNOWN_ERROR; } @@ -699,7 +712,7 @@ status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) { return OK; } -bool GLConsumer::isExternalFormat(uint32_t format) +bool GLConsumer::isExternalFormat(PixelFormat format) { switch (format) { // supported YUV formats @@ -730,14 +743,14 @@ void GLConsumer::getTransformMatrix(float mtx[16]) { void GLConsumer::setFilteringEnabled(bool enabled) { Mutex::Autolock lock(mMutex); if (mAbandoned) { - ST_LOGE("setFilteringEnabled: GLConsumer is abandoned!"); + GLC_LOGE("setFilteringEnabled: GLConsumer is abandoned!"); return; } bool needsRecompute = mFilteringEnabled != enabled; mFilteringEnabled = enabled; if (needsRecompute && mCurrentTextureImage==NULL) { - ST_LOGD("setFilteringEnabled called with mCurrentTextureImage == NULL"); + GLC_LOGD("setFilteringEnabled called with mCurrentTextureImage == NULL"); } if (needsRecompute && mCurrentTextureImage != NULL) { @@ -746,7 +759,7 @@ void GLConsumer::setFilteringEnabled(bool enabled) { } void GLConsumer::computeCurrentTransformMatrixLocked() { - ST_LOGV("computeCurrentTransformMatrixLocked"); + GLC_LOGV("computeCurrentTransformMatrixLocked"); float xform[16]; for (int i = 0; i < 16; i++) { @@ -778,7 +791,7 @@ void GLConsumer::computeCurrentTransformMatrixLocked() { NULL : mCurrentTextureImage->graphicBuffer(); if (buf == NULL) { - ST_LOGD("computeCurrentTransformMatrixLocked: mCurrentTextureImage is NULL"); + GLC_LOGD("computeCurrentTransformMatrixLocked: mCurrentTextureImage is NULL"); } float mtxBeforeFlipV[16]; @@ -850,13 +863,13 @@ void GLConsumer::computeCurrentTransformMatrixLocked() { } nsecs_t GLConsumer::getTimestamp() { - ST_LOGV("getTimestamp"); + GLC_LOGV("getTimestamp"); Mutex::Autolock lock(mMutex); return mCurrentTimestamp; } -nsecs_t GLConsumer::getFrameNumber() { - ST_LOGV("getFrameNumber"); +uint64_t GLConsumer::getFrameNumber() { + GLC_LOGV("getFrameNumber"); Mutex::Autolock lock(mMutex); return mCurrentFrameNumber; } @@ -872,30 +885,37 @@ Rect GLConsumer::getCurrentCrop() const { Rect outCrop = mCurrentCrop; if (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) { - int32_t newWidth = mCurrentCrop.width(); - int32_t newHeight = mCurrentCrop.height(); + uint32_t newWidth = static_cast<uint32_t>(mCurrentCrop.width()); + uint32_t newHeight = static_cast<uint32_t>(mCurrentCrop.height()); if (newWidth * mDefaultHeight > newHeight * mDefaultWidth) { newWidth = newHeight * mDefaultWidth / mDefaultHeight; - ST_LOGV("too wide: newWidth = %d", newWidth); + GLC_LOGV("too wide: newWidth = %d", newWidth); } else if (newWidth * mDefaultHeight < newHeight * mDefaultWidth) { newHeight = newWidth * mDefaultHeight / mDefaultWidth; - ST_LOGV("too tall: newHeight = %d", newHeight); + GLC_LOGV("too tall: newHeight = %d", newHeight); } + uint32_t currentWidth = static_cast<uint32_t>(mCurrentCrop.width()); + uint32_t currentHeight = static_cast<uint32_t>(mCurrentCrop.height()); + // The crop is too wide - if (newWidth < mCurrentCrop.width()) { - int32_t dw = (newWidth - mCurrentCrop.width())/2; - outCrop.left -=dw; - outCrop.right += dw; + if (newWidth < currentWidth) { + uint32_t dw = currentWidth - newWidth; + auto halfdw = dw / 2; + outCrop.left += halfdw; + // Not halfdw because it would subtract 1 too few when dw is odd + outCrop.right -= (dw - halfdw); // The crop is too tall - } else if (newHeight < mCurrentCrop.height()) { - int32_t dh = (newHeight - mCurrentCrop.height())/2; - outCrop.top -= dh; - outCrop.bottom += dh; + } else if (newHeight < currentHeight) { + uint32_t dh = currentHeight - newHeight; + auto halfdh = dh / 2; + outCrop.top += halfdh; + // Not halfdh because it would subtract 1 too few when dh is odd + outCrop.bottom -= (dh - halfdh); } - ST_LOGV("getCurrentCrop final crop [%d,%d,%d,%d]", + GLC_LOGV("getCurrentCrop final crop [%d,%d,%d,%d]", outCrop.left, outCrop.top, outCrop.right,outCrop.bottom); } @@ -929,12 +949,12 @@ status_t GLConsumer::doGLFenceWaitLocked() const { EGLContext ctx = eglGetCurrentContext(); if (mEglDisplay != dpy || mEglDisplay == EGL_NO_DISPLAY) { - ST_LOGE("doGLFenceWait: invalid current EGLDisplay"); + GLC_LOGE("doGLFenceWait: invalid current EGLDisplay"); return INVALID_OPERATION; } if (mEglContext != ctx || mEglContext == EGL_NO_CONTEXT) { - ST_LOGE("doGLFenceWait: invalid current EGLContext"); + GLC_LOGE("doGLFenceWait: invalid current EGLContext"); return INVALID_OPERATION; } @@ -943,7 +963,7 @@ status_t GLConsumer::doGLFenceWaitLocked() const { // Create an EGLSyncKHR from the current fence. int fenceFd = mCurrentFence->dup(); if (fenceFd == -1) { - ST_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno); + GLC_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno); return -errno; } EGLint attribs[] = { @@ -954,7 +974,7 @@ status_t GLConsumer::doGLFenceWaitLocked() const { EGL_SYNC_NATIVE_FENCE_ANDROID, attribs); if (sync == EGL_NO_SYNC_KHR) { close(fenceFd); - ST_LOGE("doGLFenceWait: error creating EGL fence: %#x", + GLC_LOGE("doGLFenceWait: error creating EGL fence: %#x", eglGetError()); return UNKNOWN_ERROR; } @@ -966,7 +986,7 @@ status_t GLConsumer::doGLFenceWaitLocked() const { EGLint eglErr = eglGetError(); eglDestroySyncKHR(dpy, sync); if (eglErr != EGL_SUCCESS) { - ST_LOGE("doGLFenceWait: error waiting for EGL fence: %#x", + GLC_LOGE("doGLFenceWait: error waiting for EGL fence: %#x", eglErr); return UNKNOWN_ERROR; } @@ -974,7 +994,7 @@ status_t GLConsumer::doGLFenceWaitLocked() const { status_t err = mCurrentFence->waitForever( "GLConsumer::doGLFenceWaitLocked"); if (err != NO_ERROR) { - ST_LOGE("doGLFenceWait: error waiting for fence: %d", err); + GLC_LOGE("doGLFenceWait: error waiting for fence: %d", err); return err; } } @@ -984,7 +1004,7 @@ status_t GLConsumer::doGLFenceWaitLocked() const { } void GLConsumer::freeBufferLocked(int slotIndex) { - ST_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); + GLC_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); if (slotIndex == mCurrentTexture) { mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT; } @@ -993,7 +1013,7 @@ void GLConsumer::freeBufferLocked(int slotIndex) { } void GLConsumer::abandonLocked() { - ST_LOGV("abandonLocked"); + GLC_LOGV("abandonLocked"); mCurrentTextureImage.clear(); ConsumerBase::abandonLocked(); } @@ -1004,11 +1024,17 @@ void GLConsumer::setName(const String8& name) { mConsumer->setConsumerName(name); } -status_t GLConsumer::setDefaultBufferFormat(uint32_t defaultFormat) { +status_t GLConsumer::setDefaultBufferFormat(PixelFormat defaultFormat) { Mutex::Autolock lock(mMutex); return mConsumer->setDefaultBufferFormat(defaultFormat); } +status_t GLConsumer::setDefaultBufferDataSpace( + android_dataspace defaultDataSpace) { + Mutex::Autolock lock(mMutex); + return mConsumer->setDefaultBufferDataSpace(defaultDataSpace); +} + status_t GLConsumer::setConsumerUsageBits(uint32_t usage) { Mutex::Autolock lock(mMutex); usage |= DEFAULT_USAGE_FLAGS; @@ -1107,12 +1133,14 @@ status_t GLConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay, } void GLConsumer::EglImage::bindToTextureTarget(uint32_t texTarget) { - glEGLImageTargetTexture2DOES(texTarget, (GLeglImageOES)mEglImage); + glEGLImageTargetTexture2DOES(texTarget, + static_cast<GLeglImageOES>(mEglImage)); } EGLImageKHR GLConsumer::EglImage::createImage(EGLDisplay dpy, const sp<GraphicBuffer>& graphicBuffer, const Rect& crop) { - EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer(); + EGLClientBuffer cbuf = + static_cast<EGLClientBuffer>(graphicBuffer->getNativeBuffer()); EGLint attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_IMAGE_CROP_LEFT_ANDROID, crop.left, diff --git a/libs/gui/GraphicBufferAlloc.cpp b/libs/gui/GraphicBufferAlloc.cpp index b360e81d41..9643402dfa 100644 --- a/libs/gui/GraphicBufferAlloc.cpp +++ b/libs/gui/GraphicBufferAlloc.cpp @@ -31,9 +31,10 @@ GraphicBufferAlloc::GraphicBufferAlloc() { GraphicBufferAlloc::~GraphicBufferAlloc() { } -sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h, - PixelFormat format, uint32_t usage, status_t* error) { - sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage)); +sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t width, + uint32_t height, PixelFormat format, uint32_t usage, status_t* error) { + sp<GraphicBuffer> graphicBuffer( + new GraphicBuffer(width, height, format, usage)); status_t err = graphicBuffer->initCheck(); *error = err; if (err != 0 || graphicBuffer->handle == 0) { @@ -42,7 +43,7 @@ sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h } ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) " "failed (%s), handle=%p", - w, h, strerror(-err), graphicBuffer->handle); + width, height, strerror(-err), graphicBuffer->handle); return 0; } return graphicBuffer; diff --git a/libs/gui/IConsumerListener.cpp b/libs/gui/IConsumerListener.cpp index 409dfe4ee0..cab7dc3d5a 100644 --- a/libs/gui/IConsumerListener.cpp +++ b/libs/gui/IConsumerListener.cpp @@ -40,6 +40,8 @@ public: : BpInterface<IConsumerListener>(impl) { } + virtual ~BpConsumerListener(); + virtual void onFrameAvailable(const BufferItem& item) { Parcel data, reply; data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor()); @@ -60,6 +62,10 @@ public: } }; +// Out-of-line virtual method definition to trigger vtable emission in this +// translation unit (see clang warning -Wweak-vtables) +BpConsumerListener::~BpConsumerListener() {} + IMPLEMENT_META_INTERFACE(ConsumerListener, "android.gui.IConsumerListener"); // ---------------------------------------------------------------------- diff --git a/libs/gui/IDisplayEventConnection.cpp b/libs/gui/IDisplayEventConnection.cpp index 887d176b44..9890f44ef7 100644 --- a/libs/gui/IDisplayEventConnection.cpp +++ b/libs/gui/IDisplayEventConnection.cpp @@ -44,6 +44,8 @@ public: { } + virtual ~BpDisplayEventConnection(); + virtual sp<BitTube> getDataChannel() const { Parcel data, reply; @@ -55,7 +57,7 @@ public: virtual void setVsyncRate(uint32_t count) { Parcel data, reply; data.writeInterfaceToken(IDisplayEventConnection::getInterfaceDescriptor()); - data.writeInt32(count); + data.writeUint32(count); remote()->transact(SET_VSYNC_RATE, data, &reply); } @@ -66,6 +68,10 @@ public: } }; +// Out-of-line virtual method definition to trigger vtable emission in this +// translation unit (see clang warning -Wweak-vtables) +BpDisplayEventConnection::~BpDisplayEventConnection() {} + IMPLEMENT_META_INTERFACE(DisplayEventConnection, "android.gui.DisplayEventConnection"); // ---------------------------------------------------------------------------- @@ -79,17 +85,17 @@ status_t BnDisplayEventConnection::onTransact( sp<BitTube> channel(getDataChannel()); channel->writeToParcel(reply); return NO_ERROR; - } break; + } case SET_VSYNC_RATE: { CHECK_INTERFACE(IDisplayEventConnection, data, reply); - setVsyncRate(data.readInt32()); + setVsyncRate(data.readUint32()); return NO_ERROR; - } break; + } case REQUEST_NEXT_VSYNC: { CHECK_INTERFACE(IDisplayEventConnection, data, reply); requestNextVsync(); return NO_ERROR; - } break; + } } return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/IGraphicBufferAlloc.cpp b/libs/gui/IGraphicBufferAlloc.cpp index 139f2199a3..3009989964 100644 --- a/libs/gui/IGraphicBufferAlloc.cpp +++ b/libs/gui/IGraphicBufferAlloc.cpp @@ -42,20 +42,26 @@ public: { } - virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h, - PixelFormat format, uint32_t usage, status_t* error) { + virtual ~BpGraphicBufferAlloc(); + + virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t width, + uint32_t height, PixelFormat format, uint32_t usage, + status_t* error) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferAlloc::getInterfaceDescriptor()); - data.writeInt32(w); - data.writeInt32(h); - data.writeInt32(format); - data.writeInt32(usage); + data.writeUint32(width); + data.writeUint32(height); + data.writeInt32(static_cast<int32_t>(format)); + data.writeUint32(usage); remote()->transact(CREATE_GRAPHIC_BUFFER, data, &reply); sp<GraphicBuffer> graphicBuffer; status_t result = reply.readInt32(); if (result == NO_ERROR) { graphicBuffer = new GraphicBuffer(); result = reply.read(*graphicBuffer); + if (result != NO_ERROR) { + graphicBuffer.clear(); + } // reply.readStrongBinder(); // here we don't even have to read the BufferReference from // the parcel, it'll die with the parcel. @@ -65,6 +71,10 @@ public: } }; +// Out-of-line virtual method definition to trigger vtable emission in this +// translation unit (see clang warning -Wweak-vtables) +BpGraphicBufferAlloc::~BpGraphicBufferAlloc() {} + IMPLEMENT_META_INTERFACE(GraphicBufferAlloc, "android.ui.IGraphicBufferAlloc"); // ---------------------------------------------------------------------- @@ -74,27 +84,26 @@ status_t BnGraphicBufferAlloc::onTransact( { // codes that don't require permission check - /* BufferReference just keeps a strong reference to a - * GraphicBuffer until it is destroyed (that is, until - * no local or remote process have a reference to it). - */ + // BufferReference just keeps a strong reference to a GraphicBuffer until it + // is destroyed (that is, until no local or remote process have a reference + // to it). class BufferReference : public BBinder { - sp<GraphicBuffer> buffer; + sp<GraphicBuffer> mBuffer; public: - BufferReference(const sp<GraphicBuffer>& buffer) : buffer(buffer) { } + BufferReference(const sp<GraphicBuffer>& buffer) : mBuffer(buffer) {} }; - switch(code) { + switch (code) { case CREATE_GRAPHIC_BUFFER: { CHECK_INTERFACE(IGraphicBufferAlloc, data, reply); - uint32_t w = data.readInt32(); - uint32_t h = data.readInt32(); - PixelFormat format = data.readInt32(); - uint32_t usage = data.readInt32(); + uint32_t width = data.readUint32(); + uint32_t height = data.readUint32(); + PixelFormat format = static_cast<PixelFormat>(data.readInt32()); + uint32_t usage = data.readUint32(); status_t error; sp<GraphicBuffer> result = - createGraphicBuffer(w, h, format, usage, &error); + createGraphicBuffer(width, height, format, usage, &error); reply->writeInt32(error); if (result != 0) { reply->write(*result); @@ -107,7 +116,7 @@ status_t BnGraphicBufferAlloc::onTransact( reply->writeStrongBinder( new BufferReference(result) ); } return NO_ERROR; - } break; + } default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp index 590a25e4cc..7ae82e0561 100644 --- a/libs/gui/IGraphicBufferConsumer.cpp +++ b/libs/gui/IGraphicBufferConsumer.cpp @@ -23,6 +23,7 @@ #include <binder/Parcel.h> #include <binder/IInterface.h> +#include <gui/BufferItem.h> #include <gui/IConsumerListener.h> #include <gui/IGraphicBufferConsumer.h> @@ -32,159 +33,6 @@ #include <system/window.h> namespace android { -// --------------------------------------------------------------------------- - -IGraphicBufferConsumer::BufferItem::BufferItem() : - mTransform(0), - mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), - mTimestamp(0), - mIsAutoTimestamp(false), - mFrameNumber(0), - mBuf(INVALID_BUFFER_SLOT), - mIsDroppable(false), - mAcquireCalled(false), - mTransformToDisplayInverse(false) { - mCrop.makeInvalid(); -} - -size_t IGraphicBufferConsumer::BufferItem::getPodSize() const { - size_t c = sizeof(mCrop) + - sizeof(mTransform) + - sizeof(mScalingMode) + - sizeof(mTimestamp) + - sizeof(mIsAutoTimestamp) + - sizeof(mFrameNumber) + - sizeof(mBuf) + - sizeof(mIsDroppable) + - sizeof(mAcquireCalled) + - sizeof(mTransformToDisplayInverse); - return c; -} - -size_t IGraphicBufferConsumer::BufferItem::getFlattenedSize() const { - size_t c = 0; - if (mGraphicBuffer != 0) { - c += mGraphicBuffer->getFlattenedSize(); - c = FlattenableUtils::align<4>(c); - } - if (mFence != 0) { - c += mFence->getFlattenedSize(); - c = FlattenableUtils::align<4>(c); - } - return sizeof(int32_t) + c + getPodSize(); -} - -size_t IGraphicBufferConsumer::BufferItem::getFdCount() const { - size_t c = 0; - if (mGraphicBuffer != 0) { - c += mGraphicBuffer->getFdCount(); - } - if (mFence != 0) { - c += mFence->getFdCount(); - } - return c; -} - -static void writeBoolAsInt(void*& buffer, size_t& size, bool b) { - FlattenableUtils::write(buffer, size, static_cast<int32_t>(b)); -} - -static bool readBoolFromInt(void const*& buffer, size_t& size) { - int32_t i; - FlattenableUtils::read(buffer, size, i); - return static_cast<bool>(i); -} - -status_t IGraphicBufferConsumer::BufferItem::flatten( - void*& buffer, size_t& size, int*& fds, size_t& count) const { - - // make sure we have enough space - if (size < BufferItem::getFlattenedSize()) { - return NO_MEMORY; - } - - // content flags are stored first - uint32_t& flags = *static_cast<uint32_t*>(buffer); - - // advance the pointer - FlattenableUtils::advance(buffer, size, sizeof(uint32_t)); - - flags = 0; - if (mGraphicBuffer != 0) { - status_t err = mGraphicBuffer->flatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - flags |= 1; - } - if (mFence != 0) { - status_t err = mFence->flatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - flags |= 2; - } - - // check we have enough space (in case flattening the fence/graphicbuffer lied to us) - if (size < getPodSize()) { - return NO_MEMORY; - } - - FlattenableUtils::write(buffer, size, mCrop); - FlattenableUtils::write(buffer, size, mTransform); - FlattenableUtils::write(buffer, size, mScalingMode); - FlattenableUtils::write(buffer, size, mTimestamp); - writeBoolAsInt(buffer, size, mIsAutoTimestamp); - FlattenableUtils::write(buffer, size, mFrameNumber); - FlattenableUtils::write(buffer, size, mBuf); - writeBoolAsInt(buffer, size, mIsDroppable); - writeBoolAsInt(buffer, size, mAcquireCalled); - writeBoolAsInt(buffer, size, mTransformToDisplayInverse); - - return NO_ERROR; -} - -status_t IGraphicBufferConsumer::BufferItem::unflatten( - void const*& buffer, size_t& size, int const*& fds, size_t& count) { - - if (size < sizeof(uint32_t)) - return NO_MEMORY; - - uint32_t flags = 0; - FlattenableUtils::read(buffer, size, flags); - - if (flags & 1) { - mGraphicBuffer = new GraphicBuffer(); - status_t err = mGraphicBuffer->unflatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - } - - if (flags & 2) { - mFence = new Fence(); - status_t err = mFence->unflatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - } - - // check we have enough space - if (size < getPodSize()) { - return NO_MEMORY; - } - - FlattenableUtils::read(buffer, size, mCrop); - FlattenableUtils::read(buffer, size, mTransform); - FlattenableUtils::read(buffer, size, mScalingMode); - FlattenableUtils::read(buffer, size, mTimestamp); - mIsAutoTimestamp = readBoolFromInt(buffer, size); - FlattenableUtils::read(buffer, size, mFrameNumber); - FlattenableUtils::read(buffer, size, mBuf); - mIsDroppable = readBoolFromInt(buffer, size); - mAcquireCalled = readBoolFromInt(buffer, size); - mTransformToDisplayInverse = readBoolFromInt(buffer, size); - - return NO_ERROR; -} - -// --------------------------------------------------------------------------- enum { ACQUIRE_BUFFER = IBinder::FIRST_CALL_TRANSACTION, @@ -200,6 +48,7 @@ enum { SET_MAX_ACQUIRED_BUFFER_COUNT, SET_CONSUMER_NAME, SET_DEFAULT_BUFFER_FORMAT, + SET_DEFAULT_BUFFER_DATA_SPACE, SET_CONSUMER_USAGE_BITS, SET_TRANSFORM_HINT, GET_SIDEBAND_STREAM, @@ -215,10 +64,14 @@ public: { } - virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen) { + virtual ~BpGraphicBufferConsumer(); + + virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen, + uint64_t maxFrameNumber) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); data.writeInt64(presentWhen); + data.writeUint64(maxFrameNumber); status_t result = remote()->transact(ACQUIRE_BUFFER, data, &reply); if (result != NO_ERROR) { return result; @@ -261,7 +114,7 @@ public: Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); data.writeInt32(buf); - data.writeInt64(frameNumber); + data.writeInt64(static_cast<int64_t>(frameNumber)); data.write(*releaseFence); status_t result = remote()->transact(RELEASE_BUFFER, data, &reply); if (result != NO_ERROR) { @@ -273,7 +126,7 @@ public: virtual status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeStrongBinder(consumer->asBinder()); + data.writeStrongBinder(IInterface::asBinder(consumer)); data.writeInt32(controlledByApp); status_t result = remote()->transact(CONSUMER_CONNECT, data, &reply); if (result != NO_ERROR) { @@ -303,15 +156,15 @@ public: if (result != NO_ERROR) { return result; } - *slotMask = reply.readInt64(); + *slotMask = static_cast<uint64_t>(reply.readInt64()); return reply.readInt32(); } - virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) { + virtual status_t setDefaultBufferSize(uint32_t width, uint32_t height) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(w); - data.writeInt32(h); + data.writeUint32(width); + data.writeUint32(height); status_t result = remote()->transact(SET_DEFAULT_BUFFER_SIZE, data, &reply); if (result != NO_ERROR) { return result; @@ -358,10 +211,10 @@ public: remote()->transact(SET_CONSUMER_NAME, data, &reply); } - virtual status_t setDefaultBufferFormat(uint32_t defaultFormat) { + virtual status_t setDefaultBufferFormat(PixelFormat defaultFormat) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(defaultFormat); + data.writeInt32(static_cast<int32_t>(defaultFormat)); status_t result = remote()->transact(SET_DEFAULT_BUFFER_FORMAT, data, &reply); if (result != NO_ERROR) { return result; @@ -369,10 +222,23 @@ public: return reply.readInt32(); } + virtual status_t setDefaultBufferDataSpace( + android_dataspace defaultDataSpace) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInt32(static_cast<int32_t>(defaultDataSpace)); + status_t result = remote()->transact(SET_DEFAULT_BUFFER_DATA_SPACE, + data, &reply); + if (result != NO_ERROR) { + return result; + } + return reply.readInt32(); + } + virtual status_t setConsumerUsageBits(uint32_t usage) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(usage); + data.writeUint32(usage); status_t result = remote()->transact(SET_CONSUMER_USAGE_BITS, data, &reply); if (result != NO_ERROR) { return result; @@ -383,7 +249,7 @@ public: virtual status_t setTransformHint(uint32_t hint) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(hint); + data.writeUint32(hint); status_t result = remote()->transact(SET_TRANSFORM_HINT, data, &reply); if (result != NO_ERROR) { return result; @@ -415,6 +281,10 @@ public: } }; +// Out-of-line virtual method definition to trigger vtable emission in this +// translation unit (see clang warning -Wweak-vtables) +BpGraphicBufferConsumer::~BpGraphicBufferConsumer() {} + IMPLEMENT_META_INTERFACE(GraphicBufferConsumer, "android.gui.IGraphicBufferConsumer"); // ---------------------------------------------------------------------- @@ -427,19 +297,20 @@ status_t BnGraphicBufferConsumer::onTransact( CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); BufferItem item; int64_t presentWhen = data.readInt64(); - status_t result = acquireBuffer(&item, presentWhen); + uint64_t maxFrameNumber = data.readUint64(); + status_t result = acquireBuffer(&item, presentWhen, maxFrameNumber); status_t err = reply->write(item); if (err) return err; reply->writeInt32(result); return NO_ERROR; - } break; + } case DETACH_BUFFER: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); int slot = data.readInt32(); int result = detachBuffer(slot); reply->writeInt32(result); return NO_ERROR; - } break; + } case ATTACH_BUFFER: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); sp<GraphicBuffer> buffer = new GraphicBuffer(); @@ -449,11 +320,11 @@ status_t BnGraphicBufferConsumer::onTransact( reply->writeInt32(slot); reply->writeInt32(result); return NO_ERROR; - } break; + } case RELEASE_BUFFER: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); int buf = data.readInt32(); - uint64_t frameNumber = data.readInt64(); + uint64_t frameNumber = static_cast<uint64_t>(data.readInt64()); sp<Fence> releaseFence = new Fence(); status_t err = data.read(*releaseFence); if (err) return err; @@ -461,7 +332,7 @@ status_t BnGraphicBufferConsumer::onTransact( EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, releaseFence); reply->writeInt32(result); return NO_ERROR; - } break; + } case CONSUMER_CONNECT: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); sp<IConsumerListener> consumer = IConsumerListener::asInterface( data.readStrongBinder() ); @@ -469,75 +340,92 @@ status_t BnGraphicBufferConsumer::onTransact( status_t result = consumerConnect(consumer, controlledByApp); reply->writeInt32(result); return NO_ERROR; - } break; + } case CONSUMER_DISCONNECT: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); status_t result = consumerDisconnect(); reply->writeInt32(result); return NO_ERROR; - } break; + } case GET_RELEASED_BUFFERS: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); uint64_t slotMask = 0; status_t result = getReleasedBuffers(&slotMask); - reply->writeInt64(slotMask); + reply->writeInt64(static_cast<int64_t>(slotMask)); reply->writeInt32(result); return NO_ERROR; - } break; + } case SET_DEFAULT_BUFFER_SIZE: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); - uint32_t w = data.readInt32(); - uint32_t h = data.readInt32(); - status_t result = setDefaultBufferSize(w, h); + uint32_t width = data.readUint32(); + uint32_t height = data.readUint32(); + status_t result = setDefaultBufferSize(width, height); reply->writeInt32(result); return NO_ERROR; - } break; + } case SET_DEFAULT_MAX_BUFFER_COUNT: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); - uint32_t bufferCount = data.readInt32(); + int bufferCount = data.readInt32(); status_t result = setDefaultMaxBufferCount(bufferCount); reply->writeInt32(result); return NO_ERROR; - } break; + } case DISABLE_ASYNC_BUFFER: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); status_t result = disableAsyncBuffer(); reply->writeInt32(result); return NO_ERROR; - } break; + } case SET_MAX_ACQUIRED_BUFFER_COUNT: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); - uint32_t maxAcquiredBuffers = data.readInt32(); + int maxAcquiredBuffers = data.readInt32(); status_t result = setMaxAcquiredBufferCount(maxAcquiredBuffers); reply->writeInt32(result); return NO_ERROR; - } break; + } case SET_CONSUMER_NAME: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); setConsumerName( data.readString8() ); return NO_ERROR; - } break; + } case SET_DEFAULT_BUFFER_FORMAT: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); - uint32_t defaultFormat = data.readInt32(); + PixelFormat defaultFormat = static_cast<PixelFormat>(data.readInt32()); status_t result = setDefaultBufferFormat(defaultFormat); reply->writeInt32(result); return NO_ERROR; - } break; + } + case SET_DEFAULT_BUFFER_DATA_SPACE: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + android_dataspace defaultDataSpace = + static_cast<android_dataspace>(data.readInt32()); + status_t result = setDefaultBufferDataSpace(defaultDataSpace); + reply->writeInt32(result); + return NO_ERROR; + } case SET_CONSUMER_USAGE_BITS: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); - uint32_t usage = data.readInt32(); + uint32_t usage = data.readUint32(); status_t result = setConsumerUsageBits(usage); reply->writeInt32(result); return NO_ERROR; - } break; + } case SET_TRANSFORM_HINT: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); - uint32_t hint = data.readInt32(); + uint32_t hint = data.readUint32(); status_t result = setTransformHint(hint); reply->writeInt32(result); return NO_ERROR; - } break; + } + case GET_SIDEBAND_STREAM: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + sp<NativeHandle> stream = getSidebandStream(); + reply->writeInt32(static_cast<int32_t>(stream != NULL)); + if (stream != NULL) { + reply->writeNativeHandle(stream->handle()); + } + return NO_ERROR; + } case DUMP: { CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); String8 result = data.readString8(); diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index b5ec604a96..c3c62358fa 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -46,6 +46,9 @@ enum { DISCONNECT, SET_SIDEBAND_STREAM, ALLOCATE_BUFFERS, + ALLOW_ALLOCATION, + SET_GENERATION_NUMBER, + GET_CONSUMER_NAME, }; class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer> @@ -56,6 +59,8 @@ public: { } + virtual ~BpGraphicBufferProducer(); + virtual status_t requestBuffer(int bufferIdx, sp<GraphicBuffer>* buf) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); @@ -91,14 +96,15 @@ public: } virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, bool async, - uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { + uint32_t width, uint32_t height, PixelFormat format, + uint32_t usage) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); - data.writeInt32(async); - data.writeInt32(w); - data.writeInt32(h); - data.writeInt32(format); - data.writeInt32(usage); + data.writeInt32(static_cast<int32_t>(async)); + data.writeUint32(width); + data.writeUint32(height); + data.writeInt32(static_cast<int32_t>(format)); + data.writeUint32(usage); status_t result = remote()->transact(DEQUEUE_BUFFER, data, &reply); if (result != NO_ERROR) { return result; @@ -211,7 +217,7 @@ public: data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); if (listener != NULL) { data.writeInt32(1); - data.writeStrongBinder(listener->asBinder()); + data.writeStrongBinder(IInterface::asBinder(listener)); } else { data.writeInt32(0); } @@ -255,21 +261,59 @@ public: } virtual void allocateBuffers(bool async, uint32_t width, uint32_t height, - uint32_t format, uint32_t usage) { + PixelFormat format, uint32_t usage) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInt32(static_cast<int32_t>(async)); - data.writeInt32(static_cast<int32_t>(width)); - data.writeInt32(static_cast<int32_t>(height)); + data.writeUint32(width); + data.writeUint32(height); data.writeInt32(static_cast<int32_t>(format)); - data.writeInt32(static_cast<int32_t>(usage)); + data.writeUint32(usage); status_t result = remote()->transact(ALLOCATE_BUFFERS, data, &reply); if (result != NO_ERROR) { ALOGE("allocateBuffers failed to transact: %d", result); } } + + virtual status_t allowAllocation(bool allow) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); + data.writeInt32(static_cast<int32_t>(allow)); + status_t result = remote()->transact(ALLOW_ALLOCATION, data, &reply); + if (result != NO_ERROR) { + return result; + } + result = reply.readInt32(); + return result; + } + + virtual status_t setGenerationNumber(uint32_t generationNumber) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); + data.writeUint32(generationNumber); + status_t result = remote()->transact(SET_GENERATION_NUMBER, data, &reply); + if (result == NO_ERROR) { + result = reply.readInt32(); + } + return result; + } + + virtual String8 getConsumerName() const { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); + status_t result = remote()->transact(GET_CONSUMER_NAME, data, &reply); + if (result != NO_ERROR) { + ALOGE("getConsumerName failed to transact: %d", result); + return String8("TransactFailed"); + } + return reply.readString8(); + } }; +// Out-of-line virtual method definition to trigger vtable emission in this +// translation unit (see clang warning -Wweak-vtables) +BpGraphicBufferProducer::~BpGraphicBufferProducer() {} + IMPLEMENT_META_INTERFACE(GraphicBufferProducer, "android.gui.IGraphicBufferProducer"); // ---------------------------------------------------------------------- @@ -289,24 +333,25 @@ status_t BnGraphicBufferProducer::onTransact( } reply->writeInt32(result); return NO_ERROR; - } break; + } case SET_BUFFER_COUNT: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); int bufferCount = data.readInt32(); int result = setBufferCount(bufferCount); reply->writeInt32(result); return NO_ERROR; - } break; + } case DEQUEUE_BUFFER: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); - bool async = data.readInt32(); - uint32_t w = data.readInt32(); - uint32_t h = data.readInt32(); - uint32_t format = data.readInt32(); - uint32_t usage = data.readInt32(); + bool async = static_cast<bool>(data.readInt32()); + uint32_t width = data.readUint32(); + uint32_t height = data.readUint32(); + PixelFormat format = static_cast<PixelFormat>(data.readInt32()); + uint32_t usage = data.readUint32(); int buf = 0; sp<Fence> fence; - int result = dequeueBuffer(&buf, &fence, async, w, h, format, usage); + int result = dequeueBuffer(&buf, &fence, async, width, height, + format, usage); reply->writeInt32(buf); reply->writeInt32(fence != NULL); if (fence != NULL) { @@ -314,14 +359,14 @@ status_t BnGraphicBufferProducer::onTransact( } reply->writeInt32(result); return NO_ERROR; - } break; + } case DETACH_BUFFER: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); int slot = data.readInt32(); int result = detachBuffer(slot); reply->writeInt32(result); return NO_ERROR; - } break; + } case DETACH_NEXT_BUFFER: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); sp<GraphicBuffer> buffer; @@ -339,7 +384,7 @@ status_t BnGraphicBufferProducer::onTransact( } } return NO_ERROR; - } break; + } case ATTACH_BUFFER: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); sp<GraphicBuffer> buffer = new GraphicBuffer(); @@ -349,7 +394,7 @@ status_t BnGraphicBufferProducer::onTransact( reply->writeInt32(slot); reply->writeInt32(result); return NO_ERROR; - } break; + } case QUEUE_BUFFER: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); int buf = data.readInt32(); @@ -361,7 +406,7 @@ status_t BnGraphicBufferProducer::onTransact( status_t result = queueBuffer(buf, input, output); reply->writeInt32(result); return NO_ERROR; - } break; + } case CANCEL_BUFFER: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); int buf = data.readInt32(); @@ -369,7 +414,7 @@ status_t BnGraphicBufferProducer::onTransact( data.read(*fence.get()); cancelBuffer(buf, fence); return NO_ERROR; - } break; + } case QUERY: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); int value = 0; @@ -378,7 +423,7 @@ status_t BnGraphicBufferProducer::onTransact( reply->writeInt32(value); reply->writeInt32(res); return NO_ERROR; - } break; + } case CONNECT: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); sp<IProducerListener> listener; @@ -394,14 +439,14 @@ status_t BnGraphicBufferProducer::onTransact( status_t res = connect(listener, api, producerControlledByApp, output); reply->writeInt32(res); return NO_ERROR; - } break; + } case DISCONNECT: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); int api = data.readInt32(); status_t res = disconnect(api); reply->writeInt32(res); return NO_ERROR; - } break; + } case SET_SIDEBAND_STREAM: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); sp<NativeHandle> stream; @@ -411,16 +456,36 @@ status_t BnGraphicBufferProducer::onTransact( status_t result = setSidebandStream(stream); reply->writeInt32(result); return NO_ERROR; - } break; - case ALLOCATE_BUFFERS: + } + case ALLOCATE_BUFFERS: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); bool async = static_cast<bool>(data.readInt32()); - uint32_t width = static_cast<uint32_t>(data.readInt32()); - uint32_t height = static_cast<uint32_t>(data.readInt32()); - uint32_t format = static_cast<uint32_t>(data.readInt32()); - uint32_t usage = static_cast<uint32_t>(data.readInt32()); + uint32_t width = data.readUint32(); + uint32_t height = data.readUint32(); + PixelFormat format = static_cast<PixelFormat>(data.readInt32()); + uint32_t usage = data.readUint32(); allocateBuffers(async, width, height, format, usage); return NO_ERROR; + } + case ALLOW_ALLOCATION: { + CHECK_INTERFACE(IGraphicBufferProducer, data, reply); + bool allow = static_cast<bool>(data.readInt32()); + status_t result = allowAllocation(allow); + reply->writeInt32(result); + return NO_ERROR; + } + case SET_GENERATION_NUMBER: { + CHECK_INTERFACE(IGraphicBufferProducer, data, reply); + uint32_t generationNumber = data.readUint32(); + status_t result = setGenerationNumber(generationNumber); + reply->writeInt32(result); + return NO_ERROR; + } + case GET_CONSUMER_NAME: { + CHECK_INTERFACE(IGraphicBufferProducer, data, reply); + reply->writeString8(getConsumerName()); + return NO_ERROR; + } } return BBinder::onTransact(code, data, reply, flags); } @@ -434,12 +499,14 @@ IGraphicBufferProducer::QueueBufferInput::QueueBufferInput(const Parcel& parcel) size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const { return sizeof(timestamp) + sizeof(isAutoTimestamp) + + sizeof(dataSpace) + sizeof(crop) + sizeof(scalingMode) + sizeof(transform) + sizeof(stickyTransform) + sizeof(async) - + fence->getFlattenedSize(); + + fence->getFlattenedSize() + + surfaceDamage.getFlattenedSize(); } size_t IGraphicBufferProducer::QueueBufferInput::getFdCount() const { @@ -454,12 +521,17 @@ status_t IGraphicBufferProducer::QueueBufferInput::flatten( } FlattenableUtils::write(buffer, size, timestamp); FlattenableUtils::write(buffer, size, isAutoTimestamp); + FlattenableUtils::write(buffer, size, dataSpace); FlattenableUtils::write(buffer, size, crop); FlattenableUtils::write(buffer, size, scalingMode); FlattenableUtils::write(buffer, size, transform); FlattenableUtils::write(buffer, size, stickyTransform); FlattenableUtils::write(buffer, size, async); - return fence->flatten(buffer, size, fds, count); + status_t result = fence->flatten(buffer, size, fds, count); + if (result != NO_ERROR) { + return result; + } + return surfaceDamage.flatten(buffer, size); } status_t IGraphicBufferProducer::QueueBufferInput::unflatten( @@ -468,6 +540,7 @@ status_t IGraphicBufferProducer::QueueBufferInput::unflatten( size_t minNeeded = sizeof(timestamp) + sizeof(isAutoTimestamp) + + sizeof(dataSpace) + sizeof(crop) + sizeof(scalingMode) + sizeof(transform) @@ -480,6 +553,7 @@ status_t IGraphicBufferProducer::QueueBufferInput::unflatten( FlattenableUtils::read(buffer, size, timestamp); FlattenableUtils::read(buffer, size, isAutoTimestamp); + FlattenableUtils::read(buffer, size, dataSpace); FlattenableUtils::read(buffer, size, crop); FlattenableUtils::read(buffer, size, scalingMode); FlattenableUtils::read(buffer, size, transform); @@ -487,7 +561,11 @@ status_t IGraphicBufferProducer::QueueBufferInput::unflatten( FlattenableUtils::read(buffer, size, async); fence = new Fence(); - return fence->unflatten(buffer, size, fds, count); + status_t result = fence->unflatten(buffer, size, fds, count); + if (result != NO_ERROR) { + return result; + } + return surfaceDamage.unflatten(buffer, size); } }; // namespace android diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp index efe4069e28..81adc95449 100644 --- a/libs/gui/IProducerListener.cpp +++ b/libs/gui/IProducerListener.cpp @@ -30,6 +30,8 @@ public: BpProducerListener(const sp<IBinder>& impl) : BpInterface<IProducerListener>(impl) {} + virtual ~BpProducerListener(); + virtual void onBufferReleased() { Parcel data, reply; data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor()); @@ -37,6 +39,10 @@ public: } }; +// Out-of-line virtual method definition to trigger vtable emission in this +// translation unit (see clang warning -Wweak-vtables) +BpProducerListener::~BpProducerListener() {} + IMPLEMENT_META_INTERFACE(ProducerListener, "android.gui.IProducerListener") status_t BnProducerListener::onTransact(uint32_t code, const Parcel& data, diff --git a/libs/gui/ISensorEventConnection.cpp b/libs/gui/ISensorEventConnection.cpp index 28fcb53d8f..dc7a35cef9 100644 --- a/libs/gui/ISensorEventConnection.cpp +++ b/libs/gui/ISensorEventConnection.cpp @@ -45,6 +45,8 @@ public: { } + virtual ~BpSensorEventConnection(); + virtual sp<BitTube> getSensorChannel() const { Parcel data, reply; @@ -85,6 +87,10 @@ public: } }; +// Out-of-line virtual method definition to trigger vtable emission in this +// translation unit (see clang warning -Wweak-vtables) +BpSensorEventConnection::~BpSensorEventConnection() {} + IMPLEMENT_META_INTERFACE(SensorEventConnection, "android.gui.SensorEventConnection"); // ---------------------------------------------------------------------------- @@ -98,7 +104,7 @@ status_t BnSensorEventConnection::onTransact( sp<BitTube> channel(getSensorChannel()); channel->writeToParcel(reply); return NO_ERROR; - } break; + } case ENABLE_DISABLE: { CHECK_INTERFACE(ISensorEventConnection, data, reply); int handle = data.readInt32(); @@ -110,21 +116,21 @@ status_t BnSensorEventConnection::onTransact( maxBatchReportLatencyNs, reservedFlags); reply->writeInt32(result); return NO_ERROR; - } break; + } case SET_EVENT_RATE: { CHECK_INTERFACE(ISensorEventConnection, data, reply); int handle = data.readInt32(); - int ns = data.readInt64(); + nsecs_t ns = data.readInt64(); status_t result = setEventRate(handle, ns); reply->writeInt32(result); return NO_ERROR; - } break; + } case FLUSH_SENSOR: { CHECK_INTERFACE(ISensorEventConnection, data, reply); status_t result = flush(); reply->writeInt32(result); return NO_ERROR; - } break; + } } return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/ISensorServer.cpp b/libs/gui/ISensorServer.cpp index 0b76f3788c..f581b5c1d4 100644 --- a/libs/gui/ISensorServer.cpp +++ b/libs/gui/ISensorServer.cpp @@ -35,6 +35,7 @@ namespace android { enum { GET_SENSOR_LIST = IBinder::FIRST_CALL_TRANSACTION, CREATE_SENSOR_EVENT_CONNECTION, + ENABLE_DATA_INJECTION }; class BpSensorServer : public BpInterface<ISensorServer> @@ -45,14 +46,17 @@ public: { } - virtual Vector<Sensor> getSensorList() + virtual ~BpSensorServer(); + + virtual Vector<Sensor> getSensorList(const String16& opPackageName) { Parcel data, reply; data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor()); + data.writeString16(opPackageName); remote()->transact(GET_SENSOR_LIST, data, &reply); Sensor s; Vector<Sensor> v; - int32_t n = reply.readInt32(); + uint32_t n = reply.readUint32(); v.setCapacity(n); while (n--) { reply.read(s); @@ -61,15 +65,30 @@ public: return v; } - virtual sp<ISensorEventConnection> createSensorEventConnection() + virtual sp<ISensorEventConnection> createSensorEventConnection(const String8& packageName, + int mode, const String16& opPackageName) { Parcel data, reply; data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor()); + data.writeString8(packageName); + data.writeInt32(mode); + data.writeString16(opPackageName); remote()->transact(CREATE_SENSOR_EVENT_CONNECTION, data, &reply); return interface_cast<ISensorEventConnection>(reply.readStrongBinder()); } + + virtual int isDataInjectionEnabled() { + Parcel data, reply; + data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor()); + remote()->transact(ENABLE_DATA_INJECTION, data, &reply); + return reply.readInt32(); + } }; +// Out-of-line virtual method definition to trigger vtable emission in this +// translation unit (see clang warning -Wweak-vtables) +BpSensorServer::~BpSensorServer() {} + IMPLEMENT_META_INTERFACE(SensorServer, "android.gui.SensorServer"); // ---------------------------------------------------------------------- @@ -80,20 +99,31 @@ status_t BnSensorServer::onTransact( switch(code) { case GET_SENSOR_LIST: { CHECK_INTERFACE(ISensorServer, data, reply); - Vector<Sensor> v(getSensorList()); + const String16& opPackageName = data.readString16(); + Vector<Sensor> v(getSensorList(opPackageName)); size_t n = v.size(); - reply->writeInt32(n); - for (size_t i=0 ; i<n ; i++) { + reply->writeUint32(static_cast<uint32_t>(n)); + for (size_t i = 0; i < n; i++) { reply->write(v[i]); } return NO_ERROR; - } break; + } case CREATE_SENSOR_EVENT_CONNECTION: { CHECK_INTERFACE(ISensorServer, data, reply); - sp<ISensorEventConnection> connection(createSensorEventConnection()); - reply->writeStrongBinder(connection->asBinder()); + String8 packageName = data.readString8(); + int32_t mode = data.readInt32(); + const String16& opPackageName = data.readString16(); + sp<ISensorEventConnection> connection(createSensorEventConnection(packageName, mode, + opPackageName)); + reply->writeStrongBinder(IInterface::asBinder(connection)); return NO_ERROR; - } break; + } + case ENABLE_DATA_INJECTION: { + CHECK_INTERFACE(ISensorServer, data, reply); + int32_t ret = isDataInjectionEnabled(); + reply->writeInt32(static_cast<int32_t>(ret)); + return NO_ERROR; + } } return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index ebb687a28a..78886d5bb6 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -51,9 +51,10 @@ public: { } + virtual ~BpSurfaceComposer(); + virtual sp<ISurfaceComposerClient> createConnection() { - uint32_t n; Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); remote()->transact(BnSurfaceComposer::CREATE_CONNECTION, data, &reply); @@ -62,7 +63,6 @@ public: virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc() { - uint32_t n; Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); remote()->transact(BnSurfaceComposer::CREATE_GRAPHIC_BUFFER_ALLOC, data, &reply); @@ -76,23 +76,18 @@ public: { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - { - Vector<ComposerState>::const_iterator b(state.begin()); - Vector<ComposerState>::const_iterator e(state.end()); - data.writeInt32(state.size()); - for ( ; b != e ; ++b ) { - b->write(data); - } + + data.writeUint32(static_cast<uint32_t>(state.size())); + for (const auto& s : state) { + s.write(data); } - { - Vector<DisplayState>::const_iterator b(displays.begin()); - Vector<DisplayState>::const_iterator e(displays.end()); - data.writeInt32(displays.size()); - for ( ; b != e ; ++b ) { - b->write(data); - } + + data.writeUint32(static_cast<uint32_t>(displays.size())); + for (const auto& d : displays) { + d.write(data); } - data.writeInt32(flags); + + data.writeUint32(flags); remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply); } @@ -113,12 +108,12 @@ public: Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); - data.writeStrongBinder(producer->asBinder()); + data.writeStrongBinder(IInterface::asBinder(producer)); data.write(sourceCrop); - data.writeInt32(reqWidth); - data.writeInt32(reqHeight); - data.writeInt32(minLayerZ); - data.writeInt32(maxLayerZ); + data.writeUint32(reqWidth); + data.writeUint32(reqHeight); + data.writeUint32(minLayerZ); + data.writeUint32(maxLayerZ); data.writeInt32(static_cast<int32_t>(useIdentityTransform)); data.writeInt32(static_cast<int32_t>(rotation)); remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply); @@ -137,7 +132,7 @@ public: "interface descriptor: %s (%d)", strerror(-err), -err); return false; } - err = data.writeStrongBinder(bufferProducer->asBinder()); + err = data.writeStrongBinder(IInterface::asBinder(bufferProducer)); if (err != NO_ERROR) { ALOGE("ISurfaceComposer::authenticateSurfaceTexture: error writing " "strong binder to parcel: %s (%d)", strerror(-err), -err); @@ -226,7 +221,7 @@ public: remote()->transact(BnSurfaceComposer::GET_DISPLAY_CONFIGS, data, &reply); status_t result = reply.readInt32(); if (result == NO_ERROR) { - size_t numConfigs = static_cast<size_t>(reply.readInt32()); + size_t numConfigs = reply.readUint32(); configs->clear(); configs->resize(numConfigs); for (size_t c = 0; c < numConfigs; ++c) { @@ -289,6 +284,10 @@ public: } }; +// Out-of-line virtual method definition to trigger vtable emission in this +// translation unit (see clang warning -Wweak-vtables) +BpSurfaceComposer::~BpSurfaceComposer() {} + IMPLEMENT_META_INTERFACE(SurfaceComposer, "android.ui.ISurfaceComposer"); // ---------------------------------------------------------------------- @@ -299,46 +298,49 @@ status_t BnSurfaceComposer::onTransact( switch(code) { case CREATE_CONNECTION: { CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IBinder> b = createConnection()->asBinder(); + sp<IBinder> b = IInterface::asBinder(createConnection()); reply->writeStrongBinder(b); return NO_ERROR; } case CREATE_GRAPHIC_BUFFER_ALLOC: { CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IBinder> b = createGraphicBufferAlloc()->asBinder(); + sp<IBinder> b = IInterface::asBinder(createGraphicBufferAlloc()); reply->writeStrongBinder(b); return NO_ERROR; } case SET_TRANSACTION_STATE: { CHECK_INTERFACE(ISurfaceComposer, data, reply); - size_t count = data.readInt32(); + + size_t count = data.readUint32(); if (count > data.dataSize()) { return BAD_VALUE; } ComposerState s; Vector<ComposerState> state; state.setCapacity(count); - for (size_t i=0 ; i<count ; i++) { + for (size_t i = 0; i < count; i++) { if (s.read(data) == BAD_VALUE) { return BAD_VALUE; } state.add(s); } - count = data.readInt32(); + + count = data.readUint32(); if (count > data.dataSize()) { return BAD_VALUE; } DisplayState d; Vector<DisplayState> displays; displays.setCapacity(count); - for (size_t i=0 ; i<count ; i++) { + for (size_t i = 0; i < count; i++) { if (d.read(data) == BAD_VALUE) { return BAD_VALUE; } displays.add(d); } - uint32_t flags = data.readInt32(); - setTransactionState(state, displays, flags); + + uint32_t stateFlags = data.readUint32(); + setTransactionState(state, displays, stateFlags); return NO_ERROR; } case BOOT_FINISHED: { @@ -353,12 +355,12 @@ status_t BnSurfaceComposer::onTransact( interface_cast<IGraphicBufferProducer>(data.readStrongBinder()); Rect sourceCrop; data.read(sourceCrop); - uint32_t reqWidth = data.readInt32(); - uint32_t reqHeight = data.readInt32(); - uint32_t minLayerZ = data.readInt32(); - uint32_t maxLayerZ = data.readInt32(); + uint32_t reqWidth = data.readUint32(); + uint32_t reqHeight = data.readUint32(); + uint32_t minLayerZ = data.readUint32(); + uint32_t maxLayerZ = data.readUint32(); bool useIdentityTransform = static_cast<bool>(data.readInt32()); - uint32_t rotation = data.readInt32(); + int32_t rotation = data.readInt32(); status_t res = captureScreen(display, producer, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, @@ -378,7 +380,7 @@ status_t BnSurfaceComposer::onTransact( case CREATE_DISPLAY_EVENT_CONNECTION: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp<IDisplayEventConnection> connection(createDisplayEventConnection()); - reply->writeStrongBinder(connection->asBinder()); + reply->writeStrongBinder(IInterface::asBinder(connection)); return NO_ERROR; } case CREATE_DISPLAY: { @@ -409,7 +411,7 @@ status_t BnSurfaceComposer::onTransact( status_t result = getDisplayConfigs(display, &configs); reply->writeInt32(result); if (result == NO_ERROR) { - reply->writeInt32(static_cast<int32_t>(configs.size())); + reply->writeUint32(static_cast<uint32_t>(configs.size())); for (size_t c = 0; c < configs.size(); ++c) { memcpy(reply->writeInplace(sizeof(DisplayInfo)), &configs[c], sizeof(DisplayInfo)); @@ -469,8 +471,6 @@ status_t BnSurfaceComposer::onTransact( return BBinder::onTransact(code, data, reply, flags); } } - // should be unreachable - return NO_ERROR; } // ---------------------------------------------------------------------------- diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp index 3da6423f42..2ecb9083ff 100644 --- a/libs/gui/ISurfaceComposerClient.cpp +++ b/libs/gui/ISurfaceComposerClient.cpp @@ -51,17 +51,19 @@ public: : BpInterface<ISurfaceComposerClient>(impl) { } - virtual status_t createSurface(const String8& name, uint32_t w, - uint32_t h, PixelFormat format, uint32_t flags, + virtual ~BpSurfaceComposerClient(); + + virtual status_t createSurface(const String8& name, uint32_t width, + uint32_t height, PixelFormat format, uint32_t flags, sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor()); data.writeString8(name); - data.writeInt32(w); - data.writeInt32(h); - data.writeInt32(format); - data.writeInt32(flags); + data.writeUint32(width); + data.writeUint32(height); + data.writeInt32(static_cast<int32_t>(format)); + data.writeUint32(flags); remote()->transact(CREATE_SURFACE, data, &reply); *handle = reply.readStrongBinder(); *gbp = interface_cast<IGraphicBufferProducer>(reply.readStrongBinder()); @@ -94,6 +96,10 @@ public: } }; +// Out-of-line virtual method definition to trigger vtable emission in this +// translation unit (see clang warning -Wweak-vtables) +BpSurfaceComposerClient::~BpSurfaceComposerClient() {} + IMPLEMENT_META_INTERFACE(SurfaceComposerClient, "android.ui.ISurfaceComposerClient"); // ---------------------------------------------------------------------- @@ -105,31 +111,31 @@ status_t BnSurfaceComposerClient::onTransact( case CREATE_SURFACE: { CHECK_INTERFACE(ISurfaceComposerClient, data, reply); String8 name = data.readString8(); - uint32_t w = data.readInt32(); - uint32_t h = data.readInt32(); - PixelFormat format = data.readInt32(); - uint32_t flags = data.readInt32(); + uint32_t width = data.readUint32(); + uint32_t height = data.readUint32(); + PixelFormat format = static_cast<PixelFormat>(data.readInt32()); + uint32_t createFlags = data.readUint32(); sp<IBinder> handle; sp<IGraphicBufferProducer> gbp; - status_t result = createSurface(name, w, h, format, flags, - &handle, &gbp); + status_t result = createSurface(name, width, height, format, + createFlags, &handle, &gbp); reply->writeStrongBinder(handle); - reply->writeStrongBinder(gbp->asBinder()); + reply->writeStrongBinder(IInterface::asBinder(gbp)); reply->writeInt32(result); return NO_ERROR; - } break; + } case DESTROY_SURFACE: { CHECK_INTERFACE(ISurfaceComposerClient, data, reply); reply->writeInt32(destroySurface( data.readStrongBinder() ) ); return NO_ERROR; - } break; + } case CLEAR_LAYER_FRAME_STATS: { CHECK_INTERFACE(ISurfaceComposerClient, data, reply); sp<IBinder> handle = data.readStrongBinder(); status_t result = clearLayerFrameStats(handle); reply->writeInt32(result); return NO_ERROR; - } break; + } case GET_LAYER_FRAME_STATS: { CHECK_INTERFACE(ISurfaceComposerClient, data, reply); sp<IBinder> handle = data.readStrongBinder(); @@ -138,7 +144,7 @@ status_t BnSurfaceComposerClient::onTransact( reply->write(stats); reply->writeInt32(result); return NO_ERROR; - } break; + } default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 1183d59215..00323dc4f2 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -25,16 +25,16 @@ namespace android { status_t layer_state_t::write(Parcel& output) const { output.writeStrongBinder(surface); - output.writeInt32(what); + output.writeUint32(what); output.writeFloat(x); output.writeFloat(y); - output.writeInt32(z); - output.writeInt32(w); - output.writeInt32(h); - output.writeInt32(layerStack); + output.writeUint32(z); + output.writeUint32(w); + output.writeUint32(h); + output.writeUint32(layerStack); output.writeFloat(alpha); - output.writeInt32(flags); - output.writeInt32(mask); + output.writeUint32(flags); + output.writeUint32(mask); *reinterpret_cast<layer_state_t::matrix22_t *>( output.writeInplace(sizeof(layer_state_t::matrix22_t))) = matrix; output.write(crop); @@ -45,16 +45,16 @@ status_t layer_state_t::write(Parcel& output) const status_t layer_state_t::read(const Parcel& input) { surface = input.readStrongBinder(); - what = input.readInt32(); + what = input.readUint32(); x = input.readFloat(); y = input.readFloat(); - z = input.readInt32(); - w = input.readInt32(); - h = input.readInt32(); - layerStack = input.readInt32(); + z = input.readUint32(); + w = input.readUint32(); + h = input.readUint32(); + layerStack = input.readUint32(); alpha = input.readFloat(); - flags = input.readInt32(); - mask = input.readInt32(); + flags = static_cast<uint8_t>(input.readUint32()); + mask = static_cast<uint8_t>(input.readUint32()); const void* matrix_data = input.readInplace(sizeof(layer_state_t::matrix22_t)); if (matrix_data) { matrix = *reinterpret_cast<layer_state_t::matrix22_t const *>(matrix_data); @@ -67,7 +67,7 @@ status_t layer_state_t::read(const Parcel& input) } status_t ComposerState::write(Parcel& output) const { - output.writeStrongBinder(client->asBinder()); + output.writeStrongBinder(IInterface::asBinder(client)); return state.write(output); } @@ -79,27 +79,27 @@ status_t ComposerState::read(const Parcel& input) { status_t DisplayState::write(Parcel& output) const { output.writeStrongBinder(token); - output.writeStrongBinder(surface->asBinder()); - output.writeInt32(what); - output.writeInt32(layerStack); - output.writeInt32(orientation); + output.writeStrongBinder(IInterface::asBinder(surface)); + output.writeUint32(what); + output.writeUint32(layerStack); + output.writeUint32(orientation); output.write(viewport); output.write(frame); - output.writeInt32(width); - output.writeInt32(height); + output.writeUint32(width); + output.writeUint32(height); return NO_ERROR; } status_t DisplayState::read(const Parcel& input) { token = input.readStrongBinder(); surface = interface_cast<IGraphicBufferProducer>(input.readStrongBinder()); - what = input.readInt32(); - layerStack = input.readInt32(); - orientation = input.readInt32(); + what = input.readUint32(); + layerStack = input.readUint32(); + orientation = input.readUint32(); input.read(viewport); input.read(frame); - width = input.readInt32(); - height = input.readInt32(); + width = input.readUint32(); + height = input.readUint32(); return NO_ERROR; } diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp index b4291bb7ca..4b3603ee12 100644 --- a/libs/gui/Sensor.cpp +++ b/libs/gui/Sensor.cpp @@ -25,6 +25,9 @@ #include <hardware/sensors.h> +#include <binder/AppOpsManager.h> +#include <binder/IServiceManager.h> + #include <gui/Sensor.h> #include <log/log.h> @@ -72,7 +75,7 @@ Sensor::Sensor(struct sensor_t const* hwSensor, int halVersion) static_cast<int64_t>(hwSensor->maxDelay)); mMaxDelay = INT_MAX; } else { - mMaxDelay = (int32_t) hwSensor->maxDelay; + mMaxDelay = static_cast<int32_t>(hwSensor->maxDelay); } } else { // For older hals set maxDelay to 0. @@ -113,11 +116,13 @@ Sensor::Sensor(struct sensor_t const* hwSensor, int halVersion) mStringType = SENSOR_STRING_TYPE_GYROSCOPE_UNCALIBRATED; mFlags |= SENSOR_FLAG_CONTINUOUS_MODE; break; - case SENSOR_TYPE_HEART_RATE: + case SENSOR_TYPE_HEART_RATE: { mStringType = SENSOR_STRING_TYPE_HEART_RATE; mRequiredPermission = SENSOR_PERMISSION_BODY_SENSORS; + AppOpsManager appOps; + mRequiredAppOp = appOps.permissionToOpCode(String16(SENSOR_PERMISSION_BODY_SENSORS)); mFlags |= SENSOR_FLAG_ON_CHANGE_MODE; - break; + } break; case SENSOR_TYPE_LIGHT: mStringType = SENSOR_STRING_TYPE_LIGHT; mFlags |= SENSOR_FLAG_ON_CHANGE_MODE; @@ -204,6 +209,13 @@ Sensor::Sensor(struct sensor_t const* hwSensor, int halVersion) mFlags |= SENSOR_FLAG_WAKE_UP; } break; + case SENSOR_TYPE_WRIST_TILT_GESTURE: + mStringType = SENSOR_STRING_TYPE_WRIST_TILT_GESTURE; + mFlags |= SENSOR_FLAG_SPECIAL_REPORTING_MODE; + if (halVersion < SENSORS_DEVICE_API_VERSION_1_3) { + mFlags |= SENSOR_FLAG_WAKE_UP; + } + break; default: // Only pipe the stringType, requiredPermission and flags for custom sensors. if (halVersion > SENSORS_DEVICE_API_VERSION_1_0 && hwSensor->stringType) { @@ -211,10 +223,14 @@ Sensor::Sensor(struct sensor_t const* hwSensor, int halVersion) } if (halVersion > SENSORS_DEVICE_API_VERSION_1_0 && hwSensor->requiredPermission) { mRequiredPermission = hwSensor->requiredPermission; + if (!strcmp(mRequiredPermission, SENSOR_PERMISSION_BODY_SENSORS)) { + AppOpsManager appOps; + mRequiredAppOp = appOps.permissionToOpCode(String16(SENSOR_PERMISSION_BODY_SENSORS)); + } } if (halVersion >= SENSORS_DEVICE_API_VERSION_1_3) { - mFlags = (int32_t) hwSensor->flags; + mFlags = static_cast<uint32_t>(hwSensor->flags); } else { // This is an OEM defined sensor on an older HAL. Use minDelay to determine the // reporting mode of the sensor. @@ -245,6 +261,17 @@ Sensor::Sensor(struct sensor_t const* hwSensor, int halVersion) } } + + if (mRequiredPermission.length() > 0) { + // If the sensor is protected by a permission we need to know if it is + // a runtime one to determine whether we can use the permission cache. + sp<IBinder> binder = defaultServiceManager()->getService(String16("permission")); + if (binder != 0) { + sp<IPermissionController> permCtrl = interface_cast<IPermissionController>(binder); + mRequiredPermissionRuntime = permCtrl->isRuntimePermission( + String16(mRequiredPermission)); + } + } } Sensor::~Sensor() @@ -295,11 +322,11 @@ int32_t Sensor::getVersion() const { return mVersion; } -int32_t Sensor::getFifoReservedEventCount() const { +uint32_t Sensor::getFifoReservedEventCount() const { return mFifoReservedEventCount; } -int32_t Sensor::getFifoMaxEventCount() const { +uint32_t Sensor::getFifoMaxEventCount() const { return mFifoMaxEventCount; } @@ -311,11 +338,19 @@ const String8& Sensor::getRequiredPermission() const { return mRequiredPermission; } +bool Sensor::isRequiredPermissionRuntime() const { + return mRequiredPermissionRuntime; +} + +int32_t Sensor::getRequiredAppOp() const { + return mRequiredAppOp; +} + int32_t Sensor::getMaxDelay() const { return mMaxDelay; } -int32_t Sensor::getFlags() const { +uint32_t Sensor::getFlags() const { return mFlags; } @@ -332,7 +367,8 @@ size_t Sensor::getFlattenedSize() const size_t fixedSize = sizeof(int32_t) * 3 + sizeof(float) * 4 + - sizeof(int32_t) * 5; + sizeof(int32_t) * 6 + + sizeof(bool); size_t variableSize = sizeof(uint32_t) + FlattenableUtils::align<4>(mName.length()) + @@ -362,6 +398,8 @@ status_t Sensor::flatten(void* buffer, size_t size) const { FlattenableUtils::write(buffer, size, mFifoMaxEventCount); flattenString8(buffer, size, mStringType); flattenString8(buffer, size, mRequiredPermission); + FlattenableUtils::write(buffer, size, mRequiredPermissionRuntime); + FlattenableUtils::write(buffer, size, mRequiredAppOp); FlattenableUtils::write(buffer, size, mMaxDelay); FlattenableUtils::write(buffer, size, mFlags); return NO_ERROR; @@ -400,6 +438,8 @@ status_t Sensor::unflatten(void const* buffer, size_t size) { if (!unflattenString8(buffer, size, mRequiredPermission)) { return NO_MEMORY; } + FlattenableUtils::read(buffer, size, mRequiredPermissionRuntime); + FlattenableUtils::read(buffer, size, mRequiredAppOp); FlattenableUtils::read(buffer, size, mMaxDelay); FlattenableUtils::read(buffer, size, mFlags); return NO_ERROR; @@ -407,7 +447,7 @@ status_t Sensor::unflatten(void const* buffer, size_t size) { void Sensor::flattenString8(void*& buffer, size_t& size, const String8& string8) { - uint32_t len = string8.length(); + uint32_t len = static_cast<uint32_t>(string8.length()); FlattenableUtils::write(buffer, size, len); memcpy(static_cast<char*>(buffer), string8.string(), len); FlattenableUtils::advance(buffer, size, FlattenableUtils::align<4>(len)); diff --git a/libs/gui/SensorEventQueue.cpp b/libs/gui/SensorEventQueue.cpp index 1305e9f63a..4b7986e1d2 100644 --- a/libs/gui/SensorEventQueue.cpp +++ b/libs/gui/SensorEventQueue.cpp @@ -16,9 +16,11 @@ #define LOG_TAG "Sensors" +#include <algorithm> #include <stdint.h> #include <sys/types.h> #include <sys/socket.h> +#include <linux/errno.h> #include <utils/Errors.h> #include <utils/RefBase.h> @@ -31,6 +33,8 @@ #include <android/sensor.h> +using std::min; + // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- @@ -68,14 +72,14 @@ ssize_t SensorEventQueue::read(ASensorEvent* events, size_t numEvents) { if (err < 0) { return err; } - mAvailable = err; + mAvailable = static_cast<size_t>(err); mConsumed = 0; } - size_t count = numEvents < mAvailable ? numEvents : mAvailable; - memcpy(events, mRecBuffer + mConsumed, count*sizeof(ASensorEvent)); + size_t count = min(numEvents, mAvailable); + memcpy(events, mRecBuffer + mConsumed, count * sizeof(ASensorEvent)); mAvailable -= count; mConsumed += count; - return count; + return static_cast<ssize_t>(count); } sp<Looper> SensorEventQueue::getLooper() const @@ -146,6 +150,23 @@ status_t SensorEventQueue::setEventRate(Sensor const* sensor, nsecs_t ns) const return mSensorEventConnection->setEventRate(sensor->getHandle(), ns); } +status_t SensorEventQueue::injectSensorEvent(const ASensorEvent& event) { + do { + // Blocking call. + ssize_t size = ::send(mSensorChannel->getFd(), &event, sizeof(event), MSG_NOSIGNAL); + if (size >= 0) { + return NO_ERROR; + } else if (size < 0 && errno == EAGAIN) { + // If send is returning a "Try again" error, sleep for 100ms and try again. In all + // other cases log a failure and exit. + usleep(100000); + } else { + ALOGE("injectSensorEvent failure %s %zd", strerror(errno), size); + return INVALID_OPERATION; + } + } while (true); +} + void SensorEventQueue::sendAck(const ASensorEvent* events, int count) { for (int i = 0; i < count; ++i) { if (events[i].flags & WAKE_UP_SENSOR_EVENT_NEEDS_ACK) { @@ -157,7 +178,7 @@ void SensorEventQueue::sendAck(const ASensorEvent* events, int count) { ssize_t size = ::send(mSensorChannel->getFd(), &mNumAcksToSend, sizeof(mNumAcksToSend), MSG_DONTWAIT | MSG_NOSIGNAL); if (size < 0) { - ALOGE("sendAck failure %d %d", size, mNumAcksToSend); + ALOGE("sendAck failure %zd %d", size, mNumAcksToSend); } else { mNumAcksToSend = 0; } diff --git a/libs/gui/SensorManager.cpp b/libs/gui/SensorManager.cpp index 7b4fa2f560..dd3778137a 100644 --- a/libs/gui/SensorManager.cpp +++ b/libs/gui/SensorManager.cpp @@ -36,10 +36,8 @@ namespace android { // ---------------------------------------------------------------------------- -ANDROID_SINGLETON_STATIC_INSTANCE(SensorManager) - -SensorManager::SensorManager() - : mSensorList(0) +SensorManager::SensorManager(const String16& opPackageName) + : mSensorList(0), mOpPackageName(opPackageName) { // okay we're not locked here, but it's not needed during construction assertStateLocked(); @@ -86,11 +84,12 @@ status_t SensorManager::assertStateLocked() const { }; mDeathObserver = new DeathObserver(*const_cast<SensorManager *>(this)); - mSensorServer->asBinder()->linkToDeath(mDeathObserver); + IInterface::asBinder(mSensorServer)->linkToDeath(mDeathObserver); - mSensors = mSensorServer->getSensorList(); + mSensors = mSensorServer->getSensorList(mOpPackageName); size_t count = mSensors.size(); - mSensorList = (Sensor const**)malloc(count * sizeof(Sensor*)); + mSensorList = + static_cast<Sensor const**>(malloc(count * sizeof(Sensor*))); for (size_t i=0 ; i<count ; i++) { mSensorList[i] = mSensors.array() + i; } @@ -99,17 +98,15 @@ status_t SensorManager::assertStateLocked() const { return NO_ERROR; } - - ssize_t SensorManager::getSensorList(Sensor const* const** list) const { Mutex::Autolock _l(mLock); status_t err = assertStateLocked(); if (err < 0) { - return ssize_t(err); + return static_cast<ssize_t>(err); } *list = mSensorList; - return mSensors.size(); + return static_cast<ssize_t>(mSensors.size()); } Sensor const* SensorManager::getDefaultSensor(int type) @@ -138,18 +135,17 @@ Sensor const* SensorManager::getDefaultSensor(int type) return NULL; } -sp<SensorEventQueue> SensorManager::createEventQueue() -{ +sp<SensorEventQueue> SensorManager::createEventQueue(String8 packageName, int mode) { sp<SensorEventQueue> queue; Mutex::Autolock _l(mLock); while (assertStateLocked() == NO_ERROR) { sp<ISensorEventConnection> connection = - mSensorServer->createSensorEventConnection(); + mSensorServer->createSensorEventConnection(packageName, mode, mOpPackageName); if (connection == NULL) { - // SensorService just died. - ALOGE("createEventQueue: connection is NULL. SensorService died."); - continue; + // SensorService just died or the app doesn't have required permissions. + ALOGE("createEventQueue: connection is NULL."); + return NULL; } queue = new SensorEventQueue(connection); break; @@ -157,5 +153,13 @@ sp<SensorEventQueue> SensorManager::createEventQueue() return queue; } +bool SensorManager::isDataInjectionEnabled() { + Mutex::Autolock _l(mLock); + if (assertStateLocked() == NO_ERROR) { + return mSensorServer->isDataInjectionEnabled(); + } + return false; +} + // ---------------------------------------------------------------------------- }; // namespace android diff --git a/libs/gui/StreamSplitter.cpp b/libs/gui/StreamSplitter.cpp index 5f39905e5e..43f9214fc7 100644 --- a/libs/gui/StreamSplitter.cpp +++ b/libs/gui/StreamSplitter.cpp @@ -20,6 +20,7 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 +#include <gui/BufferItem.h> #include <gui/IGraphicBufferConsumer.h> #include <gui/IGraphicBufferProducer.h> #include <gui/StreamSplitter.h> @@ -80,7 +81,7 @@ status_t StreamSplitter::addOutput( IGraphicBufferProducer::QueueBufferOutput queueBufferOutput; sp<OutputListener> listener(new OutputListener(this, outputQueue)); - outputQueue->asBinder()->linkToDeath(listener); + IInterface::asBinder(outputQueue)->linkToDeath(listener); status_t status = outputQueue->connect(listener, NATIVE_WINDOW_API_CPU, /* producerControlledByApp */ false, &queueBufferOutput); if (status != NO_ERROR) { @@ -123,7 +124,7 @@ void StreamSplitter::onFrameAvailable(const BufferItem& /* item */) { ++mOutstandingBuffers; // Acquire and detach the buffer from the input - IGraphicBufferConsumer::BufferItem bufferItem; + BufferItem bufferItem; status_t status = mInput->acquireBuffer(&bufferItem, /* presentWhen */ 0); LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "acquiring buffer from input failed (%d)", status); @@ -141,7 +142,8 @@ void StreamSplitter::onFrameAvailable(const BufferItem& /* item */) { IGraphicBufferProducer::QueueBufferInput queueInput( bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp, - bufferItem.mCrop, bufferItem.mScalingMode, + bufferItem.mDataSpace, bufferItem.mCrop, + static_cast<int32_t>(bufferItem.mScalingMode), bufferItem.mTransform, bufferItem.mIsDroppable, bufferItem.mFence); diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 0e2baa28fd..4b76f9834c 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -27,6 +27,7 @@ #include <utils/NativeHandle.h> #include <ui/Fence.h> +#include <ui/Region.h> #include <gui/IProducerListener.h> #include <gui/ISurfaceComposer.h> @@ -41,7 +42,8 @@ namespace android { Surface::Surface( const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp) - : mGraphicBufferProducer(bufferProducer) + : mGraphicBufferProducer(bufferProducer), + mGenerationNumber(0) { // Initialize the ANativeWindow function pointers. ANativeWindow::setSwapInterval = hook_setSwapInterval; @@ -64,6 +66,7 @@ Surface::Surface( mReqFormat = 0; mReqUsage = 0; mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO; + mDataSpace = HAL_DATASPACE_UNKNOWN; mCrop.clear(); mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; mTransform = 0; @@ -96,8 +99,20 @@ void Surface::setSidebandStream(const sp<NativeHandle>& stream) { void Surface::allocateBuffers() { uint32_t reqWidth = mReqWidth ? mReqWidth : mUserWidth; uint32_t reqHeight = mReqHeight ? mReqHeight : mUserHeight; - mGraphicBufferProducer->allocateBuffers(mSwapIntervalZero, mReqWidth, - mReqHeight, mReqFormat, mReqUsage); + mGraphicBufferProducer->allocateBuffers(mSwapIntervalZero, reqWidth, + reqHeight, mReqFormat, mReqUsage); +} + +status_t Surface::setGenerationNumber(uint32_t generation) { + status_t result = mGraphicBufferProducer->setGenerationNumber(generation); + if (result == NO_ERROR) { + mGenerationNumber = generation; + } + return result; +} + +String8 Surface::getConsumerName() const { + return mGraphicBufferProducer->getConsumerName(); } int Surface::hook_setSwapInterval(ANativeWindow* window, int interval) { @@ -193,17 +208,17 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { ATRACE_CALL(); ALOGV("Surface::dequeueBuffer"); - int reqW; - int reqH; + uint32_t reqWidth; + uint32_t reqHeight; bool swapIntervalZero; - uint32_t reqFormat; + PixelFormat reqFormat; uint32_t reqUsage; { Mutex::Autolock lock(mMutex); - reqW = mReqWidth ? mReqWidth : mUserWidth; - reqH = mReqHeight ? mReqHeight : mUserHeight; + reqWidth = mReqWidth ? mReqWidth : mUserWidth; + reqHeight = mReqHeight ? mReqHeight : mUserHeight; swapIntervalZero = mSwapIntervalZero; reqFormat = mReqFormat; @@ -213,12 +228,12 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { int buf = -1; sp<Fence> fence; status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, swapIntervalZero, - reqW, reqH, reqFormat, reqUsage); + reqWidth, reqHeight, reqFormat, reqUsage); if (result < 0) { ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d, %d)" - "failed: %d", swapIntervalZero, reqW, reqH, reqFormat, reqUsage, - result); + "failed: %d", swapIntervalZero, reqWidth, reqHeight, reqFormat, + reqUsage, result); return result; } @@ -265,6 +280,9 @@ int Surface::cancelBuffer(android_native_buffer_t* buffer, Mutex::Autolock lock(mMutex); int i = getSlotFromBufferLocked(buffer); if (i < 0) { + if (fenceFd >= 0) { + close(fenceFd); + } return i; } sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); @@ -274,7 +292,6 @@ int Surface::cancelBuffer(android_native_buffer_t* buffer, int Surface::getSlotFromBufferLocked( android_native_buffer_t* buffer) const { - bool dumpedState = false; for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { if (mSlots[i].buffer != NULL && mSlots[i].buffer->handle == buffer->handle) { @@ -307,6 +324,9 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { } int i = getSlotFromBufferLocked(buffer); if (i < 0) { + if (fenceFd >= 0) { + close(fenceFd); + } return i; } @@ -318,8 +338,72 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); IGraphicBufferProducer::QueueBufferOutput output; IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp, - crop, mScalingMode, mTransform ^ mStickyTransform, mSwapIntervalZero, - fence, mStickyTransform); + mDataSpace, crop, mScalingMode, mTransform ^ mStickyTransform, + mSwapIntervalZero, fence, mStickyTransform); + + if (mConnectedToCpu || mDirtyRegion.bounds() == Rect::INVALID_RECT) { + input.setSurfaceDamage(Region::INVALID_REGION); + } else { + // Here we do two things: + // 1) The surface damage was specified using the OpenGL ES convention of + // the origin being in the bottom-left corner. Here we flip to the + // convention that the rest of the system uses (top-left corner) by + // subtracting all top/bottom coordinates from the buffer height. + // 2) If the buffer is coming in rotated (for example, because the EGL + // implementation is reacting to the transform hint coming back from + // SurfaceFlinger), the surface damage needs to be rotated the + // opposite direction, since it was generated assuming an unrotated + // buffer (the app doesn't know that the EGL implementation is + // reacting to the transform hint behind its back). The + // transformations in the switch statement below apply those + // complementary rotations (e.g., if 90 degrees, rotate 270 degrees). + + int width = buffer->width; + int height = buffer->height; + bool rotated90 = (mTransform ^ mStickyTransform) & + NATIVE_WINDOW_TRANSFORM_ROT_90; + if (rotated90) { + std::swap(width, height); + } + + Region flippedRegion; + for (auto rect : mDirtyRegion) { + int left = rect.left; + int right = rect.right; + int top = height - rect.bottom; // Flip from OpenGL convention + int bottom = height - rect.top; // Flip from OpenGL convention + switch (mTransform ^ mStickyTransform) { + case NATIVE_WINDOW_TRANSFORM_ROT_90: { + // Rotate 270 degrees + Rect flippedRect{top, width - right, bottom, width - left}; + flippedRegion.orSelf(flippedRect); + break; + } + case NATIVE_WINDOW_TRANSFORM_ROT_180: { + // Rotate 180 degrees + Rect flippedRect{width - right, height - bottom, + width - left, height - top}; + flippedRegion.orSelf(flippedRect); + break; + } + case NATIVE_WINDOW_TRANSFORM_ROT_270: { + // Rotate 90 degrees + Rect flippedRect{height - bottom, left, + height - top, right}; + flippedRegion.orSelf(flippedRect); + break; + } + default: { + Rect flippedRect{left, top, right, bottom}; + flippedRegion.orSelf(flippedRect); + break; + } + } + } + + input.setSurfaceDamage(flippedRegion); + } + status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output); if (err != OK) { ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err); @@ -336,6 +420,11 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { mConsumerRunningBehind = (numPendingBuffers >= 2); + if (!mConnectedToCpu) { + // Clear surface damage back to full-buffer + mDirtyRegion = Region::INVALID_REGION; + } + return err; } @@ -347,7 +436,7 @@ int Surface::query(int what, int* value) const { switch (what) { case NATIVE_WINDOW_FORMAT: if (mReqFormat) { - *value = mReqFormat; + *value = static_cast<int>(mReqFormat); return NO_ERROR; } break; @@ -365,13 +454,15 @@ int Surface::query(int what, int* value) const { *value = NATIVE_WINDOW_SURFACE; return NO_ERROR; case NATIVE_WINDOW_DEFAULT_WIDTH: - *value = mUserWidth ? mUserWidth : mDefaultWidth; + *value = static_cast<int>( + mUserWidth ? mUserWidth : mDefaultWidth); return NO_ERROR; case NATIVE_WINDOW_DEFAULT_HEIGHT: - *value = mUserHeight ? mUserHeight : mDefaultHeight; + *value = static_cast<int>( + mUserHeight ? mUserHeight : mDefaultHeight); return NO_ERROR; case NATIVE_WINDOW_TRANSFORM_HINT: - *value = mTransformHint; + *value = static_cast<int>(mTransformHint); return NO_ERROR; case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: { status_t err = NO_ERROR; @@ -448,6 +539,12 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_SET_SIDEBAND_STREAM: res = dispatchSetSidebandStream(args); break; + case NATIVE_WINDOW_SET_BUFFERS_DATASPACE: + res = dispatchSetBuffersDataSpace(args); + break; + case NATIVE_WINDOW_SET_SURFACE_DAMAGE: + res = dispatchSetSurfaceDamage(args); + break; default: res = NAME_NOT_FOUND; break; @@ -467,7 +564,7 @@ int Surface::dispatchDisconnect(va_list args) { int Surface::dispatchSetUsage(va_list args) { int usage = va_arg(args, int); - return setUsage(usage); + return setUsage(static_cast<uint32_t>(usage)); } int Surface::dispatchSetCrop(va_list args) { @@ -477,49 +574,49 @@ int Surface::dispatchSetCrop(va_list args) { int Surface::dispatchSetBufferCount(va_list args) { size_t bufferCount = va_arg(args, size_t); - return setBufferCount(bufferCount); + return setBufferCount(static_cast<int32_t>(bufferCount)); } int Surface::dispatchSetBuffersGeometry(va_list args) { - int w = va_arg(args, int); - int h = va_arg(args, int); - int f = va_arg(args, int); - int err = setBuffersDimensions(w, h); + uint32_t width = va_arg(args, uint32_t); + uint32_t height = va_arg(args, uint32_t); + PixelFormat format = va_arg(args, PixelFormat); + int err = setBuffersDimensions(width, height); if (err != 0) { return err; } - return setBuffersFormat(f); + return setBuffersFormat(format); } int Surface::dispatchSetBuffersDimensions(va_list args) { - int w = va_arg(args, int); - int h = va_arg(args, int); - return setBuffersDimensions(w, h); + uint32_t width = va_arg(args, uint32_t); + uint32_t height = va_arg(args, uint32_t); + return setBuffersDimensions(width, height); } int Surface::dispatchSetBuffersUserDimensions(va_list args) { - int w = va_arg(args, int); - int h = va_arg(args, int); - return setBuffersUserDimensions(w, h); + uint32_t width = va_arg(args, uint32_t); + uint32_t height = va_arg(args, uint32_t); + return setBuffersUserDimensions(width, height); } int Surface::dispatchSetBuffersFormat(va_list args) { - int f = va_arg(args, int); - return setBuffersFormat(f); + PixelFormat format = va_arg(args, PixelFormat); + return setBuffersFormat(format); } int Surface::dispatchSetScalingMode(va_list args) { - int m = va_arg(args, int); - return setScalingMode(m); + int mode = va_arg(args, int); + return setScalingMode(mode); } int Surface::dispatchSetBuffersTransform(va_list args) { - int transform = va_arg(args, int); + uint32_t transform = va_arg(args, uint32_t); return setBuffersTransform(transform); } int Surface::dispatchSetBuffersStickyTransform(va_list args) { - int transform = va_arg(args, int); + uint32_t transform = va_arg(args, uint32_t); return setBuffersStickyTransform(transform); } @@ -545,10 +642,27 @@ int Surface::dispatchSetSidebandStream(va_list args) { return OK; } +int Surface::dispatchSetBuffersDataSpace(va_list args) { + android_dataspace dataspace = + static_cast<android_dataspace>(va_arg(args, int)); + return setBuffersDataSpace(dataspace); +} + +int Surface::dispatchSetSurfaceDamage(va_list args) { + android_native_rect_t* rects = va_arg(args, android_native_rect_t*); + size_t numRects = va_arg(args, size_t); + setSurfaceDamage(rects, numRects); + return NO_ERROR; +} + int Surface::connect(int api) { + static sp<IProducerListener> listener = new DummyProducerListener(); + return connect(api, listener); +} + +int Surface::connect(int api, const sp<IProducerListener>& listener) { ATRACE_CALL(); ALOGV("Surface::connect"); - static sp<IProducerListener> listener = new DummyProducerListener(); Mutex::Autolock lock(mMutex); IGraphicBufferProducer::QueueBufferOutput output; int err = mGraphicBufferProducer->connect(listener, api, mProducerControlledByApp, &output); @@ -567,7 +681,13 @@ int Surface::connect(int api) { } if (!err && api == NATIVE_WINDOW_API_CPU) { mConnectedToCpu = true; + // Clear the dirty region in case we're switching from a non-CPU API + mDirtyRegion.clear(); + } else if (!err) { + // Initialize the dirty region for tracking surface damage + mDirtyRegion = Region::INVALID_REGION; } + return err; } @@ -595,6 +715,58 @@ int Surface::disconnect(int api) { return err; } +int Surface::detachNextBuffer(sp<GraphicBuffer>* outBuffer, + sp<Fence>* outFence) { + ATRACE_CALL(); + ALOGV("Surface::detachNextBuffer"); + + if (outBuffer == NULL || outFence == NULL) { + return BAD_VALUE; + } + + Mutex::Autolock lock(mMutex); + + sp<GraphicBuffer> buffer(NULL); + sp<Fence> fence(NULL); + status_t result = mGraphicBufferProducer->detachNextBuffer( + &buffer, &fence); + if (result != NO_ERROR) { + return result; + } + + *outBuffer = buffer; + if (fence != NULL && fence->isValid()) { + *outFence = fence; + } else { + *outFence = Fence::NO_FENCE; + } + + return NO_ERROR; +} + +int Surface::attachBuffer(ANativeWindowBuffer* buffer) +{ + ATRACE_CALL(); + ALOGV("Surface::attachBuffer"); + + Mutex::Autolock lock(mMutex); + + sp<GraphicBuffer> graphicBuffer(static_cast<GraphicBuffer*>(buffer)); + uint32_t priorGeneration = graphicBuffer->mGenerationNumber; + graphicBuffer->mGenerationNumber = mGenerationNumber; + int32_t attachedSlot = -1; + status_t result = mGraphicBufferProducer->attachBuffer( + &attachedSlot, graphicBuffer); + if (result != NO_ERROR) { + ALOGE("attachBuffer: IGraphicBufferProducer call failed (%d)", result); + graphicBuffer->mGenerationNumber = priorGeneration; + return result; + } + mSlots[attachedSlot].buffer = graphicBuffer; + + return NO_ERROR; +} + int Surface::setUsage(uint32_t reqUsage) { ALOGV("Surface::setUsage"); @@ -639,47 +811,38 @@ int Surface::setBufferCount(int bufferCount) return err; } -int Surface::setBuffersDimensions(int w, int h) +int Surface::setBuffersDimensions(uint32_t width, uint32_t height) { ATRACE_CALL(); ALOGV("Surface::setBuffersDimensions"); - if (w<0 || h<0) - return BAD_VALUE; - - if ((w && !h) || (!w && h)) + if ((width && !height) || (!width && height)) return BAD_VALUE; Mutex::Autolock lock(mMutex); - mReqWidth = w; - mReqHeight = h; + mReqWidth = width; + mReqHeight = height; return NO_ERROR; } -int Surface::setBuffersUserDimensions(int w, int h) +int Surface::setBuffersUserDimensions(uint32_t width, uint32_t height) { ATRACE_CALL(); ALOGV("Surface::setBuffersUserDimensions"); - if (w<0 || h<0) - return BAD_VALUE; - - if ((w && !h) || (!w && h)) + if ((width && !height) || (!width && height)) return BAD_VALUE; Mutex::Autolock lock(mMutex); - mUserWidth = w; - mUserHeight = h; + mUserWidth = width; + mUserHeight = height; return NO_ERROR; } -int Surface::setBuffersFormat(int format) +int Surface::setBuffersFormat(PixelFormat format) { ALOGV("Surface::setBuffersFormat"); - if (format<0) - return BAD_VALUE; - Mutex::Autolock lock(mMutex); mReqFormat = format; return NO_ERROR; @@ -705,7 +868,7 @@ int Surface::setScalingMode(int mode) return NO_ERROR; } -int Surface::setBuffersTransform(int transform) +int Surface::setBuffersTransform(uint32_t transform) { ATRACE_CALL(); ALOGV("Surface::setBuffersTransform"); @@ -714,7 +877,7 @@ int Surface::setBuffersTransform(int transform) return NO_ERROR; } -int Surface::setBuffersStickyTransform(int transform) +int Surface::setBuffersStickyTransform(uint32_t transform) { ATRACE_CALL(); ALOGV("Surface::setBuffersStickyTransform"); @@ -731,12 +894,41 @@ int Surface::setBuffersTimestamp(int64_t timestamp) return NO_ERROR; } +int Surface::setBuffersDataSpace(android_dataspace dataSpace) +{ + ALOGV("Surface::setBuffersDataSpace"); + Mutex::Autolock lock(mMutex); + mDataSpace = dataSpace; + return NO_ERROR; +} + void Surface::freeAllBuffers() { for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { mSlots[i].buffer = 0; } } +void Surface::setSurfaceDamage(android_native_rect_t* rects, size_t numRects) { + ATRACE_CALL(); + ALOGV("Surface::setSurfaceDamage"); + Mutex::Autolock lock(mMutex); + + if (mConnectedToCpu || numRects == 0) { + mDirtyRegion = Region::INVALID_REGION; + return; + } + + mDirtyRegion.clear(); + for (size_t r = 0; r < numRects; ++r) { + // We intentionally flip top and bottom here, since because they're + // specified with a bottom-left origin, top > bottom, which fails + // validation in the Region class. We will fix this up when we flip to a + // top-left origin in queueBuffer. + Rect rect(rects[r].left, rects[r].bottom, rects[r].right, rects[r].top); + mDirtyRegion.orSelf(rect); + } +} + // ---------------------------------------------------------------------- // the lock/unlock APIs must be used from the same thread @@ -748,30 +940,34 @@ static status_t copyBlt( // src and dst with, height and format must be identical. no verification // is done here. status_t err; - uint8_t const * src_bits = NULL; - err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits); + uint8_t* src_bits = NULL; + err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), + reinterpret_cast<void**>(&src_bits)); ALOGE_IF(err, "error locking src buffer %s", strerror(-err)); uint8_t* dst_bits = NULL; - err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits); + err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), + reinterpret_cast<void**>(&dst_bits)); ALOGE_IF(err, "error locking dst buffer %s", strerror(-err)); Region::const_iterator head(reg.begin()); Region::const_iterator tail(reg.end()); if (head != tail && src_bits && dst_bits) { const size_t bpp = bytesPerPixel(src->format); - const size_t dbpr = dst->stride * bpp; - const size_t sbpr = src->stride * bpp; + const size_t dbpr = static_cast<uint32_t>(dst->stride) * bpp; + const size_t sbpr = static_cast<uint32_t>(src->stride) * bpp; while (head != tail) { const Rect& r(*head++); - ssize_t h = r.height(); + int32_t h = r.height(); if (h <= 0) continue; - size_t size = r.width() * bpp; - uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp; - uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp; + size_t size = static_cast<uint32_t>(r.width()) * bpp; + uint8_t const * s = src_bits + + static_cast<uint32_t>(r.left + src->stride * r.top) * bpp; + uint8_t * d = dst_bits + + static_cast<uint32_t>(r.left + dst->stride * r.top) * bpp; if (dbpr==sbpr && size==sbpr) { - size *= h; + size *= static_cast<size_t>(h); h = 1; } do { diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 6446926ea5..6ad47d8b71 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -71,7 +71,7 @@ void ComposerService::connectLocked() { }; mDeathObserver = new DeathObserver(*const_cast<ComposerService*>(this)); - mComposerService->asBinder()->linkToDeath(mDeathObserver); + IInterface::asBinder(mComposerService)->linkToDeath(mDeathObserver); } /*static*/ sp<ISurfaceComposer> ComposerService::getComposerService() { @@ -143,7 +143,7 @@ public: status_t setSize(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, uint32_t w, uint32_t h); status_t setLayer(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, - int32_t z); + uint32_t z); status_t setFlags(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, uint32_t flags, uint32_t mask); status_t setTransparentRegionHint( @@ -293,7 +293,7 @@ status_t Composer::setSize(const sp<SurfaceComposerClient>& client, } status_t Composer::setLayer(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, int32_t z) { + const sp<IBinder>& id, uint32_t z) { Mutex::Autolock _l(mLock); layer_state_t* s = getLayerStateLocked(client, id); if (!s) @@ -310,11 +310,10 @@ status_t Composer::setFlags(const sp<SurfaceComposerClient>& client, layer_state_t* s = getLayerStateLocked(client, id); if (!s) return BAD_INDEX; - if (mask & layer_state_t::eLayerOpaque) { - s->what |= layer_state_t::eOpacityChanged; - } - if (mask & layer_state_t::eLayerHidden) { - s->what |= layer_state_t::eVisibilityChanged; + if (mask & layer_state_t::eLayerOpaque || + mask & layer_state_t::eLayerHidden || + mask & layer_state_t::eLayerSecure) { + s->what |= layer_state_t::eFlagsChanged; } s->flags &= ~mask; s->flags |= (flags & mask); @@ -395,7 +394,7 @@ DisplayState& Composer::getDisplayStateLocked(const sp<IBinder>& token) { s.what = 0; index = mDisplayStates.add(s); } - return mDisplayStates.editItemAt(index); + return mDisplayStates.editItemAt(static_cast<size_t>(index)); } void Composer::setDisplaySurface(const sp<IBinder>& token, @@ -462,14 +461,14 @@ status_t SurfaceComposerClient::initCheck() const { } sp<IBinder> SurfaceComposerClient::connection() const { - return (mClient != 0) ? mClient->asBinder() : 0; + return IInterface::asBinder(mClient); } status_t SurfaceComposerClient::linkToComposerDeath( const sp<IBinder::DeathRecipient>& recipient, void* cookie, uint32_t flags) { sp<ISurfaceComposer> sm(ComposerService::getComposerService()); - return sm->asBinder()->linkToDeath(recipient, cookie, flags); + return IInterface::asBinder(sm)->linkToDeath(recipient, cookie, flags); } void SurfaceComposerClient::dispose() { @@ -571,7 +570,7 @@ status_t SurfaceComposerClient::setSize(const sp<IBinder>& id, uint32_t w, uint3 return getComposer().setSize(this, id, w, h); } -status_t SurfaceComposerClient::setLayer(const sp<IBinder>& id, int32_t z) { +status_t SurfaceComposerClient::setLayer(const sp<IBinder>& id, uint32_t z) { return getComposer().setLayer(this, id, z); } @@ -657,7 +656,7 @@ status_t SurfaceComposerClient::getDisplayInfo(const sp<IBinder>& display, return NAME_NOT_FOUND; } - *info = configs[activeId]; + *info = configs[static_cast<size_t>(activeId)]; return NO_ERROR; } @@ -752,14 +751,14 @@ status_t ScreenshotClient::update(const sp<IBinder>& display, status_t ScreenshotClient::update(const sp<IBinder>& display, Rect sourceCrop, bool useIdentityTransform) { - return ScreenshotClient::update(display, sourceCrop, 0, 0, 0, -1UL, + return ScreenshotClient::update(display, sourceCrop, 0, 0, 0, -1U, useIdentityTransform, ISurfaceComposer::eRotateNone); } status_t ScreenshotClient::update(const sp<IBinder>& display, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform) { return ScreenshotClient::update(display, sourceCrop, reqWidth, reqHeight, - 0, -1UL, useIdentityTransform, ISurfaceComposer::eRotateNone); + 0, -1U, useIdentityTransform, ISurfaceComposer::eRotateNone); } void ScreenshotClient::release() { diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index 7597c991f8..1983027809 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -89,12 +89,12 @@ bool SurfaceControl::isSameSurface( return lhs->mHandle == rhs->mHandle; } -status_t SurfaceControl::setLayerStack(int32_t layerStack) { +status_t SurfaceControl::setLayerStack(uint32_t layerStack) { status_t err = validate(); if (err < 0) return err; return mClient->setLayerStack(mHandle, layerStack); } -status_t SurfaceControl::setLayer(int32_t layer) { +status_t SurfaceControl::setLayer(uint32_t layer) { status_t err = validate(); if (err < 0) return err; return mClient->setLayer(mHandle, layer); @@ -176,7 +176,7 @@ status_t SurfaceControl::writeSurfaceToParcel( if (control != NULL) { bp = control->mGraphicBufferProducer; } - return parcel->writeStrongBinder(bp->asBinder()); + return parcel->writeStrongBinder(IInterface::asBinder(bp)); } sp<Surface> SurfaceControl::getSurface() const diff --git a/libs/gui/SyncFeatures.cpp b/libs/gui/SyncFeatures.cpp index e5804a77b1..187b211be8 100644 --- a/libs/gui/SyncFeatures.cpp +++ b/libs/gui/SyncFeatures.cpp @@ -16,7 +16,6 @@ #define LOG_TAG "GLConsumer" -#define GL_GLEXT_PROTOTYPES #define EGL_EGLEXT_PROTOTYPES #include <EGL/egl.h> @@ -78,10 +77,11 @@ bool SyncFeatures::useFenceSync() const { // on some devices it's better to not use EGL_KHR_fence_sync // even if they have it return false; -#endif +#else // currently we shall only attempt to use EGL_KHR_fence_sync if // USE_FENCE_SYNC is set in our makefile return !mHasNativeFenceSync && mHasFenceSync; +#endif } bool SyncFeatures::useWaitSync() const { return (useNativeFenceSync() || useFenceSync()) && mHasWaitSync; diff --git a/libs/gui/tests/Android.mk b/libs/gui/tests/Android.mk index e460290764..6ad9986220 100644 --- a/libs/gui/tests/Android.mk +++ b/libs/gui/tests/Android.mk @@ -1,6 +1,9 @@ # Build the unit tests, LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk + +LOCAL_CLANG := true LOCAL_MODULE := libgui_test @@ -31,17 +34,10 @@ LOCAL_SHARED_LIBRARIES := \ libbinder \ libcutils \ libgui \ - libstlport \ libsync \ libui \ libutils \ -LOCAL_C_INCLUDES := \ - bionic \ - bionic/libstdc++/include \ - external/gtest/include \ - external/stlport/stlport \ - # Build the binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE) # to integrate with auto-test framework. include $(BUILD_NATIVE_TEST) diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 96de11f202..1a54875446 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -17,6 +17,9 @@ #define LOG_TAG "BufferQueue_test" //#define LOG_NDEBUG 0 +#include "DummyConsumer.h" + +#include <gui/BufferItem.h> #include <gui/BufferQueue.h> #include <gui/IProducerListener.h> @@ -66,11 +69,7 @@ protected: sp<IGraphicBufferConsumer> mConsumer; }; -struct DummyConsumer : public BnConsumerListener { - virtual void onFrameAvailable(const BufferItem& /* item */) {} - virtual void onBuffersReleased() {} - virtual void onSidebandStreamChanged() {} -}; +static const uint32_t TEST_DATA = 0x12345678u; // XXX: Tests that fork a process to hold the BufferQueue must run before tests // that use a local BufferQueue, or else Binder will get unhappy @@ -87,8 +86,8 @@ TEST_F(BufferQueueTest, BufferQueueInAnotherProcess) { sp<IGraphicBufferConsumer> consumer; BufferQueue::createBufferQueue(&producer, &consumer); sp<IServiceManager> serviceManager = defaultServiceManager(); - serviceManager->addService(PRODUCER_NAME, producer->asBinder()); - serviceManager->addService(CONSUMER_NAME, consumer->asBinder()); + serviceManager->addService(PRODUCER_NAME, IInterface::asBinder(producer)); + serviceManager->addService(CONSUMER_NAME, IInterface::asBinder(consumer)); ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); LOG_ALWAYS_FATAL("Shouldn't be here"); @@ -121,20 +120,21 @@ TEST_F(BufferQueueTest, BufferQueueInAnotherProcess) { uint32_t* dataIn; ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN, reinterpret_cast<void**>(&dataIn))); - *dataIn = 0x12345678; + *dataIn = TEST_DATA; ASSERT_EQ(OK, buffer->unlock()); - IGraphicBufferProducer::QueueBufferInput input(0, false, Rect(0, 0, 1, 1), + IGraphicBufferProducer::QueueBufferInput input(0, false, + HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); - IGraphicBufferConsumer::BufferItem item; + BufferItem item; ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); uint32_t* dataOut; ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&dataOut))); - ASSERT_EQ(*dataOut, 0x12345678); + ASSERT_EQ(*dataOut, TEST_DATA); ASSERT_EQ(OK, item.mGraphicBuffer->unlock()); } @@ -150,9 +150,10 @@ TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) { int slot; sp<Fence> fence; sp<GraphicBuffer> buf; - IGraphicBufferProducer::QueueBufferInput qbi(0, false, Rect(0, 0, 1, 1), + IGraphicBufferProducer::QueueBufferInput qbi(0, false, + HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE); - BufferQueue::BufferItem item; + BufferItem item; for (int i = 0; i < 2; i++) { ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, @@ -236,7 +237,7 @@ TEST_F(BufferQueueTest, DetachAndReattachOnProducerSide) { uint32_t* dataIn; ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN, reinterpret_cast<void**>(&dataIn))); - *dataIn = 0x12345678; + *dataIn = TEST_DATA; ASSERT_EQ(OK, buffer->unlock()); int newSlot; @@ -244,17 +245,18 @@ TEST_F(BufferQueueTest, DetachAndReattachOnProducerSide) { ASSERT_EQ(BAD_VALUE, mProducer->attachBuffer(&newSlot, NULL)); ASSERT_EQ(OK, mProducer->attachBuffer(&newSlot, buffer)); - IGraphicBufferProducer::QueueBufferInput input(0, false, Rect(0, 0, 1, 1), + IGraphicBufferProducer::QueueBufferInput input(0, false, + HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE); ASSERT_EQ(OK, mProducer->queueBuffer(newSlot, input, &output)); - IGraphicBufferConsumer::BufferItem item; + BufferItem item; ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, static_cast<nsecs_t>(0))); uint32_t* dataOut; ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&dataOut))); - ASSERT_EQ(*dataOut, 0x12345678); + ASSERT_EQ(*dataOut, TEST_DATA); ASSERT_EQ(OK, item.mGraphicBuffer->unlock()); } @@ -273,7 +275,8 @@ TEST_F(BufferQueueTest, DetachAndReattachOnConsumerSide) { mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); - IGraphicBufferProducer::QueueBufferInput input(0, false, Rect(0, 0, 1, 1), + IGraphicBufferProducer::QueueBufferInput input(0, false, + HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); @@ -282,7 +285,7 @@ TEST_F(BufferQueueTest, DetachAndReattachOnConsumerSide) { BufferQueueDefs::NUM_BUFFER_SLOTS)); // Index too high ASSERT_EQ(BAD_VALUE, mConsumer->detachBuffer(0)); // Not acquired - IGraphicBufferConsumer::BufferItem item; + BufferItem item; ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, static_cast<nsecs_t>(0))); ASSERT_EQ(OK, mConsumer->detachBuffer(item.mBuf)); @@ -292,7 +295,7 @@ TEST_F(BufferQueueTest, DetachAndReattachOnConsumerSide) { ASSERT_EQ(OK, item.mGraphicBuffer->lock( GraphicBuffer::USAGE_SW_WRITE_OFTEN, reinterpret_cast<void**>(&dataIn))); - *dataIn = 0x12345678; + *dataIn = TEST_DATA; ASSERT_EQ(OK, item.mGraphicBuffer->unlock()); int newSlot; @@ -312,7 +315,7 @@ TEST_F(BufferQueueTest, DetachAndReattachOnConsumerSide) { uint32_t* dataOut; ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&dataOut))); - ASSERT_EQ(*dataOut, 0x12345678); + ASSERT_EQ(*dataOut, TEST_DATA); ASSERT_EQ(OK, buffer->unlock()); } @@ -335,14 +338,15 @@ TEST_F(BufferQueueTest, MoveFromConsumerToProducer) { uint32_t* dataIn; ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN, reinterpret_cast<void**>(&dataIn))); - *dataIn = 0x12345678; + *dataIn = TEST_DATA; ASSERT_EQ(OK, buffer->unlock()); - IGraphicBufferProducer::QueueBufferInput input(0, false, Rect(0, 0, 1, 1), + IGraphicBufferProducer::QueueBufferInput input(0, false, + HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); - IGraphicBufferConsumer::BufferItem item; + BufferItem item; ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, static_cast<nsecs_t>(0))); ASSERT_EQ(OK, mConsumer->detachBuffer(item.mBuf)); @@ -354,8 +358,86 @@ TEST_F(BufferQueueTest, MoveFromConsumerToProducer) { uint32_t* dataOut; ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&dataOut))); - ASSERT_EQ(*dataOut, 0x12345678); + ASSERT_EQ(*dataOut, TEST_DATA); ASSERT_EQ(OK, item.mGraphicBuffer->unlock()); } +TEST_F(BufferQueueTest, TestDisallowingAllocation) { + createBufferQueue(); + sp<DummyConsumer> dc(new DummyConsumer); + ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true)); + IGraphicBufferProducer::QueueBufferOutput output; + ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, + NATIVE_WINDOW_API_CPU, true, &output)); + + static const uint32_t WIDTH = 320; + static const uint32_t HEIGHT = 240; + + ASSERT_EQ(OK, mConsumer->setDefaultBufferSize(WIDTH, HEIGHT)); + + int slot; + sp<Fence> fence; + sp<GraphicBuffer> buffer; + // This should return an error since it would require an allocation + ASSERT_EQ(OK, mProducer->allowAllocation(false)); + ASSERT_EQ(WOULD_BLOCK, mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, + 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); + + // This should succeed, now that we've lifted the prohibition + ASSERT_EQ(OK, mProducer->allowAllocation(true)); + ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, + mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0, + GRALLOC_USAGE_SW_WRITE_OFTEN)); + + // Release the previous buffer back to the BufferQueue + mProducer->cancelBuffer(slot, fence); + + // This should fail since we're requesting a different size + ASSERT_EQ(OK, mProducer->allowAllocation(false)); + ASSERT_EQ(WOULD_BLOCK, mProducer->dequeueBuffer(&slot, &fence, false, + WIDTH * 2, HEIGHT * 2, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); +} + +TEST_F(BufferQueueTest, TestGenerationNumbers) { + createBufferQueue(); + sp<DummyConsumer> dc(new DummyConsumer); + ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true)); + IGraphicBufferProducer::QueueBufferOutput output; + ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, + NATIVE_WINDOW_API_CPU, true, &output)); + + ASSERT_EQ(OK, mProducer->setGenerationNumber(1)); + + // Get one buffer to play with + int slot; + sp<Fence> fence; + ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, + mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0, 0)); + + sp<GraphicBuffer> buffer; + ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); + + // Ensure that the generation number we set propagates to allocated buffers + ASSERT_EQ(1U, buffer->getGenerationNumber()); + + ASSERT_EQ(OK, mProducer->detachBuffer(slot)); + + ASSERT_EQ(OK, mProducer->setGenerationNumber(2)); + + // These should fail, since we've changed the generation number on the queue + int outSlot; + ASSERT_EQ(BAD_VALUE, mProducer->attachBuffer(&outSlot, buffer)); + ASSERT_EQ(BAD_VALUE, mConsumer->attachBuffer(&outSlot, buffer)); + + buffer->setGenerationNumber(2); + + // This should succeed now that we've changed the buffer's generation number + ASSERT_EQ(OK, mProducer->attachBuffer(&outSlot, buffer)); + + ASSERT_EQ(OK, mProducer->detachBuffer(outSlot)); + + // This should also succeed with the new generation number + ASSERT_EQ(OK, mConsumer->attachBuffer(&outSlot, buffer)); +} + } // namespace android diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp index abd372449f..2dc9cccb56 100644 --- a/libs/gui/tests/CpuConsumer_test.cpp +++ b/libs/gui/tests/CpuConsumer_test.cpp @@ -94,7 +94,7 @@ protected: mPendingFrames--; } - virtual void onFrameAvailable() { + virtual void onFrameAvailable(const BufferItem&) { Mutex::Autolock lock(mMutex); mPendingFrames++; mCondition.signal(); @@ -125,7 +125,7 @@ protected: mPendingFrames--; } - virtual void onFrameAvailable() { + virtual void onFrameAvailable(const BufferItem&) { Mutex::Autolock lock(mMutex); mPendingFrames++; mFrameCondition.signal(); @@ -166,7 +166,7 @@ void checkPixel(const CpuConsumer::LockedBuffer &buf, uint32_t x, uint32_t y, uint32_t r, uint32_t g=0, uint32_t b=0) { // Ignores components that don't exist for given pixel switch(buf.format) { - case HAL_PIXEL_FORMAT_RAW_SENSOR: { + case HAL_PIXEL_FORMAT_RAW16: { String8 msg; uint16_t *bPtr = (uint16_t*)buf.data; bPtr += y * buf.stride + x; @@ -429,7 +429,7 @@ void checkBayerRawBuffer(const CpuConsumer::LockedBuffer &buf) { void checkAnyBuffer(const CpuConsumer::LockedBuffer &buf, int format) { switch (format) { - case HAL_PIXEL_FORMAT_RAW_SENSOR: + case HAL_PIXEL_FORMAT_RAW16: checkBayerRawBuffer(buf); break; case HAL_PIXEL_FORMAT_Y8: @@ -457,9 +457,12 @@ void configureANW(const sp<ANativeWindow>& anw, const CpuConsumerTestParams& params, int maxBufferSlack) { status_t err; - err = native_window_set_buffers_geometry(anw.get(), - params.width, params.height, params.format); - ASSERT_NO_ERROR(err, "set_buffers_geometry error: "); + err = native_window_set_buffers_dimensions(anw.get(), + params.width, params.height); + ASSERT_NO_ERROR(err, "set_buffers_dimensions error: "); + + err = native_window_set_buffers_format(anw.get(), params.format); + ASSERT_NO_ERROR(err, "set_buffers_format error: "); err = native_window_set_usage(anw.get(), GRALLOC_USAGE_SW_WRITE_OFTEN); @@ -505,7 +508,7 @@ void produceOneFrame(const sp<ANativeWindow>& anw, case HAL_PIXEL_FORMAT_YV12: fillYV12Buffer(img, params.width, params.height, *stride); break; - case HAL_PIXEL_FORMAT_RAW_SENSOR: + case HAL_PIXEL_FORMAT_RAW16: fillBayerRawBuffer(img, params.width, params.height, buf->getStride()); break; case HAL_PIXEL_FORMAT_Y8: @@ -537,7 +540,7 @@ void produceOneFrame(const sp<ANativeWindow>& anw, ASSERT_NO_ERROR(err, "queueBuffer error:"); }; -// This test is disabled because the HAL_PIXEL_FORMAT_RAW_SENSOR format is not +// This test is disabled because the HAL_PIXEL_FORMAT_RAW16 format is not // supported on all devices. TEST_P(CpuConsumerTest, FromCpuSingle) { status_t err; @@ -571,7 +574,7 @@ TEST_P(CpuConsumerTest, FromCpuSingle) { mCC->unlockBuffer(b); } -// This test is disabled because the HAL_PIXEL_FORMAT_RAW_SENSOR format is not +// This test is disabled because the HAL_PIXEL_FORMAT_RAW16 format is not // supported on all devices. TEST_P(CpuConsumerTest, FromCpuManyInQueue) { status_t err; @@ -614,7 +617,7 @@ TEST_P(CpuConsumerTest, FromCpuManyInQueue) { } } -// This test is disabled because the HAL_PIXEL_FORMAT_RAW_SENSOR format is not +// This test is disabled because the HAL_PIXEL_FORMAT_RAW16 format is not // supported on all devices. TEST_P(CpuConsumerTest, FromCpuLockMax) { status_t err; @@ -710,12 +713,12 @@ CpuConsumerTestParams y16TestSets[] = { }; CpuConsumerTestParams rawTestSets[] = { - { 512, 512, 1, HAL_PIXEL_FORMAT_RAW_SENSOR}, - { 512, 512, 3, HAL_PIXEL_FORMAT_RAW_SENSOR}, - { 2608, 1960, 1, HAL_PIXEL_FORMAT_RAW_SENSOR}, - { 2608, 1960, 3, HAL_PIXEL_FORMAT_RAW_SENSOR}, - { 100, 100, 1, HAL_PIXEL_FORMAT_RAW_SENSOR}, - { 100, 100, 3, HAL_PIXEL_FORMAT_RAW_SENSOR}, + { 512, 512, 1, HAL_PIXEL_FORMAT_RAW16}, + { 512, 512, 3, HAL_PIXEL_FORMAT_RAW16}, + { 2608, 1960, 1, HAL_PIXEL_FORMAT_RAW16}, + { 2608, 1960, 3, HAL_PIXEL_FORMAT_RAW16}, + { 100, 100, 1, HAL_PIXEL_FORMAT_RAW16}, + { 100, 100, 3, HAL_PIXEL_FORMAT_RAW16}, }; CpuConsumerTestParams rgba8888TestSets[] = { diff --git a/libs/gui/tests/DummyConsumer.h b/libs/gui/tests/DummyConsumer.h new file mode 100644 index 0000000000..0511e165c2 --- /dev/null +++ b/libs/gui/tests/DummyConsumer.h @@ -0,0 +1,27 @@ +/* + * Copyright 2015 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 <gui/IConsumerListener.h> + +namespace android { + +struct DummyConsumer : public BnConsumerListener { + virtual void onFrameAvailable(const BufferItem& /* item */) {} + virtual void onBuffersReleased() {} + virtual void onSidebandStreamChanged() {} +}; + +} // namespace android diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp index 8d5fd8f58f..4ef9a69844 100644 --- a/libs/gui/tests/IGraphicBufferProducer_test.cpp +++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp @@ -38,30 +38,31 @@ #define TEST_CONTROLLED_BY_APP false #define TEST_PRODUCER_USAGE_BITS (0) -// TODO: Make these public constants in a header -enum { +namespace android { + +namespace { // Default dimensions before setDefaultBufferSize is called - DEFAULT_WIDTH = 1, - DEFAULT_HEIGHT = 1, + const uint32_t DEFAULT_WIDTH = 1; + const uint32_t DEFAULT_HEIGHT = 1; // Default format before setDefaultBufferFormat is called - DEFAULT_FORMAT = HAL_PIXEL_FORMAT_RGBA_8888, + const PixelFormat DEFAULT_FORMAT = HAL_PIXEL_FORMAT_RGBA_8888; // Default transform hint before setTransformHint is called - DEFAULT_TRANSFORM_HINT = 0, -}; + const uint32_t DEFAULT_TRANSFORM_HINT = 0; -namespace android { + // TODO: Make these constants in header + const int DEFAULT_CONSUMER_USAGE_BITS = 0; -namespace { -// Parameters for a generic "valid" input for queueBuffer. -const int64_t QUEUE_BUFFER_INPUT_TIMESTAMP = 1384888611; -const bool QUEUE_BUFFER_INPUT_IS_AUTO_TIMESTAMP = false; -const Rect QUEUE_BUFFER_INPUT_RECT = Rect(DEFAULT_WIDTH, DEFAULT_HEIGHT); -const int QUEUE_BUFFER_INPUT_SCALING_MODE = 0; -const int QUEUE_BUFFER_INPUT_TRANSFORM = 0; -const bool QUEUE_BUFFER_INPUT_ASYNC = false; -const sp<Fence> QUEUE_BUFFER_INPUT_FENCE = Fence::NO_FENCE; + // Parameters for a generic "valid" input for queueBuffer. + const int64_t QUEUE_BUFFER_INPUT_TIMESTAMP = 1384888611; + const bool QUEUE_BUFFER_INPUT_IS_AUTO_TIMESTAMP = false; + const android_dataspace QUEUE_BUFFER_INPUT_DATASPACE = HAL_DATASPACE_UNKNOWN; + const Rect QUEUE_BUFFER_INPUT_RECT = Rect(DEFAULT_WIDTH, DEFAULT_HEIGHT); + const int QUEUE_BUFFER_INPUT_SCALING_MODE = 0; + const int QUEUE_BUFFER_INPUT_TRANSFORM = 0; + const bool QUEUE_BUFFER_INPUT_ASYNC = false; + const sp<Fence> QUEUE_BUFFER_INPUT_FENCE = Fence::NO_FENCE; }; // namespace anonymous struct DummyConsumer : public BnConsumerListener { @@ -126,6 +127,7 @@ protected: QueueBufferInputBuilder() { timestamp = QUEUE_BUFFER_INPUT_TIMESTAMP; isAutoTimestamp = QUEUE_BUFFER_INPUT_IS_AUTO_TIMESTAMP; + dataSpace = QUEUE_BUFFER_INPUT_DATASPACE; crop = QUEUE_BUFFER_INPUT_RECT; scalingMode = QUEUE_BUFFER_INPUT_SCALING_MODE; transform = QUEUE_BUFFER_INPUT_TRANSFORM; @@ -137,6 +139,7 @@ protected: return IGraphicBufferProducer::QueueBufferInput( timestamp, isAutoTimestamp, + dataSpace, crop, scalingMode, transform, @@ -154,6 +157,11 @@ protected: return *this; } + QueueBufferInputBuilder& setDataSpace(android_dataspace dataSpace) { + this->dataSpace = dataSpace; + return *this; + } + QueueBufferInputBuilder& setCrop(Rect crop) { this->crop = crop; return *this; @@ -182,6 +190,7 @@ protected: private: int64_t timestamp; bool isAutoTimestamp; + android_dataspace dataSpace; Rect crop; int scalingMode; uint32_t transform; @@ -264,15 +273,12 @@ TEST_F(IGraphicBufferProducerTest, Disconnect_ReturnsError) { TEST_F(IGraphicBufferProducerTest, Query_Succeeds) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); - // TODO: Make these constants in header - const int DEFAULT_CONSUMER_USAGE_BITS = 0; - - int value = -1; + int32_t value = -1; EXPECT_OK(mProducer->query(NATIVE_WINDOW_WIDTH, &value)); - EXPECT_EQ(DEFAULT_WIDTH, value); + EXPECT_EQ(DEFAULT_WIDTH, static_cast<uint32_t>(value)); EXPECT_OK(mProducer->query(NATIVE_WINDOW_HEIGHT, &value)); - EXPECT_EQ(DEFAULT_HEIGHT, value); + EXPECT_EQ(DEFAULT_HEIGHT, static_cast<uint32_t>(value)); EXPECT_OK(mProducer->query(NATIVE_WINDOW_FORMAT, &value)); EXPECT_EQ(DEFAULT_FORMAT, value); @@ -293,7 +299,7 @@ TEST_F(IGraphicBufferProducerTest, Query_ReturnsError) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); // One past the end of the last 'query' enum value. Update this if we add more enums. - const int NATIVE_WINDOW_QUERY_LAST_OFF_BY_ONE = NATIVE_WINDOW_CONSUMER_USAGE_BITS + 1; + const int NATIVE_WINDOW_QUERY_LAST_OFF_BY_ONE = NATIVE_WINDOW_BUFFER_AGE + 1; int value; // What was out of range @@ -360,7 +366,7 @@ TEST_F(IGraphicBufferProducerTest, Queue_Succeeds) { EXPECT_EQ(DEFAULT_WIDTH, width); EXPECT_EQ(DEFAULT_HEIGHT, height); EXPECT_EQ(DEFAULT_TRANSFORM_HINT, transformHint); - EXPECT_EQ(1, numPendingBuffers); // since queueBuffer was called exactly once + EXPECT_EQ(1u, numPendingBuffers); // since queueBuffer was called exactly once } // Buffer was not in the dequeued state diff --git a/libs/gui/tests/SRGB_test.cpp b/libs/gui/tests/SRGB_test.cpp index 2d5b8aaf20..3b11b974c6 100644 --- a/libs/gui/tests/SRGB_test.cpp +++ b/libs/gui/tests/SRGB_test.cpp @@ -17,8 +17,14 @@ #define LOG_TAG "SRGB_test" //#define LOG_NDEBUG 0 +// Ignore for this file because it flags every instance of +// ASSERT_EQ(GL_NO_ERROR, glGetError()); +#pragma clang diagnostic ignored "-Wsign-compare" + #include "GLTest.h" +#include <math.h> + #include <gui/CpuConsumer.h> #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> @@ -212,10 +218,11 @@ protected: ASSERT_EQ(GL_NO_ERROR, glGetError()); } - void checkLockedBuffer(PixelFormat format) { + void checkLockedBuffer(PixelFormat format, android_dataspace dataSpace) { ASSERT_EQ(mLockedBuffer.format, format); ASSERT_EQ(mLockedBuffer.width, DISPLAY_WIDTH); ASSERT_EQ(mLockedBuffer.height, DISPLAY_HEIGHT); + ASSERT_EQ(mLockedBuffer.dataSpace, dataSpace); } static bool withinTolerance(int a, int b) { @@ -326,14 +333,15 @@ private: ANativeWindow_Buffer outBuffer; ARect outBufferBounds; mOutputSurface->lock(&outBuffer, &outBufferBounds); - ASSERT_EQ(mLockedBuffer.width, outBuffer.width); - ASSERT_EQ(mLockedBuffer.height, outBuffer.height); - ASSERT_EQ(mLockedBuffer.stride, outBuffer.stride); + ASSERT_EQ(mLockedBuffer.width, static_cast<uint32_t>(outBuffer.width)); + ASSERT_EQ(mLockedBuffer.height, static_cast<uint32_t>(outBuffer.height)); + ASSERT_EQ(mLockedBuffer.stride, static_cast<uint32_t>(outBuffer.stride)); if (mLockedBuffer.format == outBuffer.format) { memcpy(outBuffer.bits, mLockedBuffer.data, bufferSize); } else { - ASSERT_EQ(mLockedBuffer.format, PIXEL_FORMAT_sRGB_A_8888); + ASSERT_EQ(mLockedBuffer.format, PIXEL_FORMAT_RGBA_8888); + ASSERT_EQ(mLockedBuffer.dataSpace, HAL_DATASPACE_SRGB); ASSERT_EQ(outBuffer.format, PIXEL_FORMAT_RGBA_8888); uint8_t* outPointer = reinterpret_cast<uint8_t*>(outBuffer.bits); for (int y = 0; y < outBuffer.height; ++y) { @@ -378,7 +386,8 @@ TEST_F(SRGBTest, GLRenderFromSRGBTexture) { // Lock ASSERT_EQ(NO_ERROR, mCpuConsumer->lockNextBuffer(&mLockedBuffer)); - ASSERT_NO_FATAL_FAILURE(checkLockedBuffer(PIXEL_FORMAT_RGBA_8888)); + ASSERT_NO_FATAL_FAILURE( + checkLockedBuffer(PIXEL_FORMAT_RGBA_8888, HAL_DATASPACE_UNKNOWN)); // Compare a pixel in the middle of each texture int midSRGBOffset = (DISPLAY_HEIGHT / 4) * mLockedBuffer.stride * @@ -396,7 +405,8 @@ TEST_F(SRGBTest, GLRenderFromSRGBTexture) { // the debug surface if necessary } -TEST_F(SRGBTest, RenderToSRGBSurface) { +// XXX: Disabled since we don't currently expect this to work +TEST_F(SRGBTest, DISABLED_RenderToSRGBSurface) { ASSERT_NO_FATAL_FAILURE(initShaders()); // By default, the first buffer we write into will be RGB @@ -409,7 +419,8 @@ TEST_F(SRGBTest, RenderToSRGBSurface) { // Lock ASSERT_EQ(NO_ERROR, mCpuConsumer->lockNextBuffer(&mLockedBuffer)); - ASSERT_NO_FATAL_FAILURE(checkLockedBuffer(PIXEL_FORMAT_RGBA_8888)); + ASSERT_NO_FATAL_FAILURE( + checkLockedBuffer(PIXEL_FORMAT_RGBA_8888, HAL_DATASPACE_UNKNOWN)); // Save the values of the middle pixel for later comparison against SRGB uint8_t values[PIXEL_SIZE] = {}; @@ -458,7 +469,8 @@ TEST_F(SRGBTest, RenderToSRGBSurface) { ASSERT_EQ(NO_ERROR, mCpuConsumer->lockNextBuffer(&mLockedBuffer)); // Make sure we actually got the SRGB buffer on the consumer side - ASSERT_NO_FATAL_FAILURE(checkLockedBuffer(PIXEL_FORMAT_sRGB_A_8888)); + ASSERT_NO_FATAL_FAILURE( + checkLockedBuffer(PIXEL_FORMAT_RGBA_8888, HAL_DATASPACE_SRGB)); // Verify that the stored value is the same, accounting for RGB/SRGB for (int c = 0; c < PIXEL_SIZE; ++c) { diff --git a/libs/gui/tests/StreamSplitter_test.cpp b/libs/gui/tests/StreamSplitter_test.cpp index 4e63a6f4db..00cc39dc06 100644 --- a/libs/gui/tests/StreamSplitter_test.cpp +++ b/libs/gui/tests/StreamSplitter_test.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "StreamSplitter_test" //#define LOG_NDEBUG 0 +#include <gui/BufferItem.h> #include <gui/BufferQueue.h> #include <gui/IConsumerListener.h> #include <gui/ISurfaceComposer.h> @@ -75,6 +76,8 @@ private: int mAllocCount; }; +static const uint32_t TEST_DATA = 0x12345678u; + TEST_F(StreamSplitterTest, OneInputOneOutput) { sp<CountedAllocator> allocator(new CountedAllocator); @@ -107,21 +110,22 @@ TEST_F(StreamSplitterTest, OneInputOneOutput) { uint32_t* dataIn; ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN, reinterpret_cast<void**>(&dataIn))); - *dataIn = 0x12345678; + *dataIn = TEST_DATA; ASSERT_EQ(OK, buffer->unlock()); IGraphicBufferProducer::QueueBufferInput qbInput(0, false, + HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE); ASSERT_EQ(OK, inputProducer->queueBuffer(slot, qbInput, &qbOutput)); - IGraphicBufferConsumer::BufferItem item; + BufferItem item; ASSERT_EQ(OK, outputConsumer->acquireBuffer(&item, 0)); uint32_t* dataOut; ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&dataOut))); - ASSERT_EQ(*dataOut, 0x12345678); + ASSERT_EQ(*dataOut, TEST_DATA); ASSERT_EQ(OK, item.mGraphicBuffer->unlock()); ASSERT_EQ(OK, outputConsumer->releaseBuffer(item.mBuf, item.mFrameNumber, @@ -173,22 +177,23 @@ TEST_F(StreamSplitterTest, OneInputMultipleOutputs) { uint32_t* dataIn; ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN, reinterpret_cast<void**>(&dataIn))); - *dataIn = 0x12345678; + *dataIn = TEST_DATA; ASSERT_EQ(OK, buffer->unlock()); IGraphicBufferProducer::QueueBufferInput qbInput(0, false, + HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE); ASSERT_EQ(OK, inputProducer->queueBuffer(slot, qbInput, &qbOutput)); for (int output = 0; output < NUM_OUTPUTS; ++output) { - IGraphicBufferConsumer::BufferItem item; + BufferItem item; ASSERT_EQ(OK, outputConsumers[output]->acquireBuffer(&item, 0)); uint32_t* dataOut; ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&dataOut))); - ASSERT_EQ(*dataOut, 0x12345678); + ASSERT_EQ(*dataOut, TEST_DATA); ASSERT_EQ(OK, item.mGraphicBuffer->unlock()); ASSERT_EQ(OK, outputConsumers[output]->releaseBuffer(item.mBuf, @@ -234,6 +239,7 @@ TEST_F(StreamSplitterTest, OutputAbandonment) { outputConsumer->consumerDisconnect(); IGraphicBufferProducer::QueueBufferInput qbInput(0, false, + HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE); ASSERT_EQ(OK, inputProducer->queueBuffer(slot, qbInput, &qbOutput)); diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp index 8cdf3bc349..1a50b2480d 100644 --- a/libs/gui/tests/SurfaceTextureClient_test.cpp +++ b/libs/gui/tests/SurfaceTextureClient_test.cpp @@ -27,6 +27,9 @@ #include <utils/Log.h> #include <utils/Thread.h> +EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); +#define CROP_EXT_STR "EGL_ANDROID_image_crop" + namespace android { class SurfaceTextureClientTest : public ::testing::Test { @@ -207,12 +210,8 @@ TEST_F(SurfaceTextureClientTest, EglSwapBuffersAbandonErrorIsEglBadSurface) { } TEST_F(SurfaceTextureClientTest, BufferGeometryInvalidSizesFail) { - EXPECT_GT(OK, native_window_set_buffers_geometry(mANW.get(), -1, 0, 0)); - EXPECT_GT(OK, native_window_set_buffers_geometry(mANW.get(), 0, -1, 0)); - EXPECT_GT(OK, native_window_set_buffers_geometry(mANW.get(), 0, 0, -1)); - EXPECT_GT(OK, native_window_set_buffers_geometry(mANW.get(), -1, -1, 0)); - EXPECT_GT(OK, native_window_set_buffers_geometry(mANW.get(), 0, 8, 0)); - EXPECT_GT(OK, native_window_set_buffers_geometry(mANW.get(), 8, 0, 0)); + EXPECT_GT(OK, native_window_set_buffers_dimensions(mANW.get(), 0, 8)); + EXPECT_GT(OK, native_window_set_buffers_dimensions(mANW.get(), 8, 0)); } TEST_F(SurfaceTextureClientTest, DefaultGeometryValues) { @@ -226,7 +225,8 @@ TEST_F(SurfaceTextureClientTest, DefaultGeometryValues) { TEST_F(SurfaceTextureClientTest, BufferGeometryCanBeSet) { ANativeWindowBuffer* buf; - EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 16, 8, PIXEL_FORMAT_RGB_565)); + EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 16, 8)); + EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), PIXEL_FORMAT_RGB_565)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(16, buf->width); EXPECT_EQ(8, buf->height); @@ -236,7 +236,8 @@ TEST_F(SurfaceTextureClientTest, BufferGeometryCanBeSet) { TEST_F(SurfaceTextureClientTest, BufferGeometryDefaultSizeSetFormat) { ANativeWindowBuffer* buf; - EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 0, 0, PIXEL_FORMAT_RGB_565)); + EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 0, 0)); + EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), PIXEL_FORMAT_RGB_565)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(1, buf->width); EXPECT_EQ(1, buf->height); @@ -246,7 +247,8 @@ TEST_F(SurfaceTextureClientTest, BufferGeometryDefaultSizeSetFormat) { TEST_F(SurfaceTextureClientTest, BufferGeometrySetSizeDefaultFormat) { ANativeWindowBuffer* buf; - EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 16, 8, 0)); + EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 16, 8)); + EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), 0)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(16, buf->width); EXPECT_EQ(8, buf->height); @@ -256,13 +258,15 @@ TEST_F(SurfaceTextureClientTest, BufferGeometrySetSizeDefaultFormat) { TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeUnset) { ANativeWindowBuffer* buf; - EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 16, 8, 0)); + EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 16, 8)); + EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), 0)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(16, buf->width); EXPECT_EQ(8, buf->height); EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1)); - EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 0, 0, 0)); + EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 0, 0)); + EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), 0)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(1, buf->width); EXPECT_EQ(1, buf->height); @@ -272,7 +276,8 @@ TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeUnset) { TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeChangedWithoutFormat) { ANativeWindowBuffer* buf; - EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 0, 0, PIXEL_FORMAT_RGB_565)); + EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 0, 0)); + EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), PIXEL_FORMAT_RGB_565)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); EXPECT_EQ(1, buf->width); EXPECT_EQ(1, buf->height); @@ -330,7 +335,8 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeVsGeometry) { EXPECT_EQ(8, buf[1]->height); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0], -1)); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1], -1)); - EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 12, 24, 0)); + EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 12, 24)); + EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), 0)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); EXPECT_NE(buf[0], buf[1]); @@ -468,7 +474,8 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeMinUndequeued) { // Once we've queued a buffer, however we should not be able to dequeue more // than (buffer-count - MIN_UNDEQUEUED_BUFFERS), which is 2 in this case. - EXPECT_EQ(-EBUSY, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); + EXPECT_EQ(INVALID_OPERATION, + native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0], -1)); ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[2], -1)); @@ -611,6 +618,18 @@ TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffers) } TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffersWithCrop) { + // Query to see if the image crop extension exists + EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); + const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS); + size_t cropExtLen = strlen(CROP_EXT_STR); + size_t extsLen = strlen(exts); + bool equal = !strcmp(CROP_EXT_STR, exts); + bool atStart = !strncmp(CROP_EXT_STR " ", exts, cropExtLen+1); + bool atEnd = (cropExtLen+1) < extsLen && + !strcmp(" " CROP_EXT_STR, exts + extsLen - (cropExtLen+1)); + bool inMiddle = strstr(exts, " " CROP_EXT_STR " "); + bool hasEglAndroidImageCrop = equal || atStart || atEnd || inMiddle; + android_native_buffer_t* buf[3]; float mtx[16] = {}; android_native_rect_t crop; @@ -620,7 +639,8 @@ TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffersWi crop.bottom = 5; ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); - ASSERT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 8, 8, 0)); + ASSERT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 8, 8)); + ASSERT_EQ(OK, native_window_set_buffers_format(mANW.get(), 0)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, native_window_set_crop(mANW.get(), &crop)); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1)); @@ -628,15 +648,17 @@ TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffersWi ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 6)); // frees buffers mST->getTransformMatrix(mtx); - // This accounts for the .5 texel shrink for each edge that's included in the - // transform matrix to avoid texturing outside the crop region. - EXPECT_EQ(0.5, mtx[0]); + // If the egl image crop extension is not present, this accounts for the + // .5 texel shrink for each edge that's included in the transform matrix + // to avoid texturing outside the crop region. Otherwise the crop is not + // included in the transform matrix. + EXPECT_EQ(hasEglAndroidImageCrop ? 1 : 0.5, mtx[0]); EXPECT_EQ(0.f, mtx[1]); EXPECT_EQ(0.f, mtx[2]); EXPECT_EQ(0.f, mtx[3]); EXPECT_EQ(0.f, mtx[4]); - EXPECT_EQ(-0.5, mtx[5]); + EXPECT_EQ(hasEglAndroidImageCrop ? -1 : -0.5, mtx[5]); EXPECT_EQ(0.f, mtx[6]); EXPECT_EQ(0.f, mtx[7]); @@ -645,8 +667,8 @@ TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffersWi EXPECT_EQ(1.f, mtx[10]); EXPECT_EQ(0.f, mtx[11]); - EXPECT_EQ(0.0625f, mtx[12]); - EXPECT_EQ(0.5625f, mtx[13]); + EXPECT_EQ(hasEglAndroidImageCrop ? 0 : 0.0625f, mtx[12]); + EXPECT_EQ(hasEglAndroidImageCrop ? 1 : 0.5625f, mtx[13]); EXPECT_EQ(0.f, mtx[14]); EXPECT_EQ(1.f, mtx[15]); } @@ -668,7 +690,8 @@ TEST_F(SurfaceTextureClientTest, QueryFormatAfterSettingWorks) { const int numFmts = (sizeof(fmts) / sizeof(fmts[0])); for (int i = 0; i < numFmts; i++) { int fmt = -1; - ASSERT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 0, 0, fmts[i])); + ASSERT_EQ(OK, native_window_set_buffers_dimensions(anw.get(), 0, 0)); + ASSERT_EQ(OK, native_window_set_buffers_format(anw.get(), fmts[i])); ASSERT_EQ(OK, anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &fmt)); EXPECT_EQ(fmts[i], fmt); } diff --git a/libs/gui/tests/SurfaceTextureFBO_test.cpp b/libs/gui/tests/SurfaceTextureFBO_test.cpp index b165ae6609..c243fc047e 100644 --- a/libs/gui/tests/SurfaceTextureFBO_test.cpp +++ b/libs/gui/tests/SurfaceTextureFBO_test.cpp @@ -27,8 +27,10 @@ TEST_F(SurfaceTextureFBOTest, BlitFromCpuFilledBufferToFbo) { const int texWidth = 64; const int texHeight = 64; - ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(), - texWidth, texHeight, HAL_PIXEL_FORMAT_RGBA_8888)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(), + texWidth, texHeight)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), + HAL_PIXEL_FORMAT_RGBA_8888)); ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(), GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN)); diff --git a/libs/gui/tests/SurfaceTextureGLToGL_test.cpp b/libs/gui/tests/SurfaceTextureGLToGL_test.cpp index f4c796131b..6edbfb87a6 100644 --- a/libs/gui/tests/SurfaceTextureGLToGL_test.cpp +++ b/libs/gui/tests/SurfaceTextureGLToGL_test.cpp @@ -188,10 +188,10 @@ TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceUnrefsBuffers) { // This test should have the only reference to buffer 0. EXPECT_EQ(1, buffers[0]->getStrongCount()); - // The GLConsumer should hold a single reference to buffer 1 in its - // mCurrentBuffer member. All of the references in the slots should have - // been released. - EXPECT_EQ(2, buffers[1]->getStrongCount()); + // The GLConsumer should hold one reference to buffer 1 in its + // mCurrentTextureImage member and another reference in mEglSlots. The third + // reference is in this test. + EXPECT_EQ(3, buffers[1]->getStrongCount()); } TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceAfterAbandonUnrefsBuffers) { @@ -235,14 +235,19 @@ TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceAfterAbandonUnrefsBuffers) { ASSERT_EQ(EGL_SUCCESS, eglGetError()); mProducerEglSurface = EGL_NO_SURFACE; - EXPECT_EQ(1, buffers[0]->getStrongCount()); EXPECT_EQ(1, buffers[1]->getStrongCount()); // Depending on how lazily the GL driver dequeues buffers, we may end up - // with either two or three total buffers. If there are three, make sure - // the last one was properly down-ref'd. + // with either two or three total buffers. If there are three, each entry + // of the buffers array will be unique and there should only be one + // reference (the one in this test). If there are two the first and last + // element in the array will be equal meaning that buffer representing both + // 0 and 2 will have two references (one for 0 and one for 2). if (buffers[2] != buffers[0]) { + EXPECT_EQ(1, buffers[0]->getStrongCount()); EXPECT_EQ(1, buffers[2]->getStrongCount()); + } else { + EXPECT_EQ(2, buffers[0]->getStrongCount()); } } diff --git a/libs/gui/tests/SurfaceTextureGL_test.cpp b/libs/gui/tests/SurfaceTextureGL_test.cpp index fa1e1b78ae..fad133fcb8 100644 --- a/libs/gui/tests/SurfaceTextureGL_test.cpp +++ b/libs/gui/tests/SurfaceTextureGL_test.cpp @@ -28,8 +28,10 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferNpot) { const int texWidth = 64; const int texHeight = 66; - ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(), - texWidth, texHeight, HAL_PIXEL_FORMAT_YV12)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(), + texWidth, texHeight)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), + HAL_PIXEL_FORMAT_YV12)); ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(), GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN)); @@ -74,8 +76,10 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferPow2) { const int texWidth = 64; const int texHeight = 64; - ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(), - texWidth, texHeight, HAL_PIXEL_FORMAT_YV12)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(), + texWidth, texHeight)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), + HAL_PIXEL_FORMAT_YV12)); ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(), GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN)); @@ -120,8 +124,10 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) { const int texWidth = 64; const int texHeight = 66; - ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(), - texWidth, texHeight, HAL_PIXEL_FORMAT_YV12)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(), + texWidth, texHeight)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), + HAL_PIXEL_FORMAT_YV12)); ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(), GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN)); @@ -185,8 +191,10 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) { enum { numFrames = 1024 }; ASSERT_EQ(NO_ERROR, mST->setDefaultMaxBufferCount(2)); - ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(), - texWidth, texHeight, HAL_PIXEL_FORMAT_YV12)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(), + texWidth, texHeight)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), + HAL_PIXEL_FORMAT_YV12)); ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(), GRALLOC_USAGE_SW_WRITE_OFTEN)); @@ -326,8 +334,10 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferNpot) { const int texWidth = 64; const int texHeight = 66; - ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(), - texWidth, texHeight, HAL_PIXEL_FORMAT_RGBA_8888)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(), + texWidth, texHeight)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), + HAL_PIXEL_FORMAT_RGBA_8888)); ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(), GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN)); @@ -368,8 +378,10 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferPow2) { const int texWidth = 64; const int texHeight = 64; - ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(), - texWidth, texHeight, HAL_PIXEL_FORMAT_RGBA_8888)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(), + texWidth, texHeight)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), + HAL_PIXEL_FORMAT_RGBA_8888)); ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(), GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN)); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 5e6aeef356..3f495f8dee 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include "DummyConsumer.h" + #include <gtest/gtest.h> #include <binder/IMemory.h> @@ -155,4 +157,75 @@ TEST_F(SurfaceTest, QueryConsumerUsage) { ASSERT_EQ(TEST_USAGE_FLAGS, flags); } +TEST_F(SurfaceTest, QueryDefaultBuffersDataSpace) { + const android_dataspace TEST_DATASPACE = HAL_DATASPACE_SRGB; + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1); + + cpuConsumer->setDefaultBufferDataSpace(TEST_DATASPACE); + + sp<Surface> s = new Surface(producer); + + sp<ANativeWindow> anw(s); + + android_dataspace dataSpace; + + int err = anw->query(anw.get(), NATIVE_WINDOW_DEFAULT_DATASPACE, + reinterpret_cast<int*>(&dataSpace)); + + ASSERT_EQ(NO_ERROR, err); + ASSERT_EQ(TEST_DATASPACE, dataSpace); +} + +TEST_F(SurfaceTest, SettingGenerationNumber) { + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1); + sp<Surface> surface = new Surface(producer); + sp<ANativeWindow> window(surface); + + // Allocate a buffer with a generation number of 0 + ANativeWindowBuffer* buffer; + int fenceFd; + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fenceFd)); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fenceFd)); + + // Detach the buffer and check its generation number + sp<GraphicBuffer> graphicBuffer; + sp<Fence> fence; + ASSERT_EQ(NO_ERROR, surface->detachNextBuffer(&graphicBuffer, &fence)); + ASSERT_EQ(0U, graphicBuffer->getGenerationNumber()); + + ASSERT_EQ(NO_ERROR, surface->setGenerationNumber(1)); + buffer = static_cast<ANativeWindowBuffer*>(graphicBuffer.get()); + + // This should change the generation number of the GraphicBuffer + ASSERT_EQ(NO_ERROR, surface->attachBuffer(buffer)); + + // Check that the new generation number sticks with the buffer + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, -1)); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fenceFd)); + graphicBuffer = static_cast<GraphicBuffer*>(buffer); + ASSERT_EQ(1U, graphicBuffer->getGenerationNumber()); +} + +TEST_F(SurfaceTest, GetConsumerName) { + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp<DummyConsumer> dummyConsumer(new DummyConsumer); + consumer->consumerConnect(dummyConsumer, false); + consumer->setConsumerName(String8("TestConsumer")); + + sp<Surface> surface = new Surface(producer); + sp<ANativeWindow> window(surface); + native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU); + + EXPECT_STREQ("TestConsumer", surface->getConsumerName().string()); +} + } diff --git a/libs/input/Android.mk b/libs/input/Android.mk index f1921a4e0d..944ac7f653 100644 --- a/libs/input/Android.mk +++ b/libs/input/Android.mk @@ -27,6 +27,7 @@ commonSources := \ deviceSources := \ $(commonSources) \ + IInputFlinger.cpp \ InputTransport.cpp \ VelocityControl.cpp \ VelocityTracker.cpp diff --git a/libs/input/IInputFlinger.cpp b/libs/input/IInputFlinger.cpp new file mode 100644 index 0000000000..e00973149c --- /dev/null +++ b/libs/input/IInputFlinger.cpp @@ -0,0 +1,59 @@ +/* + * 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 <stdint.h> +#include <sys/types.h> + +#include <binder/Parcel.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> + +#include <input/IInputFlinger.h> + + +namespace android { + +class BpInputFlinger : public BpInterface<IInputFlinger> { +public: + BpInputFlinger(const sp<IBinder>& impl) : + BpInterface<IInputFlinger>(impl) { } + + virtual status_t doSomething() { + Parcel data, reply; + data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor()); + remote()->transact(BnInputFlinger::DO_SOMETHING_TRANSACTION, data, &reply); + return reply.readInt32(); + } +}; + +IMPLEMENT_META_INTERFACE(InputFlinger, "android.input.IInputFlinger"); + + +status_t BnInputFlinger::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { + switch(code) { + case DO_SOMETHING_TRANSACTION: { + CHECK_INTERFACE(IInputFlinger, data, reply); + reply->writeInt32(0); + break; + } + default: + return BBinder::onTransact(code, data, reply, flags); + } + return NO_ERROR; +} + +}; diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index cd55ee54bf..b64cb2ca9d 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -216,6 +216,7 @@ void MotionEvent::initialize( int32_t deviceId, int32_t source, int32_t action, + int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, @@ -231,6 +232,7 @@ void MotionEvent::initialize( const PointerCoords* pointerCoords) { InputEvent::initialize(deviceId, source); mAction = action; + mActionButton = actionButton; mFlags = flags; mEdgeFlags = edgeFlags; mMetaState = metaState; @@ -250,6 +252,7 @@ void MotionEvent::initialize( void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) { InputEvent::initialize(other->mDeviceId, other->mSource); mAction = other->mAction; + mActionButton = other->mActionButton; mFlags = other->mFlags; mEdgeFlags = other->mEdgeFlags; mMetaState = other->mMetaState; @@ -429,6 +432,7 @@ status_t MotionEvent::readFromParcel(Parcel* parcel) { mDeviceId = parcel->readInt32(); mSource = parcel->readInt32(); mAction = parcel->readInt32(); + mActionButton = parcel->readInt32(); mFlags = parcel->readInt32(); mEdgeFlags = parcel->readInt32(); mMetaState = parcel->readInt32(); @@ -476,6 +480,7 @@ status_t MotionEvent::writeToParcel(Parcel* parcel) const { parcel->writeInt32(mDeviceId); parcel->writeInt32(mSource); parcel->writeInt32(mAction); + parcel->writeInt32(mActionButton); parcel->writeInt32(mFlags); parcel->writeInt32(mEdgeFlags); parcel->writeInt32(mMetaState); diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp index b11110a18c..d755ed30ac 100644 --- a/libs/input/InputDevice.cpp +++ b/libs/input/InputDevice.cpp @@ -127,28 +127,31 @@ String8 getInputDeviceConfigurationFilePathByName( // --- InputDeviceInfo --- InputDeviceInfo::InputDeviceInfo() { - initialize(-1, 0, -1, InputDeviceIdentifier(), String8(), false); + initialize(-1, 0, -1, InputDeviceIdentifier(), String8(), false, false); } InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) : mId(other.mId), mGeneration(other.mGeneration), mControllerNumber(other.mControllerNumber), mIdentifier(other.mIdentifier), mAlias(other.mAlias), mIsExternal(other.mIsExternal), - mSources(other.mSources), mKeyboardType(other.mKeyboardType), - mKeyCharacterMap(other.mKeyCharacterMap), mHasVibrator(other.mHasVibrator), - mHasButtonUnderPad(other.mHasButtonUnderPad), mMotionRanges(other.mMotionRanges) { + mHasMic(other.mHasMic), mSources(other.mSources), + mKeyboardType(other.mKeyboardType), mKeyCharacterMap(other.mKeyCharacterMap), + mHasVibrator(other.mHasVibrator), mHasButtonUnderPad(other.mHasButtonUnderPad), + mMotionRanges(other.mMotionRanges) { } InputDeviceInfo::~InputDeviceInfo() { } void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t controllerNumber, - const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal) { + const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal, + bool hasMic) { mId = id; mGeneration = generation; mControllerNumber = controllerNumber; mIdentifier = identifier; mAlias = alias; mIsExternal = isExternal; + mHasMic = hasMic; mSources = 0; mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE; mHasVibrator = false; diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 090ee530d1..0382f5788f 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -283,6 +283,7 @@ status_t InputPublisher::publishMotionEvent( int32_t deviceId, int32_t source, int32_t action, + int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, @@ -298,12 +299,12 @@ status_t InputPublisher::publishMotionEvent( const PointerCoords* pointerCoords) { #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, " - "action=0x%x, flags=0x%x, edgeFlags=0x%x, metaState=0x%x, buttonState=0x%x, " - "xOffset=%f, yOffset=%f, " + "action=0x%x, actionButton=0x%08x, flags=0x%x, edgeFlags=0x%x, " + "metaState=0x%x, buttonState=0x%x, xOffset=%f, yOffset=%f, " "xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, " "pointerCount=%" PRIu32, mChannel->getName().string(), seq, - deviceId, source, action, flags, edgeFlags, metaState, buttonState, + deviceId, source, action, actionButton, flags, edgeFlags, metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount); #endif @@ -324,6 +325,7 @@ status_t InputPublisher::publishMotionEvent( msg.body.motion.deviceId = deviceId; msg.body.motion.source = source; msg.body.motion.action = action; + msg.body.motion.actionButton = actionButton; msg.body.motion.flags = flags; msg.body.motion.edgeFlags = edgeFlags; msg.body.motion.metaState = metaState; @@ -907,6 +909,7 @@ void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage msg->body.motion.deviceId, msg->body.motion.source, msg->body.motion.action, + msg->body.motion.actionButton, msg->body.motion.flags, msg->body.motion.edgeFlags, msg->body.motion.metaState, diff --git a/libs/input/tests/Android.mk b/libs/input/tests/Android.mk index 9612a65fed..5bfa3d4808 100644 --- a/libs/input/tests/Android.mk +++ b/libs/input/tests/Android.mk @@ -1,6 +1,5 @@ # Build the unit tests. LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) # Build the unit tests. test_src_files := \ @@ -14,14 +13,10 @@ shared_libraries := \ libutils \ libbinder \ libui \ - libstlport - -static_libraries := \ - libgtest \ - libgtest_main $(foreach file,$(test_src_files), \ $(eval include $(CLEAR_VARS)) \ + $(eval LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk) \ $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \ $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \ $(eval LOCAL_SRC_FILES := $(file)) \ @@ -33,6 +28,7 @@ $(foreach file,$(test_src_files), \ # run. All assertions are static_asserts and will fail during # buildtime if something's wrong. include $(CLEAR_VARS) +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_SRC_FILES := StructLayout_test.cpp LOCAL_MODULE := StructLayout_test LOCAL_CFLAGS := -std=c++11 -O0 diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp index 9105ae523a..3fb1c6df9b 100644 --- a/libs/input/tests/InputEvent_test.cpp +++ b/libs/input/tests/InputEvent_test.cpp @@ -248,7 +248,7 @@ void MotionEventTest::initializeEventWithHistory(MotionEvent* event) { pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 26); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 27); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28); - event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE, + event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE, 0, AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY, X_OFFSET, Y_OFFSET, 2.0f, 2.1f, @@ -557,7 +557,7 @@ TEST_F(MotionEventTest, Transform) { pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, angle); } MotionEvent event; - event.initialize(0, 0, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0, 0, + event.initialize(0, 0, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords); float originalRawX = 0 + 3; float originalRawY = -RADIUS + 2; diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp index de192f1f57..8e69c9cb30 100644 --- a/libs/input/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp @@ -133,6 +133,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { const int32_t deviceId = 1; const int32_t source = AINPUT_SOURCE_TOUCHSCREEN; const int32_t action = AMOTION_EVENT_ACTION_MOVE; + const int32_t actionButton = 0; const int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED; const int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_TOP; const int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON; @@ -163,8 +164,8 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i); } - status = mPublisher->publishMotionEvent(seq, deviceId, source, action, flags, edgeFlags, - metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision, + status = mPublisher->publishMotionEvent(seq, deviceId, source, action, actionButton, + flags, edgeFlags, metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(OK, status) @@ -255,7 +256,7 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessTha PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; - status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; @@ -271,7 +272,7 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountGreater pointerCoords[i].clear(); } - status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp index 83bc6ae0b3..8d73f453e0 100644 --- a/libs/input/tests/StructLayout_test.cpp +++ b/libs/input/tests/StructLayout_test.cpp @@ -51,10 +51,11 @@ void TestInputMessageAlignment() { CHECK_OFFSET(InputMessage::Body::Motion, deviceId, 16); CHECK_OFFSET(InputMessage::Body::Motion, source, 20); CHECK_OFFSET(InputMessage::Body::Motion, action, 24); - CHECK_OFFSET(InputMessage::Body::Motion, flags, 28); - CHECK_OFFSET(InputMessage::Body::Motion, metaState, 32); - CHECK_OFFSET(InputMessage::Body::Motion, buttonState, 36); - CHECK_OFFSET(InputMessage::Body::Motion, edgeFlags, 40); + CHECK_OFFSET(InputMessage::Body::Motion, actionButton, 28); + CHECK_OFFSET(InputMessage::Body::Motion, flags, 32); + CHECK_OFFSET(InputMessage::Body::Motion, metaState, 36); + CHECK_OFFSET(InputMessage::Body::Motion, buttonState, 40); + CHECK_OFFSET(InputMessage::Body::Motion, edgeFlags, 44); CHECK_OFFSET(InputMessage::Body::Motion, downTime, 48); CHECK_OFFSET(InputMessage::Body::Motion, xOffset, 56); CHECK_OFFSET(InputMessage::Body::Motion, yOffset, 60); diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk index eec97be0cb..1ce8626522 100644 --- a/libs/ui/Android.mk +++ b/libs/ui/Android.mk @@ -12,10 +12,28 @@ # See the License for the specific language governing permissions and # limitations under the License. -LOCAL_PATH:= $(call my-dir) +LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES:= \ +LOCAL_CLANG := true +LOCAL_CPPFLAGS := -std=c++1y -Weverything -Werror + +# The static constructors and destructors in this library have not been noted to +# introduce significant overheads +LOCAL_CPPFLAGS += -Wno-exit-time-destructors +LOCAL_CPPFLAGS += -Wno-global-constructors + +# We only care about compiling as C++14 +LOCAL_CPPFLAGS += -Wno-c++98-compat-pedantic + +# We use four-character constants for the GraphicBuffer header, and don't care +# that they're non-portable as long as they're consistent within one execution +LOCAL_CPPFLAGS += -Wno-four-char-constants + +# Don't warn about struct padding +LOCAL_CPPFLAGS += -Wno-padded + +LOCAL_SRC_FILES := \ Fence.cpp \ FramebufferNativeWindow.cpp \ FrameStats.cpp \ @@ -38,7 +56,7 @@ ifneq ($(BOARD_FRAMEBUFFER_FORCE_FORMAT),) LOCAL_CFLAGS += -DFRAMEBUFFER_FORCE_FORMAT=$(BOARD_FRAMEBUFFER_FORCE_FORMAT) endif -LOCAL_MODULE:= libui +LOCAL_MODULE := libui include $(BUILD_SHARED_LIBRARY) diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp index 45e188e52a..1b2f34dfa8 100644 --- a/libs/ui/Fence.cpp +++ b/libs/ui/Fence.cpp @@ -18,10 +18,13 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 - // This is needed for stdint.h to define INT64_MAX in C++ - #define __STDC_LIMIT_MACROS - +// We would eliminate the non-conforming zero-length array, but we can't since +// this is effectively included from the Linux kernel +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wzero-length-array" #include <sync/sync.h> +#pragma clang diagnostic pop + #include <ui/Fence.h> #include <unistd.h> #include <utils/Log.h> @@ -45,7 +48,7 @@ Fence::~Fence() { } } -status_t Fence::wait(unsigned int timeout) { +status_t Fence::wait(int timeout) { ATRACE_CALL(); if (mFenceFd == -1) { return NO_ERROR; @@ -59,7 +62,7 @@ status_t Fence::waitForever(const char* logname) { if (mFenceFd == -1) { return NO_ERROR; } - unsigned int warningTimeout = 3000; + int warningTimeout = 3000; int err = sync_wait(mFenceFd, warningTimeout); if (err < 0 && errno == ETIME) { ALOGE("%s: fence %d didn't signal in %u ms", logname, mFenceFd, @@ -138,7 +141,9 @@ status_t Fence::flatten(void*& buffer, size_t& size, int*& fds, size_t& count) c if (size < getFlattenedSize() || count < getFdCount()) { return NO_MEMORY; } - FlattenableUtils::write(buffer, size, (uint32_t)getFdCount()); + // Cast to uint32_t since the size of a size_t can vary between 32- and + // 64-bit processes + FlattenableUtils::write(buffer, size, static_cast<uint32_t>(getFdCount())); if (isValid()) { *fds++ = mFenceFd; count--; diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp index 918f2e7567..3ead25cfe8 100644 --- a/libs/ui/FramebufferNativeWindow.cpp +++ b/libs/ui/FramebufferNativeWindow.cpp @@ -1,17 +1,17 @@ -/* +/* ** ** Copyright 2007 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 +** 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 +** 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 +** 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. */ @@ -29,7 +29,9 @@ #include <ui/ANativeObjectBase.h> #include <ui/Fence.h> +#define INCLUDED_FROM_FRAMEBUFFER_NATIVE_WINDOW_CPP #include <ui/FramebufferNativeWindow.h> +#undef INCLUDED_FROM_FRAMEBUFFER_NATIVE_WINDOW_CPP #include <ui/Rect.h> #include <EGL/egl.h> @@ -41,11 +43,11 @@ namespace android { // ---------------------------------------------------------------------------- -class NativeBuffer +class NativeBuffer final : public ANativeObjectBase< - ANativeWindowBuffer, - NativeBuffer, - LightRefBase<NativeBuffer> > + ANativeWindowBuffer, + NativeBuffer, + LightRefBase<NativeBuffer>> { public: NativeBuffer(int w, int h, int f, int u) : BASE() { @@ -55,43 +57,41 @@ public: ANativeWindowBuffer::usage = u; } private: - friend class LightRefBase<NativeBuffer>; - ~NativeBuffer() { }; // this class cannot be overloaded + friend class LightRefBase<NativeBuffer>; }; /* * This implements the (main) framebuffer management. This class is used * mostly by SurfaceFlinger, but also by command line GL application. - * + * * In fact this is an implementation of ANativeWindow on top of * the framebuffer. - * - * Currently it is pretty simple, it manages only two buffers (the front and + * + * Currently it is pretty simple, it manages only two buffers (the front and * back buffer). - * + * */ -FramebufferNativeWindow::FramebufferNativeWindow() +FramebufferNativeWindow::FramebufferNativeWindow() : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false) { hw_module_t const* module; if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) { - int stride; int err; int i; err = framebuffer_open(module, &fbDev); ALOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err)); - + err = gralloc_open(module, &grDev); ALOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err)); // bail out if we can't initialize the modules if (!fbDev || !grDev) return; - + mUpdateOnDemand = (fbDev->setUpdateRect != 0); - + // initialize the buffer FIFO if(fbDev->numFramebuffers >= MIN_NUM_FRAME_BUFFERS && fbDev->numFramebuffers <= MAX_NUM_FRAME_BUFFERS){ @@ -114,36 +114,37 @@ FramebufferNativeWindow::FramebufferNativeWindow() *((uint32_t *)&fbDev->format) = FRAMEBUFFER_FORCE_FORMAT; #endif - for (i = 0; i < mNumBuffers; i++) - { - buffers[i] = new NativeBuffer( - fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB); + for (i = 0; i < mNumBuffers; i++) { + buffers[i] = new NativeBuffer( + static_cast<int>(fbDev->width), + static_cast<int>(fbDev->height), + fbDev->format, GRALLOC_USAGE_HW_FB); } - for (i = 0; i < mNumBuffers; i++) - { - err = grDev->alloc(grDev, - fbDev->width, fbDev->height, fbDev->format, - GRALLOC_USAGE_HW_FB, &buffers[i]->handle, &buffers[i]->stride); - - ALOGE_IF(err, "fb buffer %d allocation failed w=%d, h=%d, err=%s", - i, fbDev->width, fbDev->height, strerror(-err)); - - if (err) - { - mNumBuffers = i; - mNumFreeBuffers = i; - mBufferHead = mNumBuffers-1; - break; - } + for (i = 0; i < mNumBuffers; i++) { + err = grDev->alloc(grDev, + static_cast<int>(fbDev->width), + static_cast<int>(fbDev->height), + fbDev->format, GRALLOC_USAGE_HW_FB, + &buffers[i]->handle, &buffers[i]->stride); + + ALOGE_IF(err, "fb buffer %d allocation failed w=%d, h=%d, err=%s", + i, fbDev->width, fbDev->height, strerror(-err)); + + if (err) { + mNumBuffers = i; + mNumFreeBuffers = i; + mBufferHead = mNumBuffers-1; + break; + } } - const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags; + const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags; const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi; const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi; - const_cast<int&>(ANativeWindow::minSwapInterval) = + const_cast<int&>(ANativeWindow::minSwapInterval) = fbDev->minSwapInterval; - const_cast<int&>(ANativeWindow::maxSwapInterval) = + const_cast<int&>(ANativeWindow::maxSwapInterval) = fbDev->maxSwapInterval; } else { ALOGE("Couldn't get gralloc module"); @@ -160,7 +161,7 @@ FramebufferNativeWindow::FramebufferNativeWindow() ANativeWindow::queueBuffer_DEPRECATED = queueBuffer_DEPRECATED; } -FramebufferNativeWindow::~FramebufferNativeWindow() +FramebufferNativeWindow::~FramebufferNativeWindow() { if (grDev) { for(int i = 0; i < mNumBuffers; i++) { @@ -176,7 +177,7 @@ FramebufferNativeWindow::~FramebufferNativeWindow() } } -status_t FramebufferNativeWindow::setUpdateRectangle(const Rect& r) +status_t FramebufferNativeWindow::setUpdateRectangle(const Rect& r) { if (!mUpdateOnDemand) { return INVALID_OPERATION; @@ -193,7 +194,7 @@ status_t FramebufferNativeWindow::compositionComplete() } int FramebufferNativeWindow::setSwapInterval( - ANativeWindow* window, int interval) + ANativeWindow* window, int interval) { framebuffer_device_t* fb = getSelf(window)->fbDev; return fb->setSwapInterval(fb, interval); @@ -217,7 +218,7 @@ int FramebufferNativeWindow::getCurrentBufferIndex() const return index; } -int FramebufferNativeWindow::dequeueBuffer_DEPRECATED(ANativeWindow* window, +int FramebufferNativeWindow::dequeueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer** buffer) { int fenceFd = -1; @@ -232,12 +233,11 @@ int FramebufferNativeWindow::dequeueBuffer_DEPRECATED(ANativeWindow* window, return result; } -int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window, +int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer, int* fenceFd) { FramebufferNativeWindow* self = getSelf(window); Mutex::Autolock _l(self->mutex); - framebuffer_device_t* fb = self->fbDev; int index = self->mBufferHead++; if (self->mBufferHead >= self->mNumBuffers) @@ -247,7 +247,7 @@ int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window, while (self->mNumFreeBuffers < 2) { self->mCondition.wait(self->mutex); } - ALOG_ASSERT(self->buffers[index] != self->front); + ALOG_ASSERT(self->buffers[index] != self->front, ""); // get this buffer self->mNumFreeBuffers--; @@ -259,19 +259,19 @@ int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window, return 0; } -int FramebufferNativeWindow::lockBuffer_DEPRECATED(ANativeWindow* /*window*/, +int FramebufferNativeWindow::lockBuffer_DEPRECATED(ANativeWindow* /*window*/, ANativeWindowBuffer* /*buffer*/) { return NO_ERROR; } -int FramebufferNativeWindow::queueBuffer_DEPRECATED(ANativeWindow* window, +int FramebufferNativeWindow::queueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer) { return queueBuffer(window, buffer, -1); } -int FramebufferNativeWindow::queueBuffer(ANativeWindow* window, +int FramebufferNativeWindow::queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd) { FramebufferNativeWindow* self = getSelf(window); @@ -282,7 +282,6 @@ int FramebufferNativeWindow::queueBuffer(ANativeWindow* window, sp<Fence> fence(new Fence(fenceFd)); fence->wait(Fence::TIMEOUT_NEVER); - const int index = self->mCurrentBufferIndex; int res = fb->post(fb, handle); self->front = static_cast<NativeBuffer*>(buffer); self->mNumFreeBuffers++; @@ -291,17 +290,17 @@ int FramebufferNativeWindow::queueBuffer(ANativeWindow* window, } int FramebufferNativeWindow::query(const ANativeWindow* window, - int what, int* value) + int what, int* value) { const FramebufferNativeWindow* self = getSelf(window); Mutex::Autolock _l(self->mutex); framebuffer_device_t* fb = self->fbDev; switch (what) { case NATIVE_WINDOW_WIDTH: - *value = fb->width; + *value = static_cast<int>(fb->width); return NO_ERROR; case NATIVE_WINDOW_HEIGHT: - *value = fb->height; + *value = static_cast<int>(fb->height); return NO_ERROR; case NATIVE_WINDOW_FORMAT: *value = fb->format; @@ -313,10 +312,10 @@ int FramebufferNativeWindow::query(const ANativeWindow* window, *value = 0; return NO_ERROR; case NATIVE_WINDOW_DEFAULT_WIDTH: - *value = fb->width; + *value = static_cast<int>(fb->width); return NO_ERROR; case NATIVE_WINDOW_DEFAULT_HEIGHT: - *value = fb->height; + *value = static_cast<int>(fb->height); return NO_ERROR; case NATIVE_WINDOW_TRANSFORM_HINT: *value = 0; @@ -357,7 +356,8 @@ int FramebufferNativeWindow::perform(ANativeWindow* /*window*/, }; // namespace android // ---------------------------------------------------------------------------- -using namespace android; +using android::sp; +using android::FramebufferNativeWindow; EGLNativeWindowType android_createDisplaySurface(void) { @@ -368,5 +368,5 @@ EGLNativeWindowType android_createDisplaySurface(void) sp<FramebufferNativeWindow> ref(w); return NULL; } - return (EGLNativeWindowType)w; + return static_cast<EGLNativeWindowType>(w); } diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index 3ae88408d6..e55db30f8e 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -45,40 +45,40 @@ GraphicBuffer::GraphicBuffer() : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()), mInitCheck(NO_ERROR), mId(getUniqueId()) { - width = - height = - stride = - format = + width = + height = + stride = + format = usage = 0; handle = NULL; } -GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h, - PixelFormat reqFormat, uint32_t reqUsage) +GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight, + PixelFormat inFormat, uint32_t inUsage) : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()), mInitCheck(NO_ERROR), mId(getUniqueId()) { - width = - height = - stride = - format = + width = + height = + stride = + format = usage = 0; handle = NULL; - mInitCheck = initSize(w, h, reqFormat, reqUsage); + mInitCheck = initSize(inWidth, inHeight, inFormat, inUsage); } -GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h, - PixelFormat inFormat, uint32_t inUsage, - uint32_t inStride, native_handle_t* inHandle, bool keepOwnership) +GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight, + PixelFormat inFormat, uint32_t inUsage, uint32_t inStride, + native_handle_t* inHandle, bool keepOwnership) : BASE(), mOwner(keepOwnership ? ownHandle : ownNone), mBufferMapper(GraphicBufferMapper::get()), mInitCheck(NO_ERROR), mId(getUniqueId()) { - width = w; - height = h; - stride = inStride; + width = static_cast<int>(inWidth); + height = static_cast<int>(inHeight); + stride = static_cast<int>(inStride); format = inFormat; - usage = inUsage; + usage = static_cast<int>(inUsage); handle = inHandle; } @@ -116,7 +116,7 @@ void GraphicBuffer::free_handle() } status_t GraphicBuffer::initCheck() const { - return mInitCheck; + return static_cast<status_t>(mInitCheck); } void GraphicBuffer::dumpAllocationsToSystemLog() @@ -131,13 +131,17 @@ ANativeWindowBuffer* GraphicBuffer::getNativeBuffer() const const_cast<GraphicBuffer*>(this)); } -status_t GraphicBuffer::reallocate(uint32_t w, uint32_t h, PixelFormat f, - uint32_t reqUsage) +status_t GraphicBuffer::reallocate(uint32_t inWidth, uint32_t inHeight, + PixelFormat inFormat, uint32_t inUsage) { if (mOwner != ownData) return INVALID_OPERATION; - if (handle && w==width && h==height && f==format && reqUsage==usage) + if (handle && + static_cast<int>(inWidth) == width && + static_cast<int>(inHeight) == height && + inFormat == format && + static_cast<int>(inUsage) == usage) return NO_ERROR; if (handle) { @@ -145,61 +149,74 @@ status_t GraphicBuffer::reallocate(uint32_t w, uint32_t h, PixelFormat f, allocator.free(handle); handle = 0; } - return initSize(w, h, f, reqUsage); + return initSize(inWidth, inHeight, inFormat, inUsage); } -status_t GraphicBuffer::initSize(uint32_t w, uint32_t h, PixelFormat format, - uint32_t reqUsage) +bool GraphicBuffer::needsReallocation(uint32_t inWidth, uint32_t inHeight, + PixelFormat inFormat, uint32_t inUsage) +{ + if (static_cast<int>(inWidth) != width) return true; + if (static_cast<int>(inHeight) != height) return true; + if (inFormat != format) return true; + if ((static_cast<uint32_t>(usage) & inUsage) != inUsage) return true; + return false; +} + +status_t GraphicBuffer::initSize(uint32_t inWidth, uint32_t inHeight, + PixelFormat inFormat, uint32_t inUsage) { GraphicBufferAllocator& allocator = GraphicBufferAllocator::get(); - status_t err = allocator.alloc(w, h, format, reqUsage, &handle, &stride); + uint32_t outStride = 0; + status_t err = allocator.alloc(inWidth, inHeight, inFormat, inUsage, + &handle, &outStride); if (err == NO_ERROR) { - this->width = w; - this->height = h; - this->format = format; - this->usage = reqUsage; + width = static_cast<int>(inWidth); + height = static_cast<int>(inHeight); + format = inFormat; + usage = static_cast<int>(inUsage); + stride = static_cast<int>(outStride); } return err; } -status_t GraphicBuffer::lock(uint32_t usage, void** vaddr) +status_t GraphicBuffer::lock(uint32_t inUsage, void** vaddr) { const Rect lockBounds(width, height); - status_t res = lock(usage, lockBounds, vaddr); + status_t res = lock(inUsage, lockBounds, vaddr); return res; } -status_t GraphicBuffer::lock(uint32_t usage, const Rect& rect, void** vaddr) +status_t GraphicBuffer::lock(uint32_t inUsage, const Rect& rect, void** vaddr) { - if (rect.left < 0 || rect.right > this->width || - rect.top < 0 || rect.bottom > this->height) { + if (rect.left < 0 || rect.right > width || + rect.top < 0 || rect.bottom > height) { ALOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)", - rect.left, rect.top, rect.right, rect.bottom, - this->width, this->height); + rect.left, rect.top, rect.right, rect.bottom, + width, height); return BAD_VALUE; } - status_t res = getBufferMapper().lock(handle, usage, rect, vaddr); + status_t res = getBufferMapper().lock(handle, inUsage, rect, vaddr); return res; } -status_t GraphicBuffer::lockYCbCr(uint32_t usage, android_ycbcr *ycbcr) +status_t GraphicBuffer::lockYCbCr(uint32_t inUsage, android_ycbcr* ycbcr) { const Rect lockBounds(width, height); - status_t res = lockYCbCr(usage, lockBounds, ycbcr); + status_t res = lockYCbCr(inUsage, lockBounds, ycbcr); return res; } -status_t GraphicBuffer::lockYCbCr(uint32_t usage, const Rect& rect, - android_ycbcr *ycbcr) +status_t GraphicBuffer::lockYCbCr(uint32_t inUsage, const Rect& rect, + android_ycbcr* ycbcr) { - if (rect.left < 0 || rect.right > this->width || - rect.top < 0 || rect.bottom > this->height) { + if (rect.left < 0 || rect.right > width || + rect.top < 0 || rect.bottom > height) { ALOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)", rect.left, rect.top, rect.right, rect.bottom, - this->width, this->height); + width, height); return BAD_VALUE; } - status_t res = getBufferMapper().lockYCbCr(handle, usage, rect, ycbcr); + status_t res = getBufferMapper().lockYCbCr(handle, inUsage, rect, ycbcr); return res; } @@ -209,43 +226,48 @@ status_t GraphicBuffer::unlock() return res; } -status_t GraphicBuffer::lockAsync(uint32_t usage, void** vaddr, int fenceFd) +status_t GraphicBuffer::lockAsync(uint32_t inUsage, void** vaddr, int fenceFd) { const Rect lockBounds(width, height); - status_t res = lockAsync(usage, lockBounds, vaddr, fenceFd); + status_t res = lockAsync(inUsage, lockBounds, vaddr, fenceFd); return res; } -status_t GraphicBuffer::lockAsync(uint32_t usage, const Rect& rect, void** vaddr, int fenceFd) +status_t GraphicBuffer::lockAsync(uint32_t inUsage, const Rect& rect, + void** vaddr, int fenceFd) { - if (rect.left < 0 || rect.right > this->width || - rect.top < 0 || rect.bottom > this->height) { + if (rect.left < 0 || rect.right > width || + rect.top < 0 || rect.bottom > height) { ALOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)", rect.left, rect.top, rect.right, rect.bottom, - this->width, this->height); + width, height); return BAD_VALUE; } - status_t res = getBufferMapper().lockAsync(handle, usage, rect, vaddr, fenceFd); + status_t res = getBufferMapper().lockAsync(handle, inUsage, rect, vaddr, + fenceFd); return res; } -status_t GraphicBuffer::lockAsyncYCbCr(uint32_t usage, android_ycbcr *ycbcr, int fenceFd) +status_t GraphicBuffer::lockAsyncYCbCr(uint32_t inUsage, android_ycbcr* ycbcr, + int fenceFd) { const Rect lockBounds(width, height); - status_t res = lockAsyncYCbCr(usage, lockBounds, ycbcr, fenceFd); + status_t res = lockAsyncYCbCr(inUsage, lockBounds, ycbcr, fenceFd); return res; } -status_t GraphicBuffer::lockAsyncYCbCr(uint32_t usage, const Rect& rect, android_ycbcr *ycbcr, int fenceFd) +status_t GraphicBuffer::lockAsyncYCbCr(uint32_t inUsage, const Rect& rect, + android_ycbcr* ycbcr, int fenceFd) { - if (rect.left < 0 || rect.right > this->width || - rect.top < 0 || rect.bottom > this->height) { + if (rect.left < 0 || rect.right > width || + rect.top < 0 || rect.bottom > height) { ALOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)", rect.left, rect.top, rect.right, rect.bottom, - this->width, this->height); + width, height); return BAD_VALUE; } - status_t res = getBufferMapper().lockAsyncYCbCr(handle, usage, rect, ycbcr, fenceFd); + status_t res = getBufferMapper().lockAsyncYCbCr(handle, inUsage, rect, + ycbcr, fenceFd); return res; } @@ -256,11 +278,11 @@ status_t GraphicBuffer::unlockAsync(int *fenceFd) } size_t GraphicBuffer::getFlattenedSize() const { - return (10 + (handle ? handle->numInts : 0))*sizeof(int); + return static_cast<size_t>(11 + (handle ? handle->numInts : 0)) * sizeof(int); } size_t GraphicBuffer::getFdCount() const { - return handle ? handle->numFds : 0; + return static_cast<size_t>(handle ? handle->numFds : 0); } status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const { @@ -279,22 +301,24 @@ status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& buf[5] = usage; buf[6] = static_cast<int32_t>(mId >> 32); buf[7] = static_cast<int32_t>(mId & 0xFFFFFFFFull); - buf[8] = 0; + buf[8] = static_cast<int32_t>(mGenerationNumber); buf[9] = 0; + buf[10] = 0; if (handle) { - buf[8] = handle->numFds; - buf[9] = handle->numInts; - native_handle_t const* const h = handle; - memcpy(fds, h->data, h->numFds*sizeof(int)); - memcpy(&buf[10], h->data + h->numFds, h->numInts*sizeof(int)); + buf[9] = handle->numFds; + buf[10] = handle->numInts; + memcpy(fds, handle->data, + static_cast<size_t>(handle->numFds) * sizeof(int)); + memcpy(&buf[11], handle->data + handle->numFds, + static_cast<size_t>(handle->numInts) * sizeof(int)); } - buffer = reinterpret_cast<void*>(static_cast<int*>(buffer) + sizeNeeded); + buffer = static_cast<void*>(static_cast<uint8_t*>(buffer) + sizeNeeded); size -= sizeNeeded; if (handle) { fds += handle->numFds; - count -= handle->numFds; + count -= static_cast<size_t>(handle->numFds); } return NO_ERROR; @@ -302,28 +326,28 @@ status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& status_t GraphicBuffer::unflatten( void const*& buffer, size_t& size, int const*& fds, size_t& count) { - if (size < 8*sizeof(int)) return NO_MEMORY; + if (size < 11 * sizeof(int)) return NO_MEMORY; int const* buf = static_cast<int const*>(buffer); if (buf[0] != 'GBFR') return BAD_TYPE; - const size_t numFds = buf[8]; - const size_t numInts = buf[9]; + const size_t numFds = static_cast<size_t>(buf[9]); + const size_t numInts = static_cast<size_t>(buf[10]); // Limit the maxNumber to be relatively small. The number of fds or ints // should not come close to this number, and the number itself was simply // chosen to be high enough to not cause issues and low enough to prevent // overflow problems. const size_t maxNumber = 4096; - if (numFds >= maxNumber || numInts >= (maxNumber - 10)) { + if (numFds >= maxNumber || numInts >= (maxNumber - 11)) { width = height = stride = format = usage = 0; handle = NULL; - ALOGE("unflatten: numFds or numInts is too large: %d, %d", + ALOGE("unflatten: numFds or numInts is too large: %zd, %zd", numFds, numInts); return BAD_VALUE; } - const size_t sizeNeeded = (10 + numInts) * sizeof(int); + const size_t sizeNeeded = (11 + numInts) * sizeof(int); if (size < sizeNeeded) return NO_MEMORY; size_t fdCountNeeded = numFds; @@ -340,15 +364,16 @@ status_t GraphicBuffer::unflatten( stride = buf[3]; format = buf[4]; usage = buf[5]; - native_handle* h = native_handle_create(numFds, numInts); + native_handle* h = native_handle_create( + static_cast<int>(numFds), static_cast<int>(numInts)); if (!h) { width = height = stride = format = usage = 0; handle = NULL; ALOGE("unflatten: native_handle_create failed"); return NO_MEMORY; } - memcpy(h->data, fds, numFds*sizeof(int)); - memcpy(h->data + numFds, &buf[10], numInts*sizeof(int)); + memcpy(h->data, fds, numFds * sizeof(int)); + memcpy(h->data + numFds, &buf[11], numInts * sizeof(int)); handle = h; } else { width = height = stride = format = usage = 0; @@ -358,6 +383,8 @@ status_t GraphicBuffer::unflatten( mId = static_cast<uint64_t>(buf[6]) << 32; mId |= static_cast<uint32_t>(buf[7]); + mGenerationNumber = static_cast<uint32_t>(buf[8]); + mOwner = ownHandle; if (handle != 0) { @@ -371,7 +398,7 @@ status_t GraphicBuffer::unflatten( } } - buffer = reinterpret_cast<void const*>(static_cast<int const*>(buffer) + sizeNeeded); + buffer = static_cast<void const*>(static_cast<uint8_t const*>(buffer) + sizeNeeded); size -= sizeNeeded; fds += numFds; count -= numFds; diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp index ff550d961e..9b265af2b4 100644 --- a/libs/ui/GraphicBufferAllocator.cpp +++ b/libs/ui/GraphicBufferAllocator.cpp @@ -1,17 +1,17 @@ -/* +/* ** ** Copyright 2009, 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 +** 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 +** 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 +** 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. */ @@ -66,11 +66,11 @@ void GraphicBufferAllocator::dump(String8& result) const if (rec.size) { snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %8X | 0x%08x\n", list.keyAt(i), rec.size/1024.0f, - rec.w, rec.s, rec.h, rec.format, rec.usage); + rec.width, rec.stride, rec.height, rec.format, rec.usage); } else { snprintf(buffer, SIZE, "%10p: unknown | %4u (%4u) x %4u | %8X | 0x%08x\n", list.keyAt(i), - rec.w, rec.s, rec.h, rec.format, rec.usage); + rec.width, rec.stride, rec.height, rec.format, rec.usage); } result.append(buffer); total += rec.size; @@ -90,39 +90,43 @@ void GraphicBufferAllocator::dumpToSystemLog() ALOGD("%s", s.string()); } -status_t GraphicBufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat format, - int usage, buffer_handle_t* handle, int32_t* stride) +status_t GraphicBufferAllocator::alloc(uint32_t width, uint32_t height, + PixelFormat format, uint32_t usage, buffer_handle_t* handle, + uint32_t* stride) { ATRACE_CALL(); + // make sure to not allocate a N x 0 or 0 x N buffer, since this is // allowed from an API stand-point allocate a 1x1 buffer instead. - if (!w || !h) - w = h = 1; + if (!width || !height) + width = height = 1; // we have a h/w allocator and h/w buffer is requested - status_t err; - - err = mAllocDev->alloc(mAllocDev, w, h, format, usage, handle, stride); + status_t err; + + // Filter out any usage bits that should not be passed to the gralloc module + usage &= GRALLOC_USAGE_ALLOC_MASK; + + int outStride = 0; + err = mAllocDev->alloc(mAllocDev, static_cast<int>(width), + static_cast<int>(height), format, static_cast<int>(usage), handle, + &outStride); + *stride = static_cast<uint32_t>(outStride); ALOGW_IF(err, "alloc(%u, %u, %d, %08x, ...) failed %d (%s)", - w, h, format, usage, err, strerror(-err)); - + width, height, format, usage, err, strerror(-err)); + if (err == NO_ERROR) { Mutex::Autolock _l(sLock); KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList); - int bpp = bytesPerPixel(format); - if (bpp < 0) { - // probably a HAL custom format. in any case, we don't know - // what its pixel size is. - bpp = 0; - } + uint32_t bpp = bytesPerPixel(format); alloc_rec_t rec; - rec.w = w; - rec.h = h; - rec.s = *stride; + rec.width = width; + rec.height = height; + rec.stride = *stride; rec.format = format; rec.usage = usage; - rec.size = h * stride[0] * bpp; + rec.size = static_cast<size_t>(height * (*stride) * bpp); list.add(*handle, rec); } diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp index e949b0c9b1..90a1c1110d 100644 --- a/libs/ui/GraphicBufferMapper.cpp +++ b/libs/ui/GraphicBufferMapper.cpp @@ -20,7 +20,12 @@ #include <stdint.h> #include <errno.h> +// We would eliminate the non-conforming zero-length array, but we can't since +// this is effectively included from the Linux kernel +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wzero-length-array" #include <sync/sync.h> +#pragma clang diagnostic pop #include <utils/Errors.h> #include <utils/Log.h> @@ -44,7 +49,7 @@ GraphicBufferMapper::GraphicBufferMapper() int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module); ALOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID); if (err == 0) { - mAllocMod = (gralloc_module_t const *)module; + mAllocMod = reinterpret_cast<gralloc_module_t const *>(module); } } @@ -72,13 +77,13 @@ status_t GraphicBufferMapper::unregisterBuffer(buffer_handle_t handle) return err; } -status_t GraphicBufferMapper::lock(buffer_handle_t handle, - int usage, const Rect& bounds, void** vaddr) +status_t GraphicBufferMapper::lock(buffer_handle_t handle, + uint32_t usage, const Rect& bounds, void** vaddr) { ATRACE_CALL(); status_t err; - err = mAllocMod->lock(mAllocMod, handle, usage, + err = mAllocMod->lock(mAllocMod, handle, static_cast<int>(usage), bounds.left, bounds.top, bounds.width(), bounds.height(), vaddr); @@ -87,7 +92,7 @@ status_t GraphicBufferMapper::lock(buffer_handle_t handle, } status_t GraphicBufferMapper::lockYCbCr(buffer_handle_t handle, - int usage, const Rect& bounds, android_ycbcr *ycbcr) + uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr) { ATRACE_CALL(); status_t err; @@ -96,7 +101,7 @@ status_t GraphicBufferMapper::lockYCbCr(buffer_handle_t handle, return -EINVAL; // do not log failure } - err = mAllocMod->lock_ycbcr(mAllocMod, handle, usage, + err = mAllocMod->lock_ycbcr(mAllocMod, handle, static_cast<int>(usage), bounds.left, bounds.top, bounds.width(), bounds.height(), ycbcr); @@ -116,19 +121,21 @@ status_t GraphicBufferMapper::unlock(buffer_handle_t handle) } status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle, - int usage, const Rect& bounds, void** vaddr, int fenceFd) + uint32_t usage, const Rect& bounds, void** vaddr, int fenceFd) { ATRACE_CALL(); status_t err; if (mAllocMod->common.module_api_version >= GRALLOC_MODULE_API_VERSION_0_3) { - err = mAllocMod->lockAsync(mAllocMod, handle, usage, + err = mAllocMod->lockAsync(mAllocMod, handle, static_cast<int>(usage), bounds.left, bounds.top, bounds.width(), bounds.height(), vaddr, fenceFd); } else { - sync_wait(fenceFd, -1); - close(fenceFd); - err = mAllocMod->lock(mAllocMod, handle, usage, + if (fenceFd >= 0) { + sync_wait(fenceFd, -1); + close(fenceFd); + } + err = mAllocMod->lock(mAllocMod, handle, static_cast<int>(usage), bounds.left, bounds.top, bounds.width(), bounds.height(), vaddr); } @@ -138,23 +145,28 @@ status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle, } status_t GraphicBufferMapper::lockAsyncYCbCr(buffer_handle_t handle, - int usage, const Rect& bounds, android_ycbcr *ycbcr, int fenceFd) + uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr, int fenceFd) { ATRACE_CALL(); status_t err; if (mAllocMod->common.module_api_version >= GRALLOC_MODULE_API_VERSION_0_3 && mAllocMod->lockAsync_ycbcr != NULL) { - err = mAllocMod->lockAsync_ycbcr(mAllocMod, handle, usage, - bounds.left, bounds.top, bounds.width(), bounds.height(), - ycbcr, fenceFd); + err = mAllocMod->lockAsync_ycbcr(mAllocMod, handle, + static_cast<int>(usage), bounds.left, bounds.top, + bounds.width(), bounds.height(), ycbcr, fenceFd); } else if (mAllocMod->lock_ycbcr != NULL) { - sync_wait(fenceFd, -1); - close(fenceFd); - err = mAllocMod->lock_ycbcr(mAllocMod, handle, usage, + if (fenceFd >= 0) { + sync_wait(fenceFd, -1); + close(fenceFd); + } + err = mAllocMod->lock_ycbcr(mAllocMod, handle, static_cast<int>(usage), bounds.left, bounds.top, bounds.width(), bounds.height(), ycbcr); } else { + if (fenceFd >= 0) { + close(fenceFd); + } return -EINVAL; // do not log failure } diff --git a/libs/ui/PixelFormat.cpp b/libs/ui/PixelFormat.cpp index 5ce7fba54e..cab1dde3fa 100644 --- a/libs/ui/PixelFormat.cpp +++ b/libs/ui/PixelFormat.cpp @@ -15,19 +15,16 @@ */ #include <ui/PixelFormat.h> -#include <hardware/hardware.h> // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- -ssize_t bytesPerPixel(PixelFormat format) { +uint32_t bytesPerPixel(PixelFormat format) { switch (format) { case PIXEL_FORMAT_RGBA_8888: case PIXEL_FORMAT_RGBX_8888: case PIXEL_FORMAT_BGRA_8888: - case PIXEL_FORMAT_sRGB_A_8888: - case PIXEL_FORMAT_sRGB_X_8888: return 4; case PIXEL_FORMAT_RGB_888: return 3; @@ -36,10 +33,10 @@ ssize_t bytesPerPixel(PixelFormat format) { case PIXEL_FORMAT_RGBA_4444: return 2; } - return BAD_VALUE; + return 0; } -ssize_t bitsPerPixel(PixelFormat format) { +uint32_t bitsPerPixel(PixelFormat format) { switch (format) { case PIXEL_FORMAT_RGBA_8888: case PIXEL_FORMAT_RGBX_8888: @@ -52,10 +49,9 @@ ssize_t bitsPerPixel(PixelFormat format) { case PIXEL_FORMAT_RGBA_4444: return 16; } - return BAD_VALUE; + return 0; } // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- - diff --git a/libs/ui/Rect.cpp b/libs/ui/Rect.cpp index b480f3a62b..dcce21f15a 100644 --- a/libs/ui/Rect.cpp +++ b/libs/ui/Rect.cpp @@ -19,6 +19,8 @@ namespace android { +const Rect Rect::INVALID_RECT{0, 0, -1, -1}; + static inline int32_t min(int32_t a, int32_t b) { return (a < b) ? a : b; } diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp index fa812f4dae..cfed7a984c 100644 --- a/libs/ui/Region.cpp +++ b/libs/ui/Region.cpp @@ -53,6 +53,8 @@ enum { direction_RTL }; +const Region Region::INVALID_REGION(Rect::INVALID_RECT); + // ---------------------------------------------------------------------------- Region::Region() { @@ -102,8 +104,8 @@ static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, current--; } while (current->top == lastTop && current >= begin); - unsigned int beginLastSpan = -1; - unsigned int endLastSpan = -1; + int beginLastSpan = -1; + int endLastSpan = -1; int top = -1; int bottom = -1; @@ -118,7 +120,7 @@ static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, } else { beginLastSpan = endLastSpan + 1; } - endLastSpan = dst.size() - 1; + endLastSpan = static_cast<int>(dst.size()) - 1; top = current->top; bottom = current->bottom; @@ -126,43 +128,46 @@ static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, int left = current->left; int right = current->right; - for (unsigned int prevIndex = beginLastSpan; prevIndex <= endLastSpan; prevIndex++) { - const Rect* prev = &dst[prevIndex]; + for (int prevIndex = beginLastSpan; prevIndex <= endLastSpan; prevIndex++) { + // prevIndex can't be -1 here because if endLastSpan is set to a + // value greater than -1 (allowing the loop to execute), + // beginLastSpan (and therefore prevIndex) will also be increased + const Rect prev = dst[static_cast<size_t>(prevIndex)]; if (spanDirection == direction_RTL) { // iterating over previous span RTL, quit if it's too far left - if (prev->right <= left) break; + if (prev.right <= left) break; - if (prev->right > left && prev->right < right) { - dst.add(Rect(prev->right, top, right, bottom)); - right = prev->right; + if (prev.right > left && prev.right < right) { + dst.add(Rect(prev.right, top, right, bottom)); + right = prev.right; } - if (prev->left > left && prev->left < right) { - dst.add(Rect(prev->left, top, right, bottom)); - right = prev->left; + if (prev.left > left && prev.left < right) { + dst.add(Rect(prev.left, top, right, bottom)); + right = prev.left; } // if an entry in the previous span is too far right, nothing further left in the // current span will need it - if (prev->left >= right) { + if (prev.left >= right) { beginLastSpan = prevIndex; } } else { // iterating over previous span LTR, quit if it's too far right - if (prev->left >= right) break; + if (prev.left >= right) break; - if (prev->left > left && prev->left < right) { - dst.add(Rect(left, top, prev->left, bottom)); - left = prev->left; + if (prev.left > left && prev.left < right) { + dst.add(Rect(left, top, prev.left, bottom)); + left = prev.left; } - if (prev->right > left && prev->right < right) { - dst.add(Rect(left, top, prev->right, bottom)); - left = prev->right; + if (prev.right > left && prev.right < right) { + dst.add(Rect(left, top, prev.right, bottom)); + left = prev.right; } // if an entry in the previous span is too far left, nothing further right in the // current span will need it - if (prev->right <= left) { + if (prev.right <= left) { beginLastSpan = prevIndex; } } @@ -250,10 +255,16 @@ void Region::set(const Rect& r) mStorage.add(r); } +void Region::set(int32_t w, int32_t h) +{ + mStorage.clear(); + mStorage.add(Rect(w, h)); +} + void Region::set(uint32_t w, uint32_t h) { mStorage.clear(); - mStorage.add(Rect(w,h)); + mStorage.add(Rect(w, h)); } bool Region::isTriviallyEqual(const Region& region) const { @@ -404,7 +415,7 @@ const Region Region::operation(const Region& rhs, int dx, int dy, int op) const // This is our region rasterizer, which merges rects and spans together // to obtain an optimal region. -class Region::rasterizer : public region_operator<Rect>::region_rasterizer +class Region::rasterizer : public region_operator<Rect>::region_rasterizer { Rect bounds; Vector<Rect>& storage; @@ -413,80 +424,91 @@ class Region::rasterizer : public region_operator<Rect>::region_rasterizer Vector<Rect> span; Rect* cur; public: - rasterizer(Region& reg) + rasterizer(Region& reg) : bounds(INT_MAX, 0, INT_MIN, 0), storage(reg.mStorage), head(), tail(), cur() { storage.clear(); } - ~rasterizer() { - if (span.size()) { - flushSpan(); - } - if (storage.size()) { - bounds.top = storage.itemAt(0).top; - bounds.bottom = storage.top().bottom; - if (storage.size() == 1) { - storage.clear(); - } - } else { - bounds.left = 0; - bounds.right = 0; + virtual ~rasterizer(); + + virtual void operator()(const Rect& rect); + +private: + template<typename T> + static inline T min(T rhs, T lhs) { return rhs < lhs ? rhs : lhs; } + template<typename T> + static inline T max(T rhs, T lhs) { return rhs > lhs ? rhs : lhs; } + + void flushSpan(); +}; + +Region::rasterizer::~rasterizer() +{ + if (span.size()) { + flushSpan(); + } + if (storage.size()) { + bounds.top = storage.itemAt(0).top; + bounds.bottom = storage.top().bottom; + if (storage.size() == 1) { + storage.clear(); } - storage.add(bounds); + } else { + bounds.left = 0; + bounds.right = 0; } - - virtual void operator()(const Rect& rect) { - //ALOGD(">>> %3d, %3d, %3d, %3d", - // rect.left, rect.top, rect.right, rect.bottom); - if (span.size()) { - if (cur->top != rect.top) { - flushSpan(); - } else if (cur->right == rect.left) { - cur->right = rect.right; - return; - } + storage.add(bounds); +} + +void Region::rasterizer::operator()(const Rect& rect) +{ + //ALOGD(">>> %3d, %3d, %3d, %3d", + // rect.left, rect.top, rect.right, rect.bottom); + if (span.size()) { + if (cur->top != rect.top) { + flushSpan(); + } else if (cur->right == rect.left) { + cur->right = rect.right; + return; } - span.add(rect); - cur = span.editArray() + (span.size() - 1); } -private: - template<typename T> - static inline T min(T rhs, T lhs) { return rhs < lhs ? rhs : lhs; } - template<typename T> - static inline T max(T rhs, T lhs) { return rhs > lhs ? rhs : lhs; } - void flushSpan() { - bool merge = false; - if (tail-head == ssize_t(span.size())) { - Rect const* p = span.editArray(); - Rect const* q = head; - if (p->top == q->bottom) { - merge = true; - while (q != tail) { - if ((p->left != q->left) || (p->right != q->right)) { - merge = false; - break; - } - p++, q++; + span.add(rect); + cur = span.editArray() + (span.size() - 1); +} + +void Region::rasterizer::flushSpan() +{ + bool merge = false; + if (tail-head == ssize_t(span.size())) { + Rect const* p = span.editArray(); + Rect const* q = head; + if (p->top == q->bottom) { + merge = true; + while (q != tail) { + if ((p->left != q->left) || (p->right != q->right)) { + merge = false; + break; } + p++, q++; } } - if (merge) { - const int bottom = span[0].bottom; - Rect* r = head; - while (r != tail) { - r->bottom = bottom; - r++; - } - } else { - bounds.left = min(span.itemAt(0).left, bounds.left); - bounds.right = max(span.top().right, bounds.right); - storage.appendVector(span); - tail = storage.editArray() + storage.size(); - head = tail - span.size(); + } + if (merge) { + const int bottom = span[0].bottom; + Rect* r = head; + while (r != tail) { + r->bottom = bottom; + r++; } - span.clear(); + } else { + bounds.left = min(span.itemAt(0).left, bounds.left); + bounds.right = max(span.top().right, bounds.right); + storage.appendVector(span); + tail = storage.editArray() + storage.size(); + head = tail - span.size(); } -}; + span.clear(); +} bool Region::validate(const Region& reg, const char* name, bool silent) { @@ -497,8 +519,12 @@ bool Region::validate(const Region& reg, const char* name, bool silent) Rect b(*prev); while (cur != tail) { if (cur->isValid() == false) { - ALOGE_IF(!silent, "%s: region contains an invalid Rect", name); - result = false; + // We allow this particular flavor of invalid Rect, since it is used + // as a signal value in various parts of the system + if (*cur != Rect::INVALID_RECT) { + ALOGE_IF(!silent, "%s: region contains an invalid Rect", name); + result = false; + } } if (cur->right > region_operator<Rect>::max_value) { ALOGE_IF(!silent, "%s: rect->right > max_value", name); @@ -670,7 +696,9 @@ void Region::boolean_operation(int op, Region& dst, const Region& lhs, const Rect& rhs, int dx, int dy) { - if (!rhs.isValid()) { + // We allow this particular flavor of invalid Rect, since it is used as a + // signal value in various parts of the system + if (!rhs.isValid() && rhs != Rect::INVALID_RECT) { ALOGE("Region::boolean_operation(op=%d) invalid Rect={%d,%d,%d,%d}", op, rhs.left, rhs.top, rhs.right, rhs.bottom); return; @@ -733,35 +761,57 @@ void Region::translate(Region& dst, const Region& reg, int dx, int dy) // ---------------------------------------------------------------------------- size_t Region::getFlattenedSize() const { - return mStorage.size() * sizeof(Rect); + return sizeof(uint32_t) + mStorage.size() * sizeof(Rect); } status_t Region::flatten(void* buffer, size_t size) const { #if VALIDATE_REGIONS validate(*this, "Region::flatten"); #endif - if (size < mStorage.size() * sizeof(Rect)) { + if (size < getFlattenedSize()) { return NO_MEMORY; } - Rect* rects = reinterpret_cast<Rect*>(buffer); - memcpy(rects, mStorage.array(), mStorage.size() * sizeof(Rect)); + // Cast to uint32_t since the size of a size_t can vary between 32- and + // 64-bit processes + FlattenableUtils::write(buffer, size, static_cast<uint32_t>(mStorage.size())); + for (auto rect : mStorage) { + status_t result = rect.flatten(buffer, size); + if (result != NO_ERROR) { + return result; + } + FlattenableUtils::advance(buffer, size, sizeof(rect)); + } return NO_ERROR; } status_t Region::unflatten(void const* buffer, size_t size) { + if (size < sizeof(uint32_t)) { + return NO_MEMORY; + } + + uint32_t numRects = 0; + FlattenableUtils::read(buffer, size, numRects); + if (size < numRects * sizeof(Rect)) { + return NO_MEMORY; + } + + if (numRects > (UINT32_MAX / sizeof(Rect))) { + android_errorWriteWithInfoLog(0x534e4554, "29983260", -1, NULL, 0); + return NO_MEMORY; + } + Region result; - if (size >= sizeof(Rect)) { - Rect const* rects = reinterpret_cast<Rect const*>(buffer); - size_t count = size / sizeof(Rect); - if (count > 0) { - result.mStorage.clear(); - ssize_t err = result.mStorage.insertAt(0, count); - if (err < 0) { - return status_t(err); - } - memcpy(result.mStorage.editArray(), rects, count*sizeof(Rect)); + result.mStorage.clear(); + for (size_t r = 0; r < numRects; ++r) { + Rect rect; + status_t status = rect.unflatten(buffer, size); + if (status != NO_ERROR) { + return status; } + FlattenableUtils::advance(buffer, size, sizeof(rect)); + result.mStorage.push_back(rect); } + #if VALIDATE_REGIONS validate(result, "Region::unflatten"); #endif @@ -786,10 +836,8 @@ Region::const_iterator Region::end() const { } Rect const* Region::getArray(size_t* count) const { - const_iterator const b(begin()); - const_iterator const e(end()); - if (count) *count = e-b; - return b; + if (count) *count = static_cast<size_t>(end() - begin()); + return begin(); } SharedBuffer const* Region::getSharedBuffer(size_t* count) const { @@ -806,29 +854,22 @@ SharedBuffer const* Region::getSharedBuffer(size_t* count) const { // ---------------------------------------------------------------------------- -void Region::dump(String8& out, const char* what, uint32_t flags) const +void Region::dump(String8& out, const char* what, uint32_t /* flags */) const { - (void)flags; const_iterator head = begin(); const_iterator const tail = end(); - size_t SIZE = 256; - char buffer[SIZE]; - - snprintf(buffer, SIZE, " Region %s (this=%p, count=%" PRIdPTR ")\n", - what, this, tail-head); - out.append(buffer); + out.appendFormat(" Region %s (this=%p, count=%" PRIdPTR ")\n", + what, this, tail - head); while (head != tail) { - snprintf(buffer, SIZE, " [%3d, %3d, %3d, %3d]\n", - head->left, head->top, head->right, head->bottom); - out.append(buffer); - head++; + out.appendFormat(" [%3d, %3d, %3d, %3d]\n", head->left, head->top, + head->right, head->bottom); + ++head; } } -void Region::dump(const char* what, uint32_t flags) const +void Region::dump(const char* what, uint32_t /* flags */) const { - (void)flags; const_iterator head = begin(); const_iterator const tail = end(); ALOGD(" Region %s (this=%p, count=%" PRIdPTR ")\n", what, this, tail-head); diff --git a/libs/ui/UiConfig.cpp b/libs/ui/UiConfig.cpp index 8b2130e702..9e7ba8e886 100644 --- a/libs/ui/UiConfig.cpp +++ b/libs/ui/UiConfig.cpp @@ -18,8 +18,11 @@ namespace android { +#ifdef FRAMEBUFFER_FORCE_FORMAT +// We need the two-level macro to stringify the contents of a macro argument #define STRINGIFY(x) #x #define TOSTRING(x) STRINGIFY(x) +#endif void appendUiConfigString(String8& configStr) { diff --git a/libs/ui/tests/Android.mk b/libs/ui/tests/Android.mk index b0c57db984..6438b1f9a4 100644 --- a/libs/ui/tests/Android.mk +++ b/libs/ui/tests/Android.mk @@ -1,31 +1,36 @@ -# Build the unit tests. -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -# Build the unit tests. -test_src_files := \ - Region_test.cpp \ - vec_test.cpp \ - mat_test.cpp - -shared_libraries := \ - libutils \ - libui +# +# Copyright (C) 2014 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. +# -static_libraries := \ - libgtest \ - libgtest_main +LOCAL_PATH := $(call my-dir) -$(foreach file,$(test_src_files), \ - $(eval include $(CLEAR_VARS)) \ - $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \ - $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \ - $(eval LOCAL_SRC_FILES := $(file)) \ - $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \ - $(eval include $(BUILD_NATIVE_TEST)) \ -) +include $(CLEAR_VARS) +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk +LOCAL_SHARED_LIBRARIES := libui +LOCAL_SRC_FILES := Region_test.cpp +LOCAL_MODULE := Region_test +include $(BUILD_NATIVE_TEST) -# Build the unit tests. +include $(CLEAR_VARS) +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk +LOCAL_SRC_FILES := vec_test.cpp +LOCAL_MODULE := vec_test +include $(BUILD_NATIVE_TEST) -# Build the manual test programs. -include $(call all-makefiles-under, $(LOCAL_PATH)) +include $(CLEAR_VARS) +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk +LOCAL_SRC_FILES := mat_test.cpp +LOCAL_MODULE := mat_test +include $(BUILD_NATIVE_TEST) diff --git a/libs/ui/tests/vec_test.cpp b/libs/ui/tests/vec_test.cpp index 00f737e2f8..454c999ec4 100644 --- a/libs/ui/tests/vec_test.cpp +++ b/libs/ui/tests/vec_test.cpp @@ -16,17 +16,18 @@ #define LOG_TAG "RegionTest" +#include <math.h> #include <stdlib.h> + #include <ui/Region.h> #include <ui/Rect.h> -#include <gtest/gtest.h> - #include <ui/vec4.h> +#include <gtest/gtest.h> + namespace android { class VecTest : public testing::Test { -protected: }; TEST_F(VecTest, Basics) { diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h index 3b2984a8e4..b2abdb1021 100644 --- a/opengl/include/EGL/eglext.h +++ b/opengl/include/EGL/eglext.h @@ -176,6 +176,15 @@ typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBKHRPROC) (EGLDisplay dpy, EG #define EGL_BITMAP_PIXEL_SIZE_KHR 0x3110 #endif +#ifndef EGL_KHR_partial_update +#define EGL_KHR_partial_update 1 +#define EGL_BUFFER_AGE_KHR 0x313D +typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETDAMAGEREGIONKHRPROC) (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects); +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLBoolean EGLAPIENTRY eglSetDamageRegionKHR (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects); +#endif +#endif /* EGL_KHR_partial_update */ + #ifndef EGL_NV_coverage_sample #define EGL_NV_coverage_sample 1 #define EGL_COVERAGE_BUFFERS_NV 0x30E0 @@ -435,11 +444,24 @@ typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMTIMEKHRPROC)(EGLDisplay dpy, E #define EGL_OPENGL_ES3_BIT_KHR 0x00000040 #endif +#ifndef EGL_KHR_create_context_no_error +#define EGL_KHR_create_context_no_error 1 +#define EGL_CONTEXT_OPENGL_NO_ERROR_KHR 0x31B3 +#endif /* EGL_KHR_create_context_no_error */ + #ifndef EGL_KHR_surfaceless_context #define EGL_KHR_surfaceless_context 1 /* No tokens/entry points, just relaxes an error condition */ #endif +#ifndef EGL_KHR_swap_buffers_with_damage +#define EGL_KHR_swap_buffers_with_damage 1 +typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSWITHDAMAGEKHRPROC) (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects); +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersWithDamageKHR (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects); +#endif +#endif /* EGL_KHR_swap_buffers_with_damage */ + #ifdef EGL_KHR_stream /* Requires KHR_stream extension */ #ifndef EGL_KHR_stream_cross_process_fd #define EGL_KHR_stream_cross_process_fd 1 diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk index 64320cf75d..4b08749b22 100644 --- a/opengl/libagl/Android.mk +++ b/opengl/libagl/Android.mk @@ -31,7 +31,9 @@ LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils liblog libpixelflinger LOCAL_SRC_FILES_arm += fixed_asm.S iterators.S LOCAL_CFLAGS_arm += -fstrict-aliasing +ifndef ARCH_MIPS_REV6 LOCAL_SRC_FILES_mips += arch-mips/fixed_asm.S +endif LOCAL_CFLAGS_mips += -fstrict-aliasing # The graphics code can generate division by zero LOCAL_CFLAGS_mips += -mno-check-zero-division diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp index 1feac8b261..593d0c2d05 100644 --- a/opengl/libagl/egl.cpp +++ b/opengl/libagl/egl.cpp @@ -394,7 +394,13 @@ EGLBoolean egl_window_surface_v2_t::connect() depth.width = width; depth.height = height; depth.stride = depth.width; // use the width here - depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2); + uint64_t allocSize = static_cast<uint64_t>(depth.stride) * + static_cast<uint64_t>(depth.height) * 2; + if (depth.stride < 0 || depth.height > INT_MAX || + allocSize > UINT32_MAX) { + return setError(EGL_BAD_ALLOC, EGL_FALSE); + } + depth.data = (GGLubyte*)malloc(allocSize); if (depth.data == 0) { return setError(EGL_BAD_ALLOC, EGL_FALSE); } @@ -548,7 +554,14 @@ EGLBoolean egl_window_surface_v2_t::swapBuffers() depth.width = width; depth.height = height; depth.stride = buffer->stride; - depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2); + uint64_t allocSize = static_cast<uint64_t>(depth.stride) * + static_cast<uint64_t>(depth.height) * 2; + if (depth.stride < 0 || depth.height > INT_MAX || + allocSize > UINT32_MAX) { + setError(EGL_BAD_ALLOC, EGL_FALSE); + return EGL_FALSE; + } + depth.data = (GGLubyte*)malloc(allocSize); if (depth.data == 0) { setError(EGL_BAD_ALLOC, EGL_FALSE); return EGL_FALSE; @@ -666,7 +679,14 @@ egl_pixmap_surface_t::egl_pixmap_surface_t(EGLDisplay dpy, depth.width = pixmap->width; depth.height = pixmap->height; depth.stride = depth.width; // use the width here - depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2); + uint64_t allocSize = static_cast<uint64_t>(depth.stride) * + static_cast<uint64_t>(depth.height) * 2; + if (depth.stride < 0 || depth.height > INT_MAX || + allocSize > UINT32_MAX) { + setError(EGL_BAD_ALLOC, EGL_NO_SURFACE); + return; + } + depth.data = (GGLubyte*)malloc(allocSize); if (depth.data == 0) { setError(EGL_BAD_ALLOC, EGL_NO_SURFACE); } @@ -746,7 +766,14 @@ egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy, depth.width = pbuffer.width; depth.height = pbuffer.height; depth.stride = depth.width; // use the width here - depth.data = (GGLubyte*)malloc(depth.stride*depth.height*2); + uint64_t allocSize = static_cast<uint64_t>(depth.stride) * + static_cast<uint64_t>(depth.height) * 2; + if (depth.stride < 0 || depth.height > INT_MAX || + allocSize > UINT32_MAX) { + setError(EGL_BAD_ALLOC, EGL_NO_SURFACE); + return; + } + depth.data = (GGLubyte*)malloc(allocSize); if (depth.data == 0) { setError(EGL_BAD_ALLOC, EGL_NO_SURFACE); return; diff --git a/opengl/libagl/fp.cpp b/opengl/libagl/fp.cpp index aea44493e3..a7a4f7b102 100644 --- a/opengl/libagl/fp.cpp +++ b/opengl/libagl/fp.cpp @@ -19,7 +19,7 @@ // ---------------------------------------------------------------------------- -#if !defined(__arm__) && !defined(__mips__) +#if !(defined(__arm__) || (defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6)) GGLfixed gglFloatToFixed(float v) { return GGLfixed(floorf(v * 65536.0f + 0.5f)); } diff --git a/opengl/libagl/matrix.h b/opengl/libagl/matrix.h index 5bd717aed9..cafc11905c 100644 --- a/opengl/libagl/matrix.h +++ b/opengl/libagl/matrix.h @@ -74,7 +74,7 @@ GLfixed vsquare3(GLfixed a, GLfixed b, GLfixed c) ); return r; -#elif defined(__mips__) +#elif defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6 GLfixed res; int32_t t1,t2,t3; @@ -160,7 +160,7 @@ static inline GLfixed mla3a( GLfixed a0, GLfixed b0, ); return r; -#elif defined(__mips__) +#elif defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6 GLfixed res; int32_t t1,t2; diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk index cc5d544ae0..18ad3003e1 100644 --- a/opengl/libs/Android.mk +++ b/opengl/libs/Android.mk @@ -47,9 +47,6 @@ LOCAL_CFLAGS += -DEGL_TRACE=1 ifeq ($(BOARD_ALLOW_EGL_HIBERNATION),true) LOCAL_CFLAGS += -DBOARD_ALLOW_EGL_HIBERNATION endif -ifeq ($(TARGET_BOARD_PLATFORM), omap4) - LOCAL_CFLAGS += -DWORKAROUND_BUG_10194508=1 -endif ifneq ($(MAX_EGL_CACHE_ENTRY_SIZE),) LOCAL_CFLAGS += -DMAX_EGL_CACHE_ENTRY_SIZE=$(MAX_EGL_CACHE_ENTRY_SIZE) endif @@ -77,6 +74,7 @@ LOCAL_SRC_FILES:= \ GLES_CM/gl.cpp.arm \ # +LOCAL_CLANG := false LOCAL_SHARED_LIBRARIES += libcutils liblog libEGL LOCAL_MODULE:= libGLESv1_CM @@ -88,6 +86,9 @@ LOCAL_CFLAGS += -DLOG_TAG=\"libGLESv1\" LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES LOCAL_CFLAGS += -fvisibility=hidden +# TODO: This is to work around b/20093774. Remove after root cause is fixed +LOCAL_LDFLAGS_arm += -Wl,--hash-style,both + include $(BUILD_SHARED_LIBRARY) @@ -101,6 +102,7 @@ LOCAL_SRC_FILES:= \ GLES2/gl2.cpp.arm \ # +LOCAL_CLANG := false LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libEGL LOCAL_MODULE:= libGLESv2 @@ -112,6 +114,9 @@ LOCAL_CFLAGS += -DLOG_TAG=\"libGLESv2\" LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES LOCAL_CFLAGS += -fvisibility=hidden +# TODO: This is to work around b/20093774. Remove after root cause is fixed +LOCAL_LDFLAGS_arm += -Wl,--hash-style,both + # Symlink libGLESv3.so -> libGLESv2.so # Platform modules should link against libGLESv2.so (-lGLESv2), but NDK apps # will be linked against libGLESv3.so. diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp index 7c70fa03a7..4e0e5bc225 100644 --- a/opengl/libs/EGL/egl.cpp +++ b/opengl/libs/EGL/egl.cpp @@ -292,6 +292,44 @@ const GLubyte * egl_get_string_for_current_context(GLenum name) { return (const GLubyte *)c->gl_extensions.string(); } +const GLubyte * egl_get_string_for_current_context(GLenum name, GLuint index) { + // NOTE: returning NULL here will fall-back to the default + // implementation. + + EGLContext context = egl_tls_t::getContext(); + if (context == EGL_NO_CONTEXT) + return NULL; + + egl_context_t const * const c = get_context(context); + if (c == NULL) // this should never happen, by construction + return NULL; + + if (name != GL_EXTENSIONS) + return NULL; + + // if index is out of bounds, assume it will be in the default + // implementation too, so we don't have to generate a GL error here + if (index >= c->tokenized_gl_extensions.size()) + return NULL; + + return (const GLubyte *)c->tokenized_gl_extensions.itemAt(index).string(); +} + +GLint egl_get_num_extensions_for_current_context() { + // NOTE: returning -1 here will fall-back to the default + // implementation. + + EGLContext context = egl_tls_t::getContext(); + if (context == EGL_NO_CONTEXT) + return -1; + + egl_context_t const * const c = get_context(context); + if (c == NULL) // this should never happen, by construction + return -1; + + return (GLint)c->tokenized_gl_extensions.size(); +} + // ---------------------------------------------------------------------------- // this mutex protects: diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp index 6e77e457bc..837890759b 100644 --- a/opengl/libs/EGL/eglApi.cpp +++ b/opengl/libs/EGL/eglApi.cpp @@ -80,6 +80,7 @@ struct extention_map_t { extern char const * const gBuiltinExtensionString = "EGL_KHR_get_all_proc_addresses " "EGL_ANDROID_presentation_time " + "EGL_KHR_swap_buffers_with_damage " ; extern char const * const gExtensionString = "EGL_KHR_image " // mandatory @@ -90,16 +91,27 @@ extern char const * const gExtensionString = "EGL_KHR_gl_colorspace " #endif "EGL_KHR_gl_texture_2D_image " + "EGL_KHR_gl_texture_3D_image " "EGL_KHR_gl_texture_cubemap_image " "EGL_KHR_gl_renderbuffer_image " "EGL_KHR_reusable_sync " "EGL_KHR_fence_sync " "EGL_KHR_create_context " + "EGL_KHR_config_attribs " + "EGL_KHR_surfaceless_context " + "EGL_KHR_stream " + "EGL_KHR_stream_fifo " + "EGL_KHR_stream_producer_eglsurface " + "EGL_KHR_stream_consumer_gltexture " + "EGL_KHR_stream_cross_process_fd " "EGL_EXT_create_context_robustness " "EGL_NV_system_time " "EGL_ANDROID_image_native_buffer " // mandatory "EGL_KHR_wait_sync " // strongly recommended "EGL_ANDROID_recordable " // mandatory + "EGL_KHR_partial_update " // strongly recommended + "EGL_EXT_buffer_age " // strongly recommended with partial_update + "EGL_KHR_create_context_no_error " ; // extensions not exposed to applications but used by the ANDROID system @@ -152,6 +164,39 @@ static const extention_map_t sExtensionMap[] = { // EGL_ANDROID_presentation_time { "eglPresentationTimeANDROID", (__eglMustCastToProperFunctionPointerType)&eglPresentationTimeANDROID }, + + // EGL_KHR_swap_buffers_with_damage + { "eglSwapBuffersWithDamageKHR", + (__eglMustCastToProperFunctionPointerType)&eglSwapBuffersWithDamageKHR }, + + // EGL_KHR_partial_update + { "eglSetDamageRegionKHR", + (__eglMustCastToProperFunctionPointerType)&eglSetDamageRegionKHR }, + + { "eglCreateStreamKHR", + (__eglMustCastToProperFunctionPointerType)&eglCreateStreamKHR }, + { "eglDestroyStreamKHR", + (__eglMustCastToProperFunctionPointerType)&eglDestroyStreamKHR }, + { "eglStreamAttribKHR", + (__eglMustCastToProperFunctionPointerType)&eglStreamAttribKHR }, + { "eglQueryStreamKHR", + (__eglMustCastToProperFunctionPointerType)&eglQueryStreamKHR }, + { "eglQueryStreamu64KHR", + (__eglMustCastToProperFunctionPointerType)&eglQueryStreamu64KHR }, + { "eglQueryStreamTimeKHR", + (__eglMustCastToProperFunctionPointerType)&eglQueryStreamTimeKHR }, + { "eglCreateStreamProducerSurfaceKHR", + (__eglMustCastToProperFunctionPointerType)&eglCreateStreamProducerSurfaceKHR }, + { "eglStreamConsumerGLTextureExternalKHR", + (__eglMustCastToProperFunctionPointerType)&eglStreamConsumerGLTextureExternalKHR }, + { "eglStreamConsumerAcquireKHR", + (__eglMustCastToProperFunctionPointerType)&eglStreamConsumerAcquireKHR }, + { "eglStreamConsumerReleaseKHR", + (__eglMustCastToProperFunctionPointerType)&eglStreamConsumerReleaseKHR }, + { "eglGetStreamFileDescriptorKHR", + (__eglMustCastToProperFunctionPointerType)&eglGetStreamFileDescriptorKHR }, + { "eglCreateStreamFromFileDescriptorKHR", + (__eglMustCastToProperFunctionPointerType)&eglCreateStreamFromFileDescriptorKHR }, }; /* @@ -381,20 +426,15 @@ EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, // Turn linear formats into corresponding sRGB formats when colorspace is // EGL_GL_COLORSPACE_SRGB_KHR, or turn sRGB formats into corresponding linear // formats when colorspace is EGL_GL_COLORSPACE_LINEAR_KHR. In any cases where -// the modification isn't possible, the original format is returned. -static int modifyFormatColorspace(int fmt, EGLint colorspace) { +// the modification isn't possible, the original dataSpace is returned. +static android_dataspace modifyBufferDataspace( android_dataspace dataSpace, + EGLint colorspace) { if (colorspace == EGL_GL_COLORSPACE_LINEAR_KHR) { - switch (fmt) { - case HAL_PIXEL_FORMAT_sRGB_A_8888: return HAL_PIXEL_FORMAT_RGBA_8888; - case HAL_PIXEL_FORMAT_sRGB_X_8888: return HAL_PIXEL_FORMAT_RGBX_8888; - } + return HAL_DATASPACE_SRGB_LINEAR; } else if (colorspace == EGL_GL_COLORSPACE_SRGB_KHR) { - switch (fmt) { - case HAL_PIXEL_FORMAT_RGBA_8888: return HAL_PIXEL_FORMAT_sRGB_A_8888; - case HAL_PIXEL_FORMAT_RGBX_8888: return HAL_PIXEL_FORMAT_sRGB_X_8888; - } + return HAL_DATASPACE_SRGB; } - return fmt; + return dataSpace; } EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, @@ -421,37 +461,10 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, // of our native format. So if sRGB gamma is requested, we have to // modify the EGLconfig's format before setting the native window's // format. -#if WORKAROUND_BUG_10194508 -#warning "WORKAROUND_10194508 enabled" - EGLint format; - if (!cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_NATIVE_VISUAL_ID, - &format)) { - ALOGE("eglGetConfigAttrib(EGL_NATIVE_VISUAL_ID) failed: %#x", - eglGetError()); - format = 0; - } - if (attrib_list) { - for (const EGLint* attr = attrib_list; *attr != EGL_NONE; - attr += 2) { - if (*attr == EGL_GL_COLORSPACE_KHR && - dp->haveExtension("EGL_KHR_gl_colorspace")) { - if (ENABLE_EGL_KHR_GL_COLORSPACE) { - format = modifyFormatColorspace(format, *(attr+1)); - } else { - // Normally we'd pass through unhandled attributes to - // the driver. But in case the driver implements this - // extension but we're disabling it, we want to prevent - // it getting through -- support will be broken without - // our help. - ALOGE("sRGB window surfaces not supported"); - return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); - } - } - } - } -#else + // by default, just pick RGBA_8888 EGLint format = HAL_PIXEL_FORMAT_RGBA_8888; + android_dataspace dataSpace = HAL_DATASPACE_UNKNOWN; EGLint a = 0; cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_ALPHA_SIZE, &a); @@ -477,7 +490,7 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, for (const EGLint* attr = attrib_list; *attr != EGL_NONE; attr += 2) { if (*attr == EGL_GL_COLORSPACE_KHR) { if (ENABLE_EGL_KHR_GL_COLORSPACE) { - format = modifyFormatColorspace(format, *(attr+1)); + dataSpace = modifyBufferDataspace(dataSpace, *(attr+1)); } else { // Normally we'd pass through unhandled attributes to // the driver. But in case the driver implements this @@ -490,7 +503,7 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, } } } -#endif + if (format != 0) { int err = native_window_set_buffers_format(window, format); if (err != 0) { @@ -501,6 +514,16 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, } } + if (dataSpace != 0) { + int err = native_window_set_buffers_data_space(window, dataSpace); + if (err != 0) { + ALOGE("error setting native window pixel dataSpace: %s (%d)", + strerror(-err), err); + native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); + return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); + } + } + // the EGL spec requires that a new EGLSurface default to swap interval // 1, so explicitly set that on the window here. ANativeWindow* anw = reinterpret_cast<ANativeWindow*>(window); @@ -572,6 +595,15 @@ EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) return setError(EGL_BAD_SURFACE, EGL_FALSE); egl_surface_t * const s = get_surface(surface); + ANativeWindow* window = s->win.get(); + if (window) { + int result = native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); + if (result != OK) { + ALOGE("eglDestroySurface: native_window_api_disconnect (win=%p) " + "failed (%#x)", + window, result); + } + } EGLBoolean result = s->cnx->egl.eglDestroySurface(dp->disp.dpy, s->surface); if (result == EGL_TRUE) { _s.terminate(); @@ -1043,7 +1075,8 @@ private: Mutex mMutex; }; -EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw) +EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface draw, + EGLint *rects, EGLint n_rects) { ATRACE_CALL(); clearError(); @@ -1102,7 +1135,38 @@ EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw) } } - return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface); + if (n_rects == 0) { + return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface); + } + + Vector<android_native_rect_t> androidRects; + for (int r = 0; r < n_rects; ++r) { + int offset = r * 4; + int x = rects[offset]; + int y = rects[offset + 1]; + int width = rects[offset + 2]; + int height = rects[offset + 3]; + android_native_rect_t androidRect; + androidRect.left = x; + androidRect.top = y + height; + androidRect.right = x + width; + androidRect.bottom = y; + androidRects.push_back(androidRect); + } + native_window_set_surface_damage(s->win.get(), androidRects.array(), + androidRects.size()); + + if (s->cnx->egl.eglSwapBuffersWithDamageKHR) { + return s->cnx->egl.eglSwapBuffersWithDamageKHR(dp->disp.dpy, s->surface, + rects, n_rects); + } else { + return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface); + } +} + +EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) +{ + return eglSwapBuffersWithDamageKHR(dpy, surface, NULL, 0); } EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface, @@ -1496,6 +1560,212 @@ EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, return result; } +EGLStreamKHR eglCreateStreamKHR(EGLDisplay dpy, const EGLint *attrib_list) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_NO_STREAM_KHR; + + EGLStreamKHR result = EGL_NO_STREAM_KHR; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglCreateStreamKHR) { + result = cnx->egl.eglCreateStreamKHR( + dp->disp.dpy, attrib_list); + } + return result; +} + +EGLBoolean eglDestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + EGLBoolean result = EGL_FALSE; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglDestroyStreamKHR) { + result = cnx->egl.eglDestroyStreamKHR( + dp->disp.dpy, stream); + } + return result; +} + +EGLBoolean eglStreamAttribKHR(EGLDisplay dpy, EGLStreamKHR stream, + EGLenum attribute, EGLint value) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + EGLBoolean result = EGL_FALSE; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglStreamAttribKHR) { + result = cnx->egl.eglStreamAttribKHR( + dp->disp.dpy, stream, attribute, value); + } + return result; +} + +EGLBoolean eglQueryStreamKHR(EGLDisplay dpy, EGLStreamKHR stream, + EGLenum attribute, EGLint *value) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + EGLBoolean result = EGL_FALSE; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglQueryStreamKHR) { + result = cnx->egl.eglQueryStreamKHR( + dp->disp.dpy, stream, attribute, value); + } + return result; +} + +EGLBoolean eglQueryStreamu64KHR(EGLDisplay dpy, EGLStreamKHR stream, + EGLenum attribute, EGLuint64KHR *value) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + EGLBoolean result = EGL_FALSE; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglQueryStreamu64KHR) { + result = cnx->egl.eglQueryStreamu64KHR( + dp->disp.dpy, stream, attribute, value); + } + return result; +} + +EGLBoolean eglQueryStreamTimeKHR(EGLDisplay dpy, EGLStreamKHR stream, + EGLenum attribute, EGLTimeKHR *value) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + EGLBoolean result = EGL_FALSE; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglQueryStreamTimeKHR) { + result = cnx->egl.eglQueryStreamTimeKHR( + dp->disp.dpy, stream, attribute, value); + } + return result; +} + +EGLSurface eglCreateStreamProducerSurfaceKHR(EGLDisplay dpy, EGLConfig config, + EGLStreamKHR stream, const EGLint *attrib_list) +{ + clearError(); + + egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_NO_SURFACE; + + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglCreateStreamProducerSurfaceKHR) { + EGLSurface surface = cnx->egl.eglCreateStreamProducerSurfaceKHR( + dp->disp.dpy, config, stream, attrib_list); + if (surface != EGL_NO_SURFACE) { + egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, + surface, cnx); + return s; + } + } + return EGL_NO_SURFACE; +} + +EGLBoolean eglStreamConsumerGLTextureExternalKHR(EGLDisplay dpy, + EGLStreamKHR stream) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + EGLBoolean result = EGL_FALSE; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglStreamConsumerGLTextureExternalKHR) { + result = cnx->egl.eglStreamConsumerGLTextureExternalKHR( + dp->disp.dpy, stream); + } + return result; +} + +EGLBoolean eglStreamConsumerAcquireKHR(EGLDisplay dpy, + EGLStreamKHR stream) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + EGLBoolean result = EGL_FALSE; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglStreamConsumerAcquireKHR) { + result = cnx->egl.eglStreamConsumerAcquireKHR( + dp->disp.dpy, stream); + } + return result; +} + +EGLBoolean eglStreamConsumerReleaseKHR(EGLDisplay dpy, + EGLStreamKHR stream) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + EGLBoolean result = EGL_FALSE; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglStreamConsumerReleaseKHR) { + result = cnx->egl.eglStreamConsumerReleaseKHR( + dp->disp.dpy, stream); + } + return result; +} + +EGLNativeFileDescriptorKHR eglGetStreamFileDescriptorKHR( + EGLDisplay dpy, EGLStreamKHR stream) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_NO_FILE_DESCRIPTOR_KHR; + + EGLNativeFileDescriptorKHR result = EGL_NO_FILE_DESCRIPTOR_KHR; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglGetStreamFileDescriptorKHR) { + result = cnx->egl.eglGetStreamFileDescriptorKHR( + dp->disp.dpy, stream); + } + return result; +} + +EGLStreamKHR eglCreateStreamFromFileDescriptorKHR( + EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_NO_STREAM_KHR; + + EGLStreamKHR result = EGL_NO_STREAM_KHR; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglCreateStreamFromFileDescriptorKHR) { + result = cnx->egl.eglCreateStreamFromFileDescriptorKHR( + dp->disp.dpy, file_descriptor); + } + return result; +} + // ---------------------------------------------------------------------------- // EGL_EGLEXT_VERSION 15 // ---------------------------------------------------------------------------- @@ -1591,3 +1861,32 @@ EGLuint64NV eglGetSystemTimeNV() return setErrorQuiet(EGL_BAD_DISPLAY, 0); } + +// ---------------------------------------------------------------------------- +// Partial update extension +// ---------------------------------------------------------------------------- +EGLBoolean eglSetDamageRegionKHR(EGLDisplay dpy, EGLSurface surface, + EGLint *rects, EGLint n_rects) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) { + setError(EGL_BAD_DISPLAY, EGL_FALSE); + return EGL_FALSE; + } + + SurfaceRef _s(dp.get(), surface); + if (!_s.get()) { + setError(EGL_BAD_SURFACE, EGL_FALSE); + return EGL_FALSE; + } + + egl_surface_t const * const s = get_surface(surface); + if (s->cnx->egl.eglSetDamageRegionKHR) { + return s->cnx->egl.eglSetDamageRegionKHR(dp->disp.dpy, s->surface, + rects, n_rects); + } + + return EGL_FALSE; +} diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h index 4949ef212f..2d862951c1 100644 --- a/opengl/libs/EGL/egl_display.h +++ b/opengl/libs/EGL/egl_display.h @@ -39,7 +39,7 @@ namespace android { class egl_object_t; class egl_context_t; -class egl_connection_t; +struct egl_connection_t; // ---------------------------------------------------------------------------- diff --git a/opengl/libs/EGL/egl_entries.in b/opengl/libs/EGL/egl_entries.in index 70d0e52fd3..498b2fc61a 100644 --- a/opengl/libs/EGL/egl_entries.in +++ b/opengl/libs/EGL/egl_entries.in @@ -61,18 +61,18 @@ EGL_ENTRY(EGLBoolean, eglGetSyncAttribKHR, EGLDisplay, EGLSyncKHR, EGLint, /* EGL_EGLEXT_VERSION 15 */ -// EGL_ENTRY(EGLStreamKHR, eglCreateStreamKHR, EGLDisplay, const EGLint *) -// EGL_ENTRY(EGLBoolean, eglDestroyStreamKHR, EGLDisplay, EGLStreamKHR) -// EGL_ENTRY(EGLBoolean, eglStreamAttribKHR, EGLDisplay, EGLStreamKHR, EGLenum, EGLint) -// EGL_ENTRY(EGLBoolean, eglQueryStreamKHR, EGLDisplay, EGLStreamKHR, EGLenum, EGLint *) -// EGL_ENTRY(EGLBoolean, eglQueryStreamu64KHR, EGLDisplay, EGLStreamKHR, EGLenum, EGLuint64KHR *) -// EGL_ENTRY(EGLBoolean, eglStreamConsumerGLTextureExternalKHR, EGLDisplay, EGLStreamKHR) -// EGL_ENTRY(EGLBoolean, eglStreamConsumerAcquireKHR, EGLDisplay, EGLStreamKHR) -// EGL_ENTRY(EGLBoolean, eglStreamConsumerReleaseKHR, EGLDisplay, EGLStreamKHR) -// EGL_ENTRY(EGLSurface, eglCreateStreamProducerSurfaceKHR, EGLDisplay, EGLConfig, EGLStreamKHR, const EGLint *) -// EGL_ENTRY(EGLBoolean, eglQueryStreamTimeKHR, EGLDisplay, EGLStreamKHR, EGLenum, EGLTimeKHR*) -// EGL_ENTRY(EGLNativeFileDescriptorKHR, eglGetStreamFileDescriptorKHR, EGLDisplay, EGLStreamKHR) -// EGL_ENTRY(EGLStreamKHR, eglCreateStreamFromFileDescriptorKHR, EGLDisplay, EGLNativeFileDescriptorKHR) +EGL_ENTRY(EGLStreamKHR, eglCreateStreamKHR, EGLDisplay, const EGLint *) +EGL_ENTRY(EGLBoolean, eglDestroyStreamKHR, EGLDisplay, EGLStreamKHR) +EGL_ENTRY(EGLBoolean, eglStreamAttribKHR, EGLDisplay, EGLStreamKHR, EGLenum, EGLint) +EGL_ENTRY(EGLBoolean, eglQueryStreamKHR, EGLDisplay, EGLStreamKHR, EGLenum, EGLint *) +EGL_ENTRY(EGLBoolean, eglQueryStreamu64KHR, EGLDisplay, EGLStreamKHR, EGLenum, EGLuint64KHR *) +EGL_ENTRY(EGLBoolean, eglStreamConsumerGLTextureExternalKHR, EGLDisplay, EGLStreamKHR) +EGL_ENTRY(EGLBoolean, eglStreamConsumerAcquireKHR, EGLDisplay, EGLStreamKHR) +EGL_ENTRY(EGLBoolean, eglStreamConsumerReleaseKHR, EGLDisplay, EGLStreamKHR) +EGL_ENTRY(EGLSurface, eglCreateStreamProducerSurfaceKHR, EGLDisplay, EGLConfig, EGLStreamKHR, const EGLint *) +EGL_ENTRY(EGLBoolean, eglQueryStreamTimeKHR, EGLDisplay, EGLStreamKHR, EGLenum, EGLTimeKHR*) +EGL_ENTRY(EGLNativeFileDescriptorKHR, eglGetStreamFileDescriptorKHR, EGLDisplay, EGLStreamKHR) +EGL_ENTRY(EGLStreamKHR, eglCreateStreamFromFileDescriptorKHR, EGLDisplay, EGLNativeFileDescriptorKHR) EGL_ENTRY(EGLint, eglWaitSyncKHR, EGLDisplay, EGLSyncKHR, EGLint) /* ANDROID extensions */ @@ -89,4 +89,9 @@ EGL_ENTRY(EGLuint64NV, eglGetSystemTimeNV, void) /* IMG extensions */ EGL_ENTRY(EGLBoolean, eglHibernateProcessIMG, void) -EGL_ENTRY(EGLBoolean, eglAwakenProcessIMG, void)
\ No newline at end of file +EGL_ENTRY(EGLBoolean, eglAwakenProcessIMG, void) + +/* Partial update extensions */ + +EGL_ENTRY(EGLBoolean, eglSwapBuffersWithDamageKHR, EGLDisplay, EGLSurface, EGLint *, EGLint) +EGL_ENTRY(EGLBoolean, eglSetDamageRegionKHR, EGLDisplay, EGLSurface, EGLint *, EGLint) diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp index d3ee76d4d7..918faa80a5 100644 --- a/opengl/libs/EGL/egl_object.cpp +++ b/opengl/libs/EGL/egl_object.cpp @@ -14,6 +14,9 @@ ** limitations under the License. */ +#include <string> +#include <sstream> + #include <ctype.h> #include <stdint.h> #include <stdlib.h> @@ -113,6 +116,14 @@ void egl_context_t::onMakeCurrent(EGLSurface draw, EGLSurface read) { temp.append(gl_extensions); gl_extensions.setTo(temp); } + + // tokenize the supported extensions for the glGetStringi() wrapper + std::stringstream ss; + std::string str; + ss << gl_extensions.string(); + while (ss >> str) { + tokenized_gl_extensions.push(String8(str.c_str())); + } } } diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h index 518fdec219..f5a9f587b4 100644 --- a/opengl/libs/EGL/egl_object.h +++ b/opengl/libs/EGL/egl_object.h @@ -27,6 +27,7 @@ #include <utils/threads.h> #include <utils/String8.h> +#include <utils/Vector.h> #include <system/window.h> @@ -159,6 +160,7 @@ public: egl_connection_t const* cnx; int version; String8 gl_extensions; + Vector<String8> tokenized_gl_extensions; }; // ---------------------------------------------------------------------------- diff --git a/opengl/libs/EGL/getProcAddress.cpp b/opengl/libs/EGL/getProcAddress.cpp index fc611349eb..660af3347b 100644 --- a/opengl/libs/EGL/getProcAddress.cpp +++ b/opengl/libs/EGL/getProcAddress.cpp @@ -78,7 +78,7 @@ namespace android { #elif defined(__i386__) - #define API_ENTRY(_api) __attribute__((noinline)) _api + #define API_ENTRY(_api) __attribute__((noinline,optimize("omit-frame-pointer"))) _api #define CALL_GL_EXTENSION_API(_api) \ register void** fn; \ @@ -100,7 +100,7 @@ namespace android { #elif defined(__x86_64__) - #define API_ENTRY(_api) __attribute__((noinline)) _api + #define API_ENTRY(_api) __attribute__((noinline,optimize("omit-frame-pointer"))) _api #define CALL_GL_EXTENSION_API(_api) \ register void** fn; \ @@ -120,14 +120,46 @@ namespace android { : "cc" \ ); +#elif defined(__mips64) + + #define API_ENTRY(_api) __attribute__((noinline)) _api + + #define CALL_GL_EXTENSION_API(_api, ...) \ + register unsigned int _t0 asm("$12"); \ + register unsigned int _fn asm("$25"); \ + register unsigned int _tls asm("$3"); \ + asm volatile( \ + ".set push\n\t" \ + ".set noreorder\n\t" \ + "rdhwr %[tls], $29\n\t" \ + "ld %[t0], %[OPENGL_API](%[tls])\n\t" \ + "beqz %[t0], 1f\n\t" \ + " move %[fn], $ra\n\t" \ + "ld %[t0], %[API](%[t0])\n\t" \ + "beqz %[t0], 1f\n\t" \ + " nop\n\t" \ + "move %[fn], %[t0]\n\t" \ + "1:\n\t" \ + "jalr $0, %[fn]\n\t" \ + " nop\n\t" \ + ".set pop\n\t" \ + : [fn] "=c"(_fn), \ + [tls] "=&r"(_tls), \ + [t0] "=&r"(_t0) \ + : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*4), \ + [API] "I"(__builtin_offsetof(gl_hooks_t, \ + ext.extensions[_api])) \ + : \ + ); + #elif defined(__mips__) #define API_ENTRY(_api) __attribute__((noinline)) _api #define CALL_GL_EXTENSION_API(_api, ...) \ - register unsigned int _t0 asm("t0"); \ - register unsigned int _fn asm("t1"); \ - register unsigned int _tls asm("v1"); \ + register unsigned int _t0 asm("$8"); \ + register unsigned int _fn asm("$25"); \ + register unsigned int _tls asm("$3"); \ asm volatile( \ ".set push\n\t" \ ".set noreorder\n\t" \ @@ -136,10 +168,12 @@ namespace android { "lw %[t0], %[OPENGL_API](%[tls])\n\t" \ "beqz %[t0], 1f\n\t" \ " move %[fn], $ra\n\t" \ - "lw %[fn], %[API](%[t0])\n\t" \ - "movz %[fn], $ra, %[fn]\n\t" \ + "lw %[t0], %[API](%[t0])\n\t" \ + "beqz %[t0], 1f\n\t" \ + " nop\n\t" \ + "move %[fn], %[t0]\n\t" \ "1:\n\t" \ - "j %[fn]\n\t" \ + "jalr $0, %[fn]\n\t" \ " nop\n\t" \ ".set pop\n\t" \ : [fn] "=c"(_fn), \ diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp index b07228f974..6034a8edc0 100644 --- a/opengl/libs/GLES2/gl2.cpp +++ b/opengl/libs/GLES2/gl2.cpp @@ -82,7 +82,7 @@ using namespace android; #elif defined(__i386__) - #define API_ENTRY(_api) __attribute__((noinline)) _api + #define API_ENTRY(_api) __attribute__((noinline,optimize("omit-frame-pointer"))) _api #define CALL_GL_API(_api, ...) \ register void** fn; \ @@ -101,7 +101,7 @@ using namespace android; #elif defined(__x86_64__) - #define API_ENTRY(_api) __attribute__((noinline)) _api + #define API_ENTRY(_api) __attribute__((noinline,optimize("omit-frame-pointer"))) _api #define CALL_GL_API(_api, ...) \ register void** fn; \ @@ -118,27 +118,62 @@ using namespace android; : "cc" \ ); +#elif defined(__mips64) + + #define API_ENTRY(_api) __attribute__((noinline)) _api + + #define CALL_GL_API(_api, ...) \ + register unsigned long _t0 asm("$12"); \ + register unsigned long _fn asm("$25"); \ + register unsigned long _tls asm("$3"); \ + register unsigned long _v0 asm("$2"); \ + asm volatile( \ + ".set push\n\t" \ + ".set noreorder\n\t" \ + "rdhwr %[tls], $29\n\t" \ + "ld %[t0], %[OPENGL_API](%[tls])\n\t" \ + "beqz %[t0], 1f\n\t" \ + " move %[fn], $ra\n\t" \ + "ld %[t0], %[API](%[t0])\n\t" \ + "beqz %[t0], 1f\n\t" \ + " nop\n\t" \ + "move %[fn], %[t0]\n\t" \ + "1:\n\t" \ + "jalr $0, %[fn]\n\t" \ + " move %[v0], $0\n\t" \ + ".set pop\n\t" \ + : [fn] "=c"(_fn), \ + [tls] "=&r"(_tls), \ + [t0] "=&r"(_t0), \ + [v0] "=&r"(_v0) \ + : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*sizeof(void*)),\ + [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \ + : \ + ); + #elif defined(__mips__) #define API_ENTRY(_api) __attribute__((noinline)) _api #define CALL_GL_API(_api, ...) \ - register unsigned int _t0 asm("t0"); \ - register unsigned int _fn asm("t1"); \ - register unsigned int _tls asm("v1"); \ - register unsigned int _v0 asm("v0"); \ + register unsigned int _t0 asm("$8"); \ + register unsigned int _fn asm("$25"); \ + register unsigned int _tls asm("$3"); \ + register unsigned int _v0 asm("$2"); \ asm volatile( \ ".set push\n\t" \ ".set noreorder\n\t" \ - ".set mips32r2\n\t" \ + ".set mips32r2\n\t" \ "rdhwr %[tls], $29\n\t" \ "lw %[t0], %[OPENGL_API](%[tls])\n\t" \ "beqz %[t0], 1f\n\t" \ " move %[fn],$ra\n\t" \ - "lw %[fn], %[API](%[t0])\n\t" \ - "movz %[fn], $ra, %[fn]\n\t" \ + "lw %[t0], %[API](%[t0])\n\t" \ + "beqz %[t0], 1f\n\t" \ + " nop\n\t" \ + "move %[fn], %[t0]\n\t" \ "1:\n\t" \ - "j %[fn]\n\t" \ + "jalr $0, %[fn]\n\t" \ " move %[v0], $0\n\t" \ ".set pop\n\t" \ : [fn] "=c"(_fn), \ @@ -170,17 +205,87 @@ extern "C" { #undef CALL_GL_API_RETURN /* - * glGetString() is special because we expose some extensions in the wrapper + * glGetString() and glGetStringi() are special because we expose some + * extensions in the wrapper. Also, wrapping glGetXXX() is required because + * the value returned for GL_NUM_EXTENSIONS may have been altered by the + * injection of the additional extensions. */ -extern "C" const GLubyte * __glGetString(GLenum name); +extern "C" { + const GLubyte * __glGetString(GLenum name); + const GLubyte * __glGetStringi(GLenum name, GLuint index); + void __glGetBooleanv(GLenum pname, GLboolean * data); + void __glGetFloatv(GLenum pname, GLfloat * data); + void __glGetIntegerv(GLenum pname, GLint * data); + void __glGetInteger64v(GLenum pname, GLint64 * data); +} -const GLubyte * glGetString(GLenum name) -{ +const GLubyte * glGetString(GLenum name) { const GLubyte * ret = egl_get_string_for_current_context(name); if (ret == NULL) { gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; - ret = _c->glGetString(name); + if(_c) ret = _c->glGetString(name); + } + return ret; +} + +const GLubyte * glGetStringi(GLenum name, GLuint index) { + const GLubyte * ret = egl_get_string_for_current_context(name, index); + if (ret == NULL) { + gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; + if(_c) ret = _c->glGetStringi(name, index); } return ret; } + +void glGetBooleanv(GLenum pname, GLboolean * data) { + if (pname == GL_NUM_EXTENSIONS) { + int num_exts = egl_get_num_extensions_for_current_context(); + if (num_exts >= 0) { + *data = num_exts > 0 ? GL_TRUE : GL_FALSE; + return; + } + } + + gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; + if (_c) _c->glGetBooleanv(pname, data); +} + +void glGetFloatv(GLenum pname, GLfloat * data) { + if (pname == GL_NUM_EXTENSIONS) { + int num_exts = egl_get_num_extensions_for_current_context(); + if (num_exts >= 0) { + *data = (GLfloat)num_exts; + return; + } + } + + gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; + if (_c) _c->glGetFloatv(pname, data); +} + +void glGetIntegerv(GLenum pname, GLint * data) { + if (pname == GL_NUM_EXTENSIONS) { + int num_exts = egl_get_num_extensions_for_current_context(); + if (num_exts >= 0) { + *data = (GLint)num_exts; + return; + } + } + + gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; + if (_c) _c->glGetIntegerv(pname, data); +} + +void glGetInteger64v(GLenum pname, GLint64 * data) { + if (pname == GL_NUM_EXTENSIONS) { + int num_exts = egl_get_num_extensions_for_current_context(); + if (num_exts >= 0) { + *data = (GLint64)num_exts; + return; + } + } + + gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; + if (_c) _c->glGetInteger64v(pname, data); +} diff --git a/opengl/libs/GLES2/gl2_api.in b/opengl/libs/GLES2/gl2_api.in index 8363960512..09d8b00065 100644 --- a/opengl/libs/GLES2/gl2_api.in +++ b/opengl/libs/GLES2/gl2_api.in @@ -172,7 +172,7 @@ void API_ENTRY(glGetAttachedShaders)(GLuint program, GLsizei maxCount, GLsizei * GLint API_ENTRY(glGetAttribLocation)(GLuint program, const GLchar * name) { CALL_GL_API_RETURN(glGetAttribLocation, program, name); } -void API_ENTRY(glGetBooleanv)(GLenum pname, GLboolean * data) { +void API_ENTRY(__glGetBooleanv)(GLenum pname, GLboolean * data) { CALL_GL_API(glGetBooleanv, pname, data); } void API_ENTRY(glGetBufferParameteriv)(GLenum target, GLenum pname, GLint * params) { @@ -181,13 +181,13 @@ void API_ENTRY(glGetBufferParameteriv)(GLenum target, GLenum pname, GLint * para GLenum API_ENTRY(glGetError)(void) { CALL_GL_API_RETURN(glGetError); } -void API_ENTRY(glGetFloatv)(GLenum pname, GLfloat * data) { +void API_ENTRY(__glGetFloatv)(GLenum pname, GLfloat * data) { CALL_GL_API(glGetFloatv, pname, data); } void API_ENTRY(glGetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint * params) { CALL_GL_API(glGetFramebufferAttachmentParameteriv, target, attachment, pname, params); } -void API_ENTRY(glGetIntegerv)(GLenum pname, GLint * data) { +void API_ENTRY(__glGetIntegerv)(GLenum pname, GLint * data) { CALL_GL_API(glGetIntegerv, pname, data); } void API_ENTRY(glGetProgramiv)(GLuint program, GLenum pname, GLint * params) { @@ -604,7 +604,7 @@ void API_ENTRY(glClearBufferfv)(GLenum buffer, GLint drawbuffer, const GLfloat * void API_ENTRY(glClearBufferfi)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) { CALL_GL_API(glClearBufferfi, buffer, drawbuffer, depth, stencil); } -const GLubyte * API_ENTRY(glGetStringi)(GLenum name, GLuint index) { +const GLubyte * API_ENTRY(__glGetStringi)(GLenum name, GLuint index) { CALL_GL_API_RETURN(glGetStringi, name, index); } void API_ENTRY(glCopyBufferSubData)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) { @@ -649,7 +649,7 @@ GLenum API_ENTRY(glClientWaitSync)(GLsync sync, GLbitfield flags, GLuint64 timeo void API_ENTRY(glWaitSync)(GLsync sync, GLbitfield flags, GLuint64 timeout) { CALL_GL_API(glWaitSync, sync, flags, timeout); } -void API_ENTRY(glGetInteger64v)(GLenum pname, GLint64 * data) { +void API_ENTRY(__glGetInteger64v)(GLenum pname, GLint64 * data) { CALL_GL_API(glGetInteger64v, pname, data); } void API_ENTRY(glGetSynciv)(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei * length, GLint * values) { diff --git a/opengl/libs/GLES_CM/gl.cpp b/opengl/libs/GLES_CM/gl.cpp index f05983c169..b1b31f8294 100644 --- a/opengl/libs/GLES_CM/gl.cpp +++ b/opengl/libs/GLES_CM/gl.cpp @@ -138,7 +138,7 @@ GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type, #elif defined(__i386__) - #define API_ENTRY(_api) __attribute__((noinline)) _api + #define API_ENTRY(_api) __attribute__((noinline,optimize("omit-frame-pointer"))) _api #define CALL_GL_API(_api, ...) \ register void* fn; \ @@ -157,7 +157,7 @@ GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type, #elif defined(__x86_64__) - #define API_ENTRY(_api) __attribute__((noinline)) _api + #define API_ENTRY(_api) __attribute__((noinline,optimize("omit-frame-pointer"))) _api #define CALL_GL_API(_api, ...) \ register void** fn; \ @@ -174,15 +174,48 @@ GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type, : "cc" \ ); +#elif defined(__mips64) + + #define API_ENTRY(_api) __attribute__((noinline)) _api + + #define CALL_GL_API(_api, ...) \ + register unsigned long _t0 asm("$12"); \ + register unsigned long _fn asm("$25"); \ + register unsigned long _tls asm("$3"); \ + register unsigned long _v0 asm("$2"); \ + asm volatile( \ + ".set push\n\t" \ + ".set noreorder\n\t" \ + "rdhwr %[tls], $29\n\t" \ + "ld %[t0], %[OPENGL_API](%[tls])\n\t" \ + "beqz %[t0], 1f\n\t" \ + " move %[fn], $ra\n\t" \ + "ld %[t0], %[API](%[t0])\n\t" \ + "beqz %[t0], 1f\n\t" \ + " nop\n\t" \ + "move %[fn], %[t0]\n\t" \ + "1:\n\t" \ + "jalr $0, %[fn]\n\t" \ + " move %[v0], $0\n\t" \ + ".set pop\n\t" \ + : [fn] "=c"(_fn), \ + [tls] "=&r"(_tls), \ + [t0] "=&r"(_t0), \ + [v0] "=&r"(_v0) \ + : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*sizeof(void*)),\ + [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \ + : \ + ); + #elif defined(__mips__) #define API_ENTRY(_api) __attribute__((noinline)) _api #define CALL_GL_API(_api, ...) \ - register unsigned int _t0 asm("t0"); \ - register unsigned int _fn asm("t1"); \ - register unsigned int _tls asm("v1"); \ - register unsigned int _v0 asm("v0"); \ + register unsigned int _t0 asm("$8"); \ + register unsigned int _fn asm("$25"); \ + register unsigned int _tls asm("$3"); \ + register unsigned int _v0 asm("$2"); \ asm volatile( \ ".set push\n\t" \ ".set noreorder\n\t" \ @@ -191,10 +224,12 @@ GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type, "lw %[t0], %[OPENGL_API](%[tls])\n\t" \ "beqz %[t0], 1f\n\t" \ " move %[fn], $ra\n\t" \ - "lw %[fn], %[API](%[t0])\n\t" \ - "movz %[fn], $ra, %[fn]\n\t" \ + "lw %[t0], %[API](%[t0])\n\t" \ + "beqz %[t0], 1f\n\t" \ + " nop\n\t" \ + "move %[fn], %[t0]\n\t" \ "1:\n\t" \ - "j %[fn]\n\t" \ + "jalr $0, %[fn]\n\t" \ " move %[v0], $0\n\t" \ ".set pop\n\t" \ : [fn] "=c"(_fn), \ diff --git a/opengl/libs/GLES_trace/Android.mk b/opengl/libs/GLES_trace/Android.mk index 846932dd35..24c4be2da8 100644 --- a/opengl/libs/GLES_trace/Android.mk +++ b/opengl/libs/GLES_trace/Android.mk @@ -1,6 +1,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_SRC_FILES := \ src/gltrace_api.cpp \ @@ -9,20 +10,18 @@ LOCAL_SRC_FILES := \ src/gltrace_eglapi.cpp \ src/gltrace_fixup.cpp \ src/gltrace_hooks.cpp \ - src/gltrace.pb.cpp \ - src/gltrace_transport.cpp + src/gltrace_transport.cpp \ + $(call all-proto-files-under, proto) LOCAL_C_INCLUDES := \ $(LOCAL_PATH) \ $(LOCAL_PATH)/../ \ - external/stlport/stlport \ - external/protobuf/src \ - external \ - bionic - -LOCAL_CFLAGS := -DGOOGLE_PROTOBUF_NO_RTTI -LOCAL_STATIC_LIBRARIES := libprotobuf-cpp-2.3.0-lite liblzf -LOCAL_SHARED_LIBRARIES := libcutils libutils liblog libstlport + external + +LOCAL_STATIC_LIBRARIES := liblzf +LOCAL_SHARED_LIBRARIES := libcutils libutils liblog + +LOCAL_PROTOC_OPTIMIZE_TYPE := lite LOCAL_CFLAGS += -DLOG_TAG=\"libGLES_trace\" diff --git a/opengl/libs/GLES_trace/dev.make b/opengl/libs/GLES_trace/dev.make index a46260c35a..3405d8e24e 100644 --- a/opengl/libs/GLES_trace/dev.make +++ b/opengl/libs/GLES_trace/dev.make @@ -1,11 +1,6 @@ ## NOTE ## This file is used for development purposes only. It is not used by the build system. -# generate protocol buffer files -genproto: gltrace.proto - aprotoc --cpp_out=src --java_out=java gltrace.proto - mv src/gltrace.pb.cc src/gltrace.pb.cpp - sync: adb root adb remount diff --git a/opengl/libs/GLES_trace/gltrace.proto b/opengl/libs/GLES_trace/proto/gltrace.proto index 00303c2f0e..0344787266 100644 --- a/opengl/libs/GLES_trace/gltrace.proto +++ b/opengl/libs/GLES_trace/proto/gltrace.proto @@ -23,6 +23,8 @@ option java_outer_classname = "GLProtoBuf"; message GLMessage { enum Function { + option allow_alias = true; + glActiveTexture = 0; glAlphaFunc = 1; glAlphaFuncx = 2; diff --git a/opengl/libs/GLES_trace/src/gltrace.pb.cpp b/opengl/libs/GLES_trace/src/gltrace.pb.cpp deleted file mode 100644 index c0867cd385..0000000000 --- a/opengl/libs/GLES_trace/src/gltrace.pb.cpp +++ /dev/null @@ -1,2715 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! - -#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION -#include "gltrace.pb.h" -#include <google/protobuf/stubs/once.h> -#include <google/protobuf/io/coded_stream.h> -#include <google/protobuf/wire_format_lite_inl.h> -// @@protoc_insertion_point(includes) - -namespace android { -namespace gltrace { - -void protobuf_ShutdownFile_gltrace_2eproto() { - delete GLMessage::default_instance_; - delete GLMessage_DataType::default_instance_; - delete GLMessage_FrameBuffer::default_instance_; -} - -void protobuf_AddDesc_gltrace_2eproto() { - static bool already_here = false; - if (already_here) return; - already_here = true; - GOOGLE_PROTOBUF_VERIFY_VERSION; - - GLMessage::default_instance_ = new GLMessage(); - GLMessage_DataType::default_instance_ = new GLMessage_DataType(); - GLMessage_FrameBuffer::default_instance_ = new GLMessage_FrameBuffer(); - GLMessage::default_instance_->InitAsDefaultInstance(); - GLMessage_DataType::default_instance_->InitAsDefaultInstance(); - GLMessage_FrameBuffer::default_instance_->InitAsDefaultInstance(); - ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_gltrace_2eproto); -} - -// Force AddDescriptors() to be called at static initialization time. -struct StaticDescriptorInitializer_gltrace_2eproto { - StaticDescriptorInitializer_gltrace_2eproto() { - protobuf_AddDesc_gltrace_2eproto(); - } -} static_descriptor_initializer_gltrace_2eproto_; - - -// =================================================================== - -bool GLMessage_Function_IsValid(int value) { - switch(value) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - case 9: - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: - case 16: - case 17: - case 18: - case 19: - case 20: - case 21: - case 22: - case 23: - case 24: - case 25: - case 26: - case 27: - case 28: - case 29: - case 30: - case 31: - case 32: - case 33: - case 34: - case 35: - case 36: - case 37: - case 38: - case 39: - case 40: - case 41: - case 42: - case 43: - case 44: - case 45: - case 46: - case 47: - case 48: - case 49: - case 50: - case 51: - case 52: - case 53: - case 54: - case 55: - case 56: - case 57: - case 58: - case 59: - case 60: - case 61: - case 62: - case 63: - case 64: - case 65: - case 66: - case 67: - case 68: - case 69: - case 70: - case 71: - case 72: - case 73: - case 74: - case 75: - case 76: - case 77: - case 78: - case 79: - case 80: - case 81: - case 82: - case 83: - case 84: - case 85: - case 86: - case 87: - case 88: - case 89: - case 90: - case 91: - case 92: - case 93: - case 94: - case 95: - case 96: - case 97: - case 98: - case 99: - case 100: - case 101: - case 102: - case 103: - case 104: - case 105: - case 106: - case 107: - case 108: - case 109: - case 110: - case 111: - case 112: - case 113: - case 114: - case 115: - case 116: - case 117: - case 118: - case 119: - case 120: - case 121: - case 122: - case 123: - case 124: - case 125: - case 126: - case 127: - case 128: - case 129: - case 130: - case 131: - case 132: - case 133: - case 134: - case 135: - case 136: - case 137: - case 138: - case 139: - case 140: - case 141: - case 142: - case 143: - case 144: - case 145: - case 146: - case 147: - case 148: - case 149: - case 150: - case 151: - case 152: - case 153: - case 154: - case 155: - case 156: - case 157: - case 158: - case 159: - case 160: - case 161: - case 162: - case 163: - case 164: - case 165: - case 166: - case 167: - case 168: - case 169: - case 170: - case 171: - case 172: - case 173: - case 174: - case 175: - case 176: - case 177: - case 178: - case 179: - case 180: - case 181: - case 182: - case 183: - case 184: - case 185: - case 186: - case 187: - case 188: - case 189: - case 190: - case 191: - case 192: - case 193: - case 194: - case 195: - case 196: - case 197: - case 198: - case 199: - case 200: - case 201: - case 202: - case 203: - case 204: - case 205: - case 206: - case 207: - case 208: - case 209: - case 210: - case 211: - case 212: - case 213: - case 214: - case 215: - case 216: - case 217: - case 218: - case 219: - case 220: - case 221: - case 222: - case 223: - case 224: - case 225: - case 226: - case 227: - case 228: - case 229: - case 230: - case 231: - case 232: - case 233: - case 234: - case 235: - case 236: - case 237: - case 238: - case 239: - case 240: - case 241: - case 242: - case 243: - case 244: - case 245: - case 246: - case 247: - case 248: - case 249: - case 250: - case 251: - case 252: - case 253: - case 254: - case 255: - case 256: - case 257: - case 258: - case 259: - case 260: - case 261: - case 262: - case 263: - case 264: - case 265: - case 266: - case 267: - case 268: - case 269: - case 270: - case 271: - case 272: - case 273: - case 274: - case 275: - case 276: - case 277: - case 278: - case 279: - case 280: - case 281: - case 282: - case 283: - case 284: - case 285: - case 286: - case 287: - case 288: - case 289: - case 290: - case 291: - case 292: - case 293: - case 294: - case 295: - case 296: - case 297: - case 298: - case 299: - case 300: - case 301: - case 302: - case 303: - case 304: - case 305: - case 306: - case 307: - case 308: - case 309: - case 310: - case 311: - case 312: - case 313: - case 314: - case 315: - case 316: - case 317: - case 318: - case 319: - case 320: - case 321: - case 322: - case 323: - case 324: - case 325: - case 326: - case 327: - case 328: - case 329: - case 330: - case 331: - case 332: - case 333: - case 334: - case 335: - case 336: - case 337: - case 338: - case 339: - case 340: - case 341: - case 342: - case 343: - case 344: - case 345: - case 346: - case 347: - case 348: - case 349: - case 350: - case 351: - case 352: - case 353: - case 354: - case 355: - case 356: - case 357: - case 358: - case 359: - case 360: - case 361: - case 362: - case 363: - case 364: - case 365: - case 366: - case 367: - case 368: - case 369: - case 370: - case 371: - case 372: - case 373: - case 374: - case 375: - case 376: - case 377: - case 378: - case 379: - case 380: - case 381: - case 382: - case 383: - case 384: - case 385: - case 386: - case 387: - case 388: - case 389: - case 390: - case 391: - case 392: - case 393: - case 394: - case 395: - case 396: - case 397: - case 398: - case 399: - case 400: - case 401: - case 402: - case 403: - case 404: - case 405: - case 406: - case 407: - case 408: - case 409: - case 410: - case 411: - case 412: - case 413: - case 414: - case 415: - case 416: - case 417: - case 418: - case 419: - case 420: - case 421: - case 422: - case 423: - case 424: - case 425: - case 426: - case 427: - case 428: - case 429: - case 430: - case 431: - case 432: - case 433: - case 434: - case 435: - case 436: - case 437: - case 438: - case 439: - case 440: - case 441: - case 442: - case 443: - case 444: - case 445: - case 446: - case 447: - case 448: - case 449: - case 450: - case 451: - case 452: - case 453: - case 454: - case 455: - case 456: - case 457: - case 458: - case 459: - case 460: - case 461: - case 462: - case 463: - case 464: - case 465: - case 466: - case 467: - case 468: - case 469: - case 470: - case 471: - case 472: - case 473: - case 474: - case 475: - case 476: - case 477: - case 478: - case 479: - case 480: - case 481: - case 482: - case 483: - case 484: - case 485: - case 486: - case 487: - case 488: - case 489: - case 490: - case 491: - case 492: - case 493: - case 494: - case 495: - case 496: - case 497: - case 498: - case 499: - case 500: - case 501: - case 502: - case 503: - case 504: - case 505: - case 506: - case 507: - case 508: - case 509: - case 510: - case 511: - case 512: - case 513: - case 514: - case 515: - case 516: - case 517: - case 518: - case 519: - case 520: - case 521: - case 522: - case 523: - case 524: - case 525: - case 526: - case 527: - case 528: - case 529: - case 530: - case 531: - case 532: - case 533: - case 534: - case 535: - case 536: - case 537: - case 538: - case 539: - case 540: - case 541: - case 542: - case 543: - case 544: - case 545: - case 546: - case 547: - case 548: - case 549: - case 550: - case 551: - case 552: - case 553: - case 554: - case 555: - case 556: - case 557: - case 558: - case 559: - case 560: - case 561: - case 562: - case 563: - case 564: - case 565: - case 566: - case 567: - case 568: - case 569: - case 570: - case 571: - case 572: - case 573: - case 574: - case 575: - case 576: - case 577: - case 578: - case 579: - case 580: - case 581: - case 582: - case 583: - case 584: - case 585: - case 586: - case 587: - case 588: - case 589: - case 590: - case 591: - case 592: - case 593: - case 594: - case 595: - case 596: - case 597: - case 598: - case 599: - case 600: - case 601: - case 602: - case 603: - case 604: - case 605: - case 606: - case 607: - case 608: - case 609: - case 610: - case 611: - case 612: - case 613: - case 614: - case 615: - case 616: - case 617: - case 618: - case 619: - case 620: - case 621: - case 622: - case 623: - case 624: - case 625: - case 626: - case 627: - case 628: - case 629: - case 630: - case 631: - case 632: - case 633: - case 634: - case 635: - case 636: - case 637: - case 638: - case 639: - case 640: - case 641: - case 642: - case 643: - case 644: - case 645: - case 646: - case 647: - case 648: - case 649: - case 650: - case 651: - case 652: - case 653: - case 654: - case 655: - case 656: - case 657: - case 658: - case 659: - case 660: - case 661: - case 662: - case 663: - case 664: - case 665: - case 666: - case 667: - case 668: - case 669: - case 670: - case 671: - case 672: - case 673: - case 674: - case 675: - case 676: - case 677: - case 678: - case 679: - case 680: - case 681: - case 682: - case 683: - case 684: - case 685: - case 686: - case 687: - case 688: - case 689: - case 690: - case 691: - case 692: - case 693: - case 694: - case 695: - case 696: - case 697: - case 698: - case 699: - case 700: - case 701: - case 702: - case 703: - case 704: - case 705: - case 706: - case 707: - case 708: - case 709: - case 710: - case 711: - case 712: - case 713: - case 714: - case 715: - case 716: - case 717: - case 718: - case 719: - case 720: - case 721: - case 722: - case 723: - case 724: - case 725: - case 726: - case 727: - case 728: - case 729: - case 730: - case 2000: - case 2001: - case 2002: - case 2003: - case 2004: - case 2005: - case 2006: - case 2007: - case 2008: - case 2009: - case 2010: - case 2011: - case 2012: - case 2013: - case 2014: - case 2015: - case 2016: - case 2017: - case 2018: - case 2019: - case 2020: - case 2021: - case 2022: - case 2023: - case 2024: - case 2025: - case 2026: - case 2027: - case 2028: - case 2029: - case 2030: - case 2031: - case 2032: - case 2033: - case 2034: - case 2035: - case 2036: - case 2037: - case 2038: - case 2039: - case 2040: - case 2041: - case 2042: - case 2043: - case 2044: - case 2045: - case 3000: - case 3001: - return true; - default: - return false; - } -} - -#ifndef _MSC_VER -const GLMessage_Function GLMessage::glActiveTexture; -const GLMessage_Function GLMessage::glAlphaFunc; -const GLMessage_Function GLMessage::glAlphaFuncx; -const GLMessage_Function GLMessage::glAlphaFuncxOES; -const GLMessage_Function GLMessage::glAttachShader; -const GLMessage_Function GLMessage::glBeginPerfMonitorAMD; -const GLMessage_Function GLMessage::glBindAttribLocation; -const GLMessage_Function GLMessage::glBindBuffer; -const GLMessage_Function GLMessage::glBindFramebuffer; -const GLMessage_Function GLMessage::glBindFramebufferOES; -const GLMessage_Function GLMessage::glBindRenderbuffer; -const GLMessage_Function GLMessage::glBindRenderbufferOES; -const GLMessage_Function GLMessage::glBindTexture; -const GLMessage_Function GLMessage::glBindVertexArrayOES; -const GLMessage_Function GLMessage::glBlendColor; -const GLMessage_Function GLMessage::glBlendEquation; -const GLMessage_Function GLMessage::glBlendEquationOES; -const GLMessage_Function GLMessage::glBlendEquationSeparate; -const GLMessage_Function GLMessage::glBlendEquationSeparateOES; -const GLMessage_Function GLMessage::glBlendFunc; -const GLMessage_Function GLMessage::glBlendFuncSeparate; -const GLMessage_Function GLMessage::glBlendFuncSeparateOES; -const GLMessage_Function GLMessage::glBufferData; -const GLMessage_Function GLMessage::glBufferSubData; -const GLMessage_Function GLMessage::glCheckFramebufferStatus; -const GLMessage_Function GLMessage::glCheckFramebufferStatusOES; -const GLMessage_Function GLMessage::glClearColor; -const GLMessage_Function GLMessage::glClearColorx; -const GLMessage_Function GLMessage::glClearColorxOES; -const GLMessage_Function GLMessage::glClearDepthf; -const GLMessage_Function GLMessage::glClearDepthfOES; -const GLMessage_Function GLMessage::glClearDepthx; -const GLMessage_Function GLMessage::glClearDepthxOES; -const GLMessage_Function GLMessage::glClear; -const GLMessage_Function GLMessage::glClearStencil; -const GLMessage_Function GLMessage::glClientActiveTexture; -const GLMessage_Function GLMessage::glClipPlanef; -const GLMessage_Function GLMessage::glClipPlanefIMG; -const GLMessage_Function GLMessage::glClipPlanefOES; -const GLMessage_Function GLMessage::glClipPlanex; -const GLMessage_Function GLMessage::glClipPlanexIMG; -const GLMessage_Function GLMessage::glClipPlanexOES; -const GLMessage_Function GLMessage::glColor4f; -const GLMessage_Function GLMessage::glColor4ub; -const GLMessage_Function GLMessage::glColor4x; -const GLMessage_Function GLMessage::glColor4xOES; -const GLMessage_Function GLMessage::glColorMask; -const GLMessage_Function GLMessage::glColorPointer; -const GLMessage_Function GLMessage::glCompileShader; -const GLMessage_Function GLMessage::glCompressedTexImage2D; -const GLMessage_Function GLMessage::glCompressedTexImage3DOES; -const GLMessage_Function GLMessage::glCompressedTexSubImage2D; -const GLMessage_Function GLMessage::glCompressedTexSubImage3DOES; -const GLMessage_Function GLMessage::glCopyTexImage2D; -const GLMessage_Function GLMessage::glCopyTexSubImage2D; -const GLMessage_Function GLMessage::glCopyTexSubImage3DOES; -const GLMessage_Function GLMessage::glCoverageMaskNV; -const GLMessage_Function GLMessage::glCoverageOperationNV; -const GLMessage_Function GLMessage::glCreateProgram; -const GLMessage_Function GLMessage::glCreateShader; -const GLMessage_Function GLMessage::glCullFace; -const GLMessage_Function GLMessage::glCurrentPaletteMatrixOES; -const GLMessage_Function GLMessage::glDeleteBuffers; -const GLMessage_Function GLMessage::glDeleteFencesNV; -const GLMessage_Function GLMessage::glDeleteFramebuffers; -const GLMessage_Function GLMessage::glDeleteFramebuffersOES; -const GLMessage_Function GLMessage::glDeletePerfMonitorsAMD; -const GLMessage_Function GLMessage::glDeleteProgram; -const GLMessage_Function GLMessage::glDeleteRenderbuffers; -const GLMessage_Function GLMessage::glDeleteRenderbuffersOES; -const GLMessage_Function GLMessage::glDeleteShader; -const GLMessage_Function GLMessage::glDeleteTextures; -const GLMessage_Function GLMessage::glDeleteVertexArraysOES; -const GLMessage_Function GLMessage::glDepthFunc; -const GLMessage_Function GLMessage::glDepthMask; -const GLMessage_Function GLMessage::glDepthRangef; -const GLMessage_Function GLMessage::glDepthRangefOES; -const GLMessage_Function GLMessage::glDepthRangex; -const GLMessage_Function GLMessage::glDepthRangexOES; -const GLMessage_Function GLMessage::glDetachShader; -const GLMessage_Function GLMessage::glDisableClientState; -const GLMessage_Function GLMessage::glDisableDriverControlQCOM; -const GLMessage_Function GLMessage::glDisable; -const GLMessage_Function GLMessage::glDisableVertexAttribArray; -const GLMessage_Function GLMessage::glDiscardFramebufferEXT; -const GLMessage_Function GLMessage::glDrawArrays; -const GLMessage_Function GLMessage::glDrawElements; -const GLMessage_Function GLMessage::glDrawTexfOES; -const GLMessage_Function GLMessage::glDrawTexfvOES; -const GLMessage_Function GLMessage::glDrawTexiOES; -const GLMessage_Function GLMessage::glDrawTexivOES; -const GLMessage_Function GLMessage::glDrawTexsOES; -const GLMessage_Function GLMessage::glDrawTexsvOES; -const GLMessage_Function GLMessage::glDrawTexxOES; -const GLMessage_Function GLMessage::glDrawTexxvOES; -const GLMessage_Function GLMessage::glEGLImageTargetRenderbufferStorageOES; -const GLMessage_Function GLMessage::glEGLImageTargetTexture2DOES; -const GLMessage_Function GLMessage::glEnableClientState; -const GLMessage_Function GLMessage::glEnableDriverControlQCOM; -const GLMessage_Function GLMessage::glEnable; -const GLMessage_Function GLMessage::glEnableVertexAttribArray; -const GLMessage_Function GLMessage::glEndPerfMonitorAMD; -const GLMessage_Function GLMessage::glEndTilingQCOM; -const GLMessage_Function GLMessage::glExtGetBufferPointervQCOM; -const GLMessage_Function GLMessage::glExtGetBuffersQCOM; -const GLMessage_Function GLMessage::glExtGetFramebuffersQCOM; -const GLMessage_Function GLMessage::glExtGetProgramBinarySourceQCOM; -const GLMessage_Function GLMessage::glExtGetProgramsQCOM; -const GLMessage_Function GLMessage::glExtGetRenderbuffersQCOM; -const GLMessage_Function GLMessage::glExtGetShadersQCOM; -const GLMessage_Function GLMessage::glExtGetTexLevelParameterivQCOM; -const GLMessage_Function GLMessage::glExtGetTexSubImageQCOM; -const GLMessage_Function GLMessage::glExtGetTexturesQCOM; -const GLMessage_Function GLMessage::glExtIsProgramBinaryQCOM; -const GLMessage_Function GLMessage::glExtTexObjectStateOverrideiQCOM; -const GLMessage_Function GLMessage::glFinishFenceNV; -const GLMessage_Function GLMessage::glFinish; -const GLMessage_Function GLMessage::glFlush; -const GLMessage_Function GLMessage::glFogf; -const GLMessage_Function GLMessage::glFogfv; -const GLMessage_Function GLMessage::glFogx; -const GLMessage_Function GLMessage::glFogxOES; -const GLMessage_Function GLMessage::glFogxv; -const GLMessage_Function GLMessage::glFogxvOES; -const GLMessage_Function GLMessage::glFramebufferRenderbuffer; -const GLMessage_Function GLMessage::glFramebufferRenderbufferOES; -const GLMessage_Function GLMessage::glFramebufferTexture2D; -const GLMessage_Function GLMessage::glFramebufferTexture2DMultisampleIMG; -const GLMessage_Function GLMessage::glFramebufferTexture2DOES; -const GLMessage_Function GLMessage::glFramebufferTexture3DOES; -const GLMessage_Function GLMessage::glFrontFace; -const GLMessage_Function GLMessage::glFrustumf; -const GLMessage_Function GLMessage::glFrustumfOES; -const GLMessage_Function GLMessage::glFrustumx; -const GLMessage_Function GLMessage::glFrustumxOES; -const GLMessage_Function GLMessage::glGenBuffers; -const GLMessage_Function GLMessage::glGenerateMipmap; -const GLMessage_Function GLMessage::glGenerateMipmapOES; -const GLMessage_Function GLMessage::glGenFencesNV; -const GLMessage_Function GLMessage::glGenFramebuffers; -const GLMessage_Function GLMessage::glGenFramebuffersOES; -const GLMessage_Function GLMessage::glGenPerfMonitorsAMD; -const GLMessage_Function GLMessage::glGenRenderbuffers; -const GLMessage_Function GLMessage::glGenRenderbuffersOES; -const GLMessage_Function GLMessage::glGenTextures; -const GLMessage_Function GLMessage::glGenVertexArraysOES; -const GLMessage_Function GLMessage::glGetActiveAttrib; -const GLMessage_Function GLMessage::glGetActiveUniform; -const GLMessage_Function GLMessage::glGetAttachedShaders; -const GLMessage_Function GLMessage::glGetAttribLocation; -const GLMessage_Function GLMessage::glGetBooleanv; -const GLMessage_Function GLMessage::glGetBufferParameteriv; -const GLMessage_Function GLMessage::glGetBufferPointervOES; -const GLMessage_Function GLMessage::glGetClipPlanef; -const GLMessage_Function GLMessage::glGetClipPlanefOES; -const GLMessage_Function GLMessage::glGetClipPlanex; -const GLMessage_Function GLMessage::glGetClipPlanexOES; -const GLMessage_Function GLMessage::glGetDriverControlsQCOM; -const GLMessage_Function GLMessage::glGetDriverControlStringQCOM; -const GLMessage_Function GLMessage::glGetError; -const GLMessage_Function GLMessage::glGetFenceivNV; -const GLMessage_Function GLMessage::glGetFixedv; -const GLMessage_Function GLMessage::glGetFixedvOES; -const GLMessage_Function GLMessage::glGetFloatv; -const GLMessage_Function GLMessage::glGetFramebufferAttachmentParameteriv; -const GLMessage_Function GLMessage::glGetFramebufferAttachmentParameterivOES; -const GLMessage_Function GLMessage::glGetIntegerv; -const GLMessage_Function GLMessage::glGetLightfv; -const GLMessage_Function GLMessage::glGetLightxv; -const GLMessage_Function GLMessage::glGetLightxvOES; -const GLMessage_Function GLMessage::glGetMaterialfv; -const GLMessage_Function GLMessage::glGetMaterialxv; -const GLMessage_Function GLMessage::glGetMaterialxvOES; -const GLMessage_Function GLMessage::glGetPerfMonitorCounterDataAMD; -const GLMessage_Function GLMessage::glGetPerfMonitorCounterInfoAMD; -const GLMessage_Function GLMessage::glGetPerfMonitorCountersAMD; -const GLMessage_Function GLMessage::glGetPerfMonitorCounterStringAMD; -const GLMessage_Function GLMessage::glGetPerfMonitorGroupsAMD; -const GLMessage_Function GLMessage::glGetPerfMonitorGroupStringAMD; -const GLMessage_Function GLMessage::glGetPointerv; -const GLMessage_Function GLMessage::glGetProgramBinaryOES; -const GLMessage_Function GLMessage::glGetProgramInfoLog; -const GLMessage_Function GLMessage::glGetProgramiv; -const GLMessage_Function GLMessage::glGetRenderbufferParameteriv; -const GLMessage_Function GLMessage::glGetRenderbufferParameterivOES; -const GLMessage_Function GLMessage::glGetShaderInfoLog; -const GLMessage_Function GLMessage::glGetShaderiv; -const GLMessage_Function GLMessage::glGetShaderPrecisionFormat; -const GLMessage_Function GLMessage::glGetShaderSource; -const GLMessage_Function GLMessage::glGetString; -const GLMessage_Function GLMessage::glGetTexEnvfv; -const GLMessage_Function GLMessage::glGetTexEnviv; -const GLMessage_Function GLMessage::glGetTexEnvxv; -const GLMessage_Function GLMessage::glGetTexEnvxvOES; -const GLMessage_Function GLMessage::glGetTexGenfvOES; -const GLMessage_Function GLMessage::glGetTexGenivOES; -const GLMessage_Function GLMessage::glGetTexGenxvOES; -const GLMessage_Function GLMessage::glGetTexParameterfv; -const GLMessage_Function GLMessage::glGetTexParameteriv; -const GLMessage_Function GLMessage::glGetTexParameterxv; -const GLMessage_Function GLMessage::glGetTexParameterxvOES; -const GLMessage_Function GLMessage::glGetUniformfv; -const GLMessage_Function GLMessage::glGetUniformiv; -const GLMessage_Function GLMessage::glGetUniformLocation; -const GLMessage_Function GLMessage::glGetVertexAttribfv; -const GLMessage_Function GLMessage::glGetVertexAttribiv; -const GLMessage_Function GLMessage::glGetVertexAttribPointerv; -const GLMessage_Function GLMessage::glHint; -const GLMessage_Function GLMessage::glIsBuffer; -const GLMessage_Function GLMessage::glIsEnabled; -const GLMessage_Function GLMessage::glIsFenceNV; -const GLMessage_Function GLMessage::glIsFramebuffer; -const GLMessage_Function GLMessage::glIsFramebufferOES; -const GLMessage_Function GLMessage::glIsProgram; -const GLMessage_Function GLMessage::glIsRenderbuffer; -const GLMessage_Function GLMessage::glIsRenderbufferOES; -const GLMessage_Function GLMessage::glIsShader; -const GLMessage_Function GLMessage::glIsTexture; -const GLMessage_Function GLMessage::glIsVertexArrayOES; -const GLMessage_Function GLMessage::glLightf; -const GLMessage_Function GLMessage::glLightfv; -const GLMessage_Function GLMessage::glLightModelf; -const GLMessage_Function GLMessage::glLightModelfv; -const GLMessage_Function GLMessage::glLightModelx; -const GLMessage_Function GLMessage::glLightModelxOES; -const GLMessage_Function GLMessage::glLightModelxv; -const GLMessage_Function GLMessage::glLightModelxvOES; -const GLMessage_Function GLMessage::glLightx; -const GLMessage_Function GLMessage::glLightxOES; -const GLMessage_Function GLMessage::glLightxv; -const GLMessage_Function GLMessage::glLightxvOES; -const GLMessage_Function GLMessage::glLineWidth; -const GLMessage_Function GLMessage::glLineWidthx; -const GLMessage_Function GLMessage::glLineWidthxOES; -const GLMessage_Function GLMessage::glLinkProgram; -const GLMessage_Function GLMessage::glLoadIdentity; -const GLMessage_Function GLMessage::glLoadMatrixf; -const GLMessage_Function GLMessage::glLoadMatrixx; -const GLMessage_Function GLMessage::glLoadMatrixxOES; -const GLMessage_Function GLMessage::glLoadPaletteFromModelViewMatrixOES; -const GLMessage_Function GLMessage::glLogicOp; -const GLMessage_Function GLMessage::glMapBufferOES; -const GLMessage_Function GLMessage::glMaterialf; -const GLMessage_Function GLMessage::glMaterialfv; -const GLMessage_Function GLMessage::glMaterialx; -const GLMessage_Function GLMessage::glMaterialxOES; -const GLMessage_Function GLMessage::glMaterialxv; -const GLMessage_Function GLMessage::glMaterialxvOES; -const GLMessage_Function GLMessage::glMatrixIndexPointerOES; -const GLMessage_Function GLMessage::glMatrixMode; -const GLMessage_Function GLMessage::glMultiDrawArraysEXT; -const GLMessage_Function GLMessage::glMultiDrawElementsEXT; -const GLMessage_Function GLMessage::glMultiTexCoord4f; -const GLMessage_Function GLMessage::glMultiTexCoord4x; -const GLMessage_Function GLMessage::glMultiTexCoord4xOES; -const GLMessage_Function GLMessage::glMultMatrixf; -const GLMessage_Function GLMessage::glMultMatrixx; -const GLMessage_Function GLMessage::glMultMatrixxOES; -const GLMessage_Function GLMessage::glNormal3f; -const GLMessage_Function GLMessage::glNormal3x; -const GLMessage_Function GLMessage::glNormal3xOES; -const GLMessage_Function GLMessage::glNormalPointer; -const GLMessage_Function GLMessage::glOrthof; -const GLMessage_Function GLMessage::glOrthofOES; -const GLMessage_Function GLMessage::glOrthox; -const GLMessage_Function GLMessage::glOrthoxOES; -const GLMessage_Function GLMessage::glPixelStorei; -const GLMessage_Function GLMessage::glPointParameterf; -const GLMessage_Function GLMessage::glPointParameterfv; -const GLMessage_Function GLMessage::glPointParameterx; -const GLMessage_Function GLMessage::glPointParameterxOES; -const GLMessage_Function GLMessage::glPointParameterxv; -const GLMessage_Function GLMessage::glPointParameterxvOES; -const GLMessage_Function GLMessage::glPointSize; -const GLMessage_Function GLMessage::glPointSizePointerOES; -const GLMessage_Function GLMessage::glPointSizex; -const GLMessage_Function GLMessage::glPointSizexOES; -const GLMessage_Function GLMessage::glPolygonOffset; -const GLMessage_Function GLMessage::glPolygonOffsetx; -const GLMessage_Function GLMessage::glPolygonOffsetxOES; -const GLMessage_Function GLMessage::glPopMatrix; -const GLMessage_Function GLMessage::glProgramBinaryOES; -const GLMessage_Function GLMessage::glPushMatrix; -const GLMessage_Function GLMessage::glQueryMatrixxOES; -const GLMessage_Function GLMessage::glReadPixels; -const GLMessage_Function GLMessage::glReleaseShaderCompiler; -const GLMessage_Function GLMessage::glRenderbufferStorage; -const GLMessage_Function GLMessage::glRenderbufferStorageMultisampleIMG; -const GLMessage_Function GLMessage::glRenderbufferStorageOES; -const GLMessage_Function GLMessage::glRotatef; -const GLMessage_Function GLMessage::glRotatex; -const GLMessage_Function GLMessage::glRotatexOES; -const GLMessage_Function GLMessage::glSampleCoverage; -const GLMessage_Function GLMessage::glSampleCoveragex; -const GLMessage_Function GLMessage::glSampleCoveragexOES; -const GLMessage_Function GLMessage::glScalef; -const GLMessage_Function GLMessage::glScalex; -const GLMessage_Function GLMessage::glScalexOES; -const GLMessage_Function GLMessage::glScissor; -const GLMessage_Function GLMessage::glSelectPerfMonitorCountersAMD; -const GLMessage_Function GLMessage::glSetFenceNV; -const GLMessage_Function GLMessage::glShadeModel; -const GLMessage_Function GLMessage::glShaderBinary; -const GLMessage_Function GLMessage::glShaderSource; -const GLMessage_Function GLMessage::glStartTilingQCOM; -const GLMessage_Function GLMessage::glStencilFunc; -const GLMessage_Function GLMessage::glStencilFuncSeparate; -const GLMessage_Function GLMessage::glStencilMask; -const GLMessage_Function GLMessage::glStencilMaskSeparate; -const GLMessage_Function GLMessage::glStencilOp; -const GLMessage_Function GLMessage::glStencilOpSeparate; -const GLMessage_Function GLMessage::glTestFenceNV; -const GLMessage_Function GLMessage::glTexCoordPointer; -const GLMessage_Function GLMessage::glTexEnvf; -const GLMessage_Function GLMessage::glTexEnvfv; -const GLMessage_Function GLMessage::glTexEnvi; -const GLMessage_Function GLMessage::glTexEnviv; -const GLMessage_Function GLMessage::glTexEnvx; -const GLMessage_Function GLMessage::glTexEnvxOES; -const GLMessage_Function GLMessage::glTexEnvxv; -const GLMessage_Function GLMessage::glTexEnvxvOES; -const GLMessage_Function GLMessage::glTexGenfOES; -const GLMessage_Function GLMessage::glTexGenfvOES; -const GLMessage_Function GLMessage::glTexGeniOES; -const GLMessage_Function GLMessage::glTexGenivOES; -const GLMessage_Function GLMessage::glTexGenxOES; -const GLMessage_Function GLMessage::glTexGenxvOES; -const GLMessage_Function GLMessage::glTexImage2D; -const GLMessage_Function GLMessage::glTexImage3DOES; -const GLMessage_Function GLMessage::glTexParameterf; -const GLMessage_Function GLMessage::glTexParameterfv; -const GLMessage_Function GLMessage::glTexParameteri; -const GLMessage_Function GLMessage::glTexParameteriv; -const GLMessage_Function GLMessage::glTexParameterx; -const GLMessage_Function GLMessage::glTexParameterxOES; -const GLMessage_Function GLMessage::glTexParameterxv; -const GLMessage_Function GLMessage::glTexParameterxvOES; -const GLMessage_Function GLMessage::glTexSubImage2D; -const GLMessage_Function GLMessage::glTexSubImage3DOES; -const GLMessage_Function GLMessage::glTranslatef; -const GLMessage_Function GLMessage::glTranslatex; -const GLMessage_Function GLMessage::glTranslatexOES; -const GLMessage_Function GLMessage::glUniform1f; -const GLMessage_Function GLMessage::glUniform1fv; -const GLMessage_Function GLMessage::glUniform1i; -const GLMessage_Function GLMessage::glUniform1iv; -const GLMessage_Function GLMessage::glUniform2f; -const GLMessage_Function GLMessage::glUniform2fv; -const GLMessage_Function GLMessage::glUniform2i; -const GLMessage_Function GLMessage::glUniform2iv; -const GLMessage_Function GLMessage::glUniform3f; -const GLMessage_Function GLMessage::glUniform3fv; -const GLMessage_Function GLMessage::glUniform3i; -const GLMessage_Function GLMessage::glUniform3iv; -const GLMessage_Function GLMessage::glUniform4f; -const GLMessage_Function GLMessage::glUniform4fv; -const GLMessage_Function GLMessage::glUniform4i; -const GLMessage_Function GLMessage::glUniform4iv; -const GLMessage_Function GLMessage::glUniformMatrix2fv; -const GLMessage_Function GLMessage::glUniformMatrix3fv; -const GLMessage_Function GLMessage::glUniformMatrix4fv; -const GLMessage_Function GLMessage::glUnmapBufferOES; -const GLMessage_Function GLMessage::glUseProgram; -const GLMessage_Function GLMessage::glValidateProgram; -const GLMessage_Function GLMessage::glVertexAttrib1f; -const GLMessage_Function GLMessage::glVertexAttrib1fv; -const GLMessage_Function GLMessage::glVertexAttrib2f; -const GLMessage_Function GLMessage::glVertexAttrib2fv; -const GLMessage_Function GLMessage::glVertexAttrib3f; -const GLMessage_Function GLMessage::glVertexAttrib3fv; -const GLMessage_Function GLMessage::glVertexAttrib4f; -const GLMessage_Function GLMessage::glVertexAttrib4fv; -const GLMessage_Function GLMessage::glVertexAttribPointer; -const GLMessage_Function GLMessage::glVertexPointer; -const GLMessage_Function GLMessage::glViewport; -const GLMessage_Function GLMessage::glWeightPointerOES; -const GLMessage_Function GLMessage::glReadBuffer; -const GLMessage_Function GLMessage::glDrawRangeElements; -const GLMessage_Function GLMessage::glTexImage3D; -const GLMessage_Function GLMessage::glTexSubImage3D; -const GLMessage_Function GLMessage::glCopyTexSubImage3D; -const GLMessage_Function GLMessage::glCompressedTexImage3D; -const GLMessage_Function GLMessage::glCompressedTexSubImage3D; -const GLMessage_Function GLMessage::glGenQueries; -const GLMessage_Function GLMessage::glDeleteQueries; -const GLMessage_Function GLMessage::glIsQuery; -const GLMessage_Function GLMessage::glBeginQuery; -const GLMessage_Function GLMessage::glEndQuery; -const GLMessage_Function GLMessage::glGetQueryiv; -const GLMessage_Function GLMessage::glGetQueryObjectuiv; -const GLMessage_Function GLMessage::glUnmapBuffer; -const GLMessage_Function GLMessage::glGetBufferPointerv; -const GLMessage_Function GLMessage::glDrawBuffers; -const GLMessage_Function GLMessage::glUniformMatrix2x3fv; -const GLMessage_Function GLMessage::glUniformMatrix3x2fv; -const GLMessage_Function GLMessage::glUniformMatrix2x4fv; -const GLMessage_Function GLMessage::glUniformMatrix4x2fv; -const GLMessage_Function GLMessage::glUniformMatrix3x4fv; -const GLMessage_Function GLMessage::glUniformMatrix4x3fv; -const GLMessage_Function GLMessage::glBlitFramebuffer; -const GLMessage_Function GLMessage::glRenderbufferStorageMultisample; -const GLMessage_Function GLMessage::glFramebufferTextureLayer; -const GLMessage_Function GLMessage::glMapBufferRange; -const GLMessage_Function GLMessage::glFlushMappedBufferRange; -const GLMessage_Function GLMessage::glBindVertexArray; -const GLMessage_Function GLMessage::glDeleteVertexArrays; -const GLMessage_Function GLMessage::glGenVertexArrays; -const GLMessage_Function GLMessage::glIsVertexArray; -const GLMessage_Function GLMessage::glGetIntegeri_v; -const GLMessage_Function GLMessage::glBeginTransformFeedback; -const GLMessage_Function GLMessage::glEndTransformFeedback; -const GLMessage_Function GLMessage::glBindBufferRange; -const GLMessage_Function GLMessage::glBindBufferBase; -const GLMessage_Function GLMessage::glTransformFeedbackVaryings; -const GLMessage_Function GLMessage::glGetTransformFeedbackVarying; -const GLMessage_Function GLMessage::glVertexAttribIPointer; -const GLMessage_Function GLMessage::glGetVertexAttribIiv; -const GLMessage_Function GLMessage::glGetVertexAttribIuiv; -const GLMessage_Function GLMessage::glVertexAttribI4i; -const GLMessage_Function GLMessage::glVertexAttribI4ui; -const GLMessage_Function GLMessage::glVertexAttribI4iv; -const GLMessage_Function GLMessage::glVertexAttribI4uiv; -const GLMessage_Function GLMessage::glGetUniformuiv; -const GLMessage_Function GLMessage::glGetFragDataLocation; -const GLMessage_Function GLMessage::glUniform1ui; -const GLMessage_Function GLMessage::glUniform2ui; -const GLMessage_Function GLMessage::glUniform3ui; -const GLMessage_Function GLMessage::glUniform4ui; -const GLMessage_Function GLMessage::glUniform1uiv; -const GLMessage_Function GLMessage::glUniform2uiv; -const GLMessage_Function GLMessage::glUniform3uiv; -const GLMessage_Function GLMessage::glUniform4uiv; -const GLMessage_Function GLMessage::glClearBufferiv; -const GLMessage_Function GLMessage::glClearBufferuiv; -const GLMessage_Function GLMessage::glClearBufferfv; -const GLMessage_Function GLMessage::glClearBufferfi; -const GLMessage_Function GLMessage::glGetStringi; -const GLMessage_Function GLMessage::glCopyBufferSubData; -const GLMessage_Function GLMessage::glGetUniformIndices; -const GLMessage_Function GLMessage::glGetActiveUniformsiv; -const GLMessage_Function GLMessage::glGetUniformBlockIndex; -const GLMessage_Function GLMessage::glGetActiveUniformBlockiv; -const GLMessage_Function GLMessage::glGetActiveUniformBlockName; -const GLMessage_Function GLMessage::glUniformBlockBinding; -const GLMessage_Function GLMessage::glDrawArraysInstanced; -const GLMessage_Function GLMessage::glDrawElementsInstanced; -const GLMessage_Function GLMessage::glFenceSync; -const GLMessage_Function GLMessage::glIsSync; -const GLMessage_Function GLMessage::glDeleteSync; -const GLMessage_Function GLMessage::glClientWaitSync; -const GLMessage_Function GLMessage::glWaitSync; -const GLMessage_Function GLMessage::glGetInteger64v; -const GLMessage_Function GLMessage::glGetSynciv; -const GLMessage_Function GLMessage::glGetInteger64i_v; -const GLMessage_Function GLMessage::glGetBufferParameteri64v; -const GLMessage_Function GLMessage::glGenSamplers; -const GLMessage_Function GLMessage::glDeleteSamplers; -const GLMessage_Function GLMessage::glIsSampler; -const GLMessage_Function GLMessage::glBindSampler; -const GLMessage_Function GLMessage::glSamplerParameteri; -const GLMessage_Function GLMessage::glSamplerParameteriv; -const GLMessage_Function GLMessage::glSamplerParameterf; -const GLMessage_Function GLMessage::glSamplerParameterfv; -const GLMessage_Function GLMessage::glGetSamplerParameteriv; -const GLMessage_Function GLMessage::glGetSamplerParameterfv; -const GLMessage_Function GLMessage::glVertexAttribDivisor; -const GLMessage_Function GLMessage::glBindTransformFeedback; -const GLMessage_Function GLMessage::glDeleteTransformFeedbacks; -const GLMessage_Function GLMessage::glGenTransformFeedbacks; -const GLMessage_Function GLMessage::glIsTransformFeedback; -const GLMessage_Function GLMessage::glPauseTransformFeedback; -const GLMessage_Function GLMessage::glResumeTransformFeedback; -const GLMessage_Function GLMessage::glGetProgramBinary; -const GLMessage_Function GLMessage::glProgramBinary; -const GLMessage_Function GLMessage::glProgramParameteri; -const GLMessage_Function GLMessage::glInvalidateFramebuffer; -const GLMessage_Function GLMessage::glInvalidateSubFramebuffer; -const GLMessage_Function GLMessage::glTexStorage2D; -const GLMessage_Function GLMessage::glTexStorage3D; -const GLMessage_Function GLMessage::glGetInternalformativ; -const GLMessage_Function GLMessage::glBeginPerfQueryINTEL; -const GLMessage_Function GLMessage::glCreatePerfQueryINTEL; -const GLMessage_Function GLMessage::glDeletePerfQueryINTEL; -const GLMessage_Function GLMessage::glEndPerfQueryINTEL; -const GLMessage_Function GLMessage::glGetFirstPerfQueryIdINTEL; -const GLMessage_Function GLMessage::glGetNextPerfQueryIdINTEL; -const GLMessage_Function GLMessage::glGetPerfCounterInfoINTEL; -const GLMessage_Function GLMessage::glGetPerfQueryDataINTEL; -const GLMessage_Function GLMessage::glGetPerfQueryIdByNameINTEL; -const GLMessage_Function GLMessage::glGetPerfQueryInfoINTEL; -const GLMessage_Function GLMessage::glBlendBarrierKHR; -const GLMessage_Function GLMessage::glBlendBarrierNV; -const GLMessage_Function GLMessage::glBlendParameteriNV; -const GLMessage_Function GLMessage::glBlitFramebufferNV; -const GLMessage_Function GLMessage::glFenceSyncAPPLE; -const GLMessage_Function GLMessage::glIsSyncAPPLE; -const GLMessage_Function GLMessage::glDeleteSyncAPPLE; -const GLMessage_Function GLMessage::glClientWaitSyncAPPLE; -const GLMessage_Function GLMessage::glWaitSyncAPPLE; -const GLMessage_Function GLMessage::glGetInteger64vAPPLE; -const GLMessage_Function GLMessage::glGetSyncivAPPLE; -const GLMessage_Function GLMessage::glCopyBufferSubDataNV; -const GLMessage_Function GLMessage::glActiveShaderProgramEXT; -const GLMessage_Function GLMessage::glAlphaFuncQCOM; -const GLMessage_Function GLMessage::glBeginQueryEXT; -const GLMessage_Function GLMessage::glBindProgramPipelineEXT; -const GLMessage_Function GLMessage::glBlitFramebufferANGLE; -const GLMessage_Function GLMessage::glCreateShaderProgramvEXT; -const GLMessage_Function GLMessage::glDeleteProgramPipelinesEXT; -const GLMessage_Function GLMessage::glDeleteQueriesEXT; -const GLMessage_Function GLMessage::glDrawBuffersNV; -const GLMessage_Function GLMessage::glEndQueryEXT; -const GLMessage_Function GLMessage::glFramebufferTexture2DMultisampleEXT; -const GLMessage_Function GLMessage::glGenProgramPipelinesEXT; -const GLMessage_Function GLMessage::glGenQueriesEXT; -const GLMessage_Function GLMessage::glGetGraphicsResetStatusEXT; -const GLMessage_Function GLMessage::glGetObjectLabelEXT; -const GLMessage_Function GLMessage::glGetProgramPipelineInfoLogEXT; -const GLMessage_Function GLMessage::glGetProgramPipelineivEXT; -const GLMessage_Function GLMessage::glGetQueryObjectuivEXT; -const GLMessage_Function GLMessage::glGetQueryivEXT; -const GLMessage_Function GLMessage::glGetnUniformfvEXT; -const GLMessage_Function GLMessage::glGetnUniformivEXT; -const GLMessage_Function GLMessage::glInsertEventMarkerEXT; -const GLMessage_Function GLMessage::glIsProgramPipelineEXT; -const GLMessage_Function GLMessage::glIsQueryEXT; -const GLMessage_Function GLMessage::glLabelObjectEXT; -const GLMessage_Function GLMessage::glPopGroupMarkerEXT; -const GLMessage_Function GLMessage::glProgramParameteriEXT; -const GLMessage_Function GLMessage::glProgramUniform1fEXT; -const GLMessage_Function GLMessage::glProgramUniform1fvEXT; -const GLMessage_Function GLMessage::glProgramUniform1iEXT; -const GLMessage_Function GLMessage::glProgramUniform1ivEXT; -const GLMessage_Function GLMessage::glProgramUniform2fEXT; -const GLMessage_Function GLMessage::glProgramUniform2fvEXT; -const GLMessage_Function GLMessage::glProgramUniform2iEXT; -const GLMessage_Function GLMessage::glProgramUniform2ivEXT; -const GLMessage_Function GLMessage::glProgramUniform3fEXT; -const GLMessage_Function GLMessage::glProgramUniform3fvEXT; -const GLMessage_Function GLMessage::glProgramUniform3iEXT; -const GLMessage_Function GLMessage::glProgramUniform3ivEXT; -const GLMessage_Function GLMessage::glProgramUniform4fEXT; -const GLMessage_Function GLMessage::glProgramUniform4fvEXT; -const GLMessage_Function GLMessage::glProgramUniform4iEXT; -const GLMessage_Function GLMessage::glProgramUniform4ivEXT; -const GLMessage_Function GLMessage::glProgramUniformMatrix2fvEXT; -const GLMessage_Function GLMessage::glProgramUniformMatrix3fvEXT; -const GLMessage_Function GLMessage::glProgramUniformMatrix4fvEXT; -const GLMessage_Function GLMessage::glPushGroupMarkerEXT; -const GLMessage_Function GLMessage::glReadBufferNV; -const GLMessage_Function GLMessage::glReadnPixelsEXT; -const GLMessage_Function GLMessage::glRenderbufferStorageMultisampleANGLE; -const GLMessage_Function GLMessage::glRenderbufferStorageMultisampleAPPLE; -const GLMessage_Function GLMessage::glRenderbufferStorageMultisampleEXT; -const GLMessage_Function GLMessage::glResolveMultisampleFramebufferAPPLE; -const GLMessage_Function GLMessage::glTexStorage1DEXT; -const GLMessage_Function GLMessage::glTexStorage2DEXT; -const GLMessage_Function GLMessage::glTexStorage3DEXT; -const GLMessage_Function GLMessage::glTextureStorage1DEXT; -const GLMessage_Function GLMessage::glTextureStorage2DEXT; -const GLMessage_Function GLMessage::glTextureStorage3DEXT; -const GLMessage_Function GLMessage::glUseProgramStagesEXT; -const GLMessage_Function GLMessage::glValidateProgramPipelineEXT; -const GLMessage_Function GLMessage::glCopyTextureLevelsAPPLE; -const GLMessage_Function GLMessage::glDebugMessageControlKHR; -const GLMessage_Function GLMessage::glDebugMessageInsertKHR; -const GLMessage_Function GLMessage::glDebugMessageCallbackKHR; -const GLMessage_Function GLMessage::glGetDebugMessageLogKHR; -const GLMessage_Function GLMessage::glPushDebugGroupKHR; -const GLMessage_Function GLMessage::glPopDebugGroupKHR; -const GLMessage_Function GLMessage::glObjectLabelKHR; -const GLMessage_Function GLMessage::glGetObjectLabelKHR; -const GLMessage_Function GLMessage::glObjectPtrLabelKHR; -const GLMessage_Function GLMessage::glGetObjectPtrLabelKHR; -const GLMessage_Function GLMessage::glGetPointervKHR; -const GLMessage_Function GLMessage::glDrawArraysInstancedANGLE; -const GLMessage_Function GLMessage::glDrawElementsInstancedANGLE; -const GLMessage_Function GLMessage::glVertexAttribDivisorANGLE; -const GLMessage_Function GLMessage::glDrawArraysInstancedEXT; -const GLMessage_Function GLMessage::glDrawElementsInstancedEXT; -const GLMessage_Function GLMessage::glVertexAttribDivisorEXT; -const GLMessage_Function GLMessage::glDrawArraysInstancedNV; -const GLMessage_Function GLMessage::glDrawElementsInstancedNV; -const GLMessage_Function GLMessage::glVertexAttribDivisorNV; -const GLMessage_Function GLMessage::glDrawBuffersEXT; -const GLMessage_Function GLMessage::glReadBufferIndexedEXT; -const GLMessage_Function GLMessage::glDrawBuffersIndexedEXT; -const GLMessage_Function GLMessage::glGetIntegeri_vEXT; -const GLMessage_Function GLMessage::glMapBufferRangeEXT; -const GLMessage_Function GLMessage::glFlushMappedBufferRangeEXT; -const GLMessage_Function GLMessage::glQueryCounterEXT; -const GLMessage_Function GLMessage::glGetQueryObjecti64vEXT; -const GLMessage_Function GLMessage::glGetQueryObjectivEXT; -const GLMessage_Function GLMessage::glGetQueryObjectui64vEXT; -const GLMessage_Function GLMessage::glGetTranslatedShaderSourceANGLE; -const GLMessage_Function GLMessage::glMinSampleShadingOES; -const GLMessage_Function GLMessage::glMultiTexCoord1bOES; -const GLMessage_Function GLMessage::glMultiTexCoord1bvOES; -const GLMessage_Function GLMessage::glMultiTexCoord2bOES; -const GLMessage_Function GLMessage::glMultiTexCoord2bvOES; -const GLMessage_Function GLMessage::glMultiTexCoord3bOES; -const GLMessage_Function GLMessage::glMultiTexCoord3bvOES; -const GLMessage_Function GLMessage::glMultiTexCoord4bOES; -const GLMessage_Function GLMessage::glMultiTexCoord4bvOES; -const GLMessage_Function GLMessage::glTexCoord1bOES; -const GLMessage_Function GLMessage::glTexCoord1bvOES; -const GLMessage_Function GLMessage::glTexCoord2bOES; -const GLMessage_Function GLMessage::glTexCoord2bvOES; -const GLMessage_Function GLMessage::glTexCoord3bOES; -const GLMessage_Function GLMessage::glTexCoord3bvOES; -const GLMessage_Function GLMessage::glTexCoord4bOES; -const GLMessage_Function GLMessage::glTexCoord4bvOES; -const GLMessage_Function GLMessage::glVertex2bOES; -const GLMessage_Function GLMessage::glVertex2bvOES; -const GLMessage_Function GLMessage::glVertex3bOES; -const GLMessage_Function GLMessage::glVertex3bvOES; -const GLMessage_Function GLMessage::glVertex4bOES; -const GLMessage_Function GLMessage::glVertex4bvOES; -const GLMessage_Function GLMessage::glProgramUniform1uiEXT; -const GLMessage_Function GLMessage::glProgramUniform2uiEXT; -const GLMessage_Function GLMessage::glProgramUniform3uiEXT; -const GLMessage_Function GLMessage::glProgramUniform4uiEXT; -const GLMessage_Function GLMessage::glProgramUniform1uivEXT; -const GLMessage_Function GLMessage::glProgramUniform2uivEXT; -const GLMessage_Function GLMessage::glProgramUniform3uivEXT; -const GLMessage_Function GLMessage::glProgramUniform4uivEXT; -const GLMessage_Function GLMessage::glProgramUniformMatrix2x3fvEXT; -const GLMessage_Function GLMessage::glProgramUniformMatrix3x2fvEXT; -const GLMessage_Function GLMessage::glProgramUniformMatrix2x4fvEXT; -const GLMessage_Function GLMessage::glProgramUniformMatrix4x2fvEXT; -const GLMessage_Function GLMessage::glProgramUniformMatrix3x4fvEXT; -const GLMessage_Function GLMessage::glProgramUniformMatrix4x3fvEXT; -const GLMessage_Function GLMessage::glRenderbufferStorageMultisampleNV; -const GLMessage_Function GLMessage::glSampleCoverageOES; -const GLMessage_Function GLMessage::glTexStorage3DMultisampleOES; -const GLMessage_Function GLMessage::glUniformMatrix2x3fvNV; -const GLMessage_Function GLMessage::glUniformMatrix3x2fvNV; -const GLMessage_Function GLMessage::glUniformMatrix2x4fvNV; -const GLMessage_Function GLMessage::glUniformMatrix4x2fvNV; -const GLMessage_Function GLMessage::glUniformMatrix3x4fvNV; -const GLMessage_Function GLMessage::glUniformMatrix4x3fvNV; -const GLMessage_Function GLMessage::glActiveShaderProgram; -const GLMessage_Function GLMessage::glBindImageTexture; -const GLMessage_Function GLMessage::glBindProgramPipeline; -const GLMessage_Function GLMessage::glBindVertexBuffer; -const GLMessage_Function GLMessage::glCreateShaderProgramv; -const GLMessage_Function GLMessage::glDeleteProgramPipelines; -const GLMessage_Function GLMessage::glDispatchCompute; -const GLMessage_Function GLMessage::glDispatchComputeIndirect; -const GLMessage_Function GLMessage::glDrawArraysIndirect; -const GLMessage_Function GLMessage::glDrawElementsIndirect; -const GLMessage_Function GLMessage::glFramebufferParameteri; -const GLMessage_Function GLMessage::glGenProgramPipelines; -const GLMessage_Function GLMessage::glGetBooleani_v; -const GLMessage_Function GLMessage::glGetFramebufferParameteriv; -const GLMessage_Function GLMessage::glGetMultisamplefv; -const GLMessage_Function GLMessage::glGetProgramInterfaceiv; -const GLMessage_Function GLMessage::glGetProgramPipelineInfoLog; -const GLMessage_Function GLMessage::glGetProgramPipelineiv; -const GLMessage_Function GLMessage::glGetProgramResourceIndex; -const GLMessage_Function GLMessage::glGetProgramResourceLocation; -const GLMessage_Function GLMessage::glGetProgramResourceName; -const GLMessage_Function GLMessage::glGetProgramResourceiv; -const GLMessage_Function GLMessage::glGetTexLevelParameterfv; -const GLMessage_Function GLMessage::glGetTexLevelParameteriv; -const GLMessage_Function GLMessage::glIsProgramPipeline; -const GLMessage_Function GLMessage::glMemoryBarrier; -const GLMessage_Function GLMessage::glMemoryBarrierByRegion; -const GLMessage_Function GLMessage::glProgramUniform1f; -const GLMessage_Function GLMessage::glProgramUniform1fv; -const GLMessage_Function GLMessage::glProgramUniform1i; -const GLMessage_Function GLMessage::glProgramUniform1iv; -const GLMessage_Function GLMessage::glProgramUniform1ui; -const GLMessage_Function GLMessage::glProgramUniform1uiv; -const GLMessage_Function GLMessage::glProgramUniform2f; -const GLMessage_Function GLMessage::glProgramUniform2fv; -const GLMessage_Function GLMessage::glProgramUniform2i; -const GLMessage_Function GLMessage::glProgramUniform2iv; -const GLMessage_Function GLMessage::glProgramUniform2ui; -const GLMessage_Function GLMessage::glProgramUniform2uiv; -const GLMessage_Function GLMessage::glProgramUniform3f; -const GLMessage_Function GLMessage::glProgramUniform3fv; -const GLMessage_Function GLMessage::glProgramUniform3i; -const GLMessage_Function GLMessage::glProgramUniform3iv; -const GLMessage_Function GLMessage::glProgramUniform3ui; -const GLMessage_Function GLMessage::glProgramUniform3uiv; -const GLMessage_Function GLMessage::glProgramUniform4f; -const GLMessage_Function GLMessage::glProgramUniform4fv; -const GLMessage_Function GLMessage::glProgramUniform4i; -const GLMessage_Function GLMessage::glProgramUniform4iv; -const GLMessage_Function GLMessage::glProgramUniform4ui; -const GLMessage_Function GLMessage::glProgramUniform4uiv; -const GLMessage_Function GLMessage::glProgramUniformMatrix2fv; -const GLMessage_Function GLMessage::glProgramUniformMatrix2x3fv; -const GLMessage_Function GLMessage::glProgramUniformMatrix2x4fv; -const GLMessage_Function GLMessage::glProgramUniformMatrix3fv; -const GLMessage_Function GLMessage::glProgramUniformMatrix3x2fv; -const GLMessage_Function GLMessage::glProgramUniformMatrix3x4fv; -const GLMessage_Function GLMessage::glProgramUniformMatrix4fv; -const GLMessage_Function GLMessage::glProgramUniformMatrix4x2fv; -const GLMessage_Function GLMessage::glProgramUniformMatrix4x3fv; -const GLMessage_Function GLMessage::glSampleMaski; -const GLMessage_Function GLMessage::glTexStorage2DMultisample; -const GLMessage_Function GLMessage::glUseProgramStages; -const GLMessage_Function GLMessage::glValidateProgramPipeline; -const GLMessage_Function GLMessage::glVertexAttribBinding; -const GLMessage_Function GLMessage::glVertexAttribFormat; -const GLMessage_Function GLMessage::glVertexAttribIFormat; -const GLMessage_Function GLMessage::glVertexBindingDivisor; -const GLMessage_Function GLMessage::glBlendEquationSeparateiEXT; -const GLMessage_Function GLMessage::glBlendEquationiEXT; -const GLMessage_Function GLMessage::glBlendFuncSeparateiEXT; -const GLMessage_Function GLMessage::glBlendFunciEXT; -const GLMessage_Function GLMessage::glColorMaskiEXT; -const GLMessage_Function GLMessage::glCopyImageSubDataEXT; -const GLMessage_Function GLMessage::glDisableiEXT; -const GLMessage_Function GLMessage::glEnableiEXT; -const GLMessage_Function GLMessage::glFramebufferTextureEXT; -const GLMessage_Function GLMessage::glGetSamplerParameterIivEXT; -const GLMessage_Function GLMessage::glGetSamplerParameterIuivEXT; -const GLMessage_Function GLMessage::glGetTexParameterIivEXT; -const GLMessage_Function GLMessage::glGetTexParameterIuivEXT; -const GLMessage_Function GLMessage::glIsEnablediEXT; -const GLMessage_Function GLMessage::glPatchParameteriEXT; -const GLMessage_Function GLMessage::glPrimitiveBoundingBoxEXT; -const GLMessage_Function GLMessage::glSamplerParameterIivEXT; -const GLMessage_Function GLMessage::glSamplerParameterIuivEXT; -const GLMessage_Function GLMessage::glTexBufferEXT; -const GLMessage_Function GLMessage::glTexBufferRangeEXT; -const GLMessage_Function GLMessage::glTexParameterIivEXT; -const GLMessage_Function GLMessage::glTexParameterIuivEXT; -const GLMessage_Function GLMessage::glTextureViewEXT; -const GLMessage_Function GLMessage::eglGetDisplay; -const GLMessage_Function GLMessage::eglInitialize; -const GLMessage_Function GLMessage::eglTerminate; -const GLMessage_Function GLMessage::eglGetConfigs; -const GLMessage_Function GLMessage::eglChooseConfig; -const GLMessage_Function GLMessage::eglGetConfigAttrib; -const GLMessage_Function GLMessage::eglCreateWindowSurface; -const GLMessage_Function GLMessage::eglCreatePixmapSurface; -const GLMessage_Function GLMessage::eglCreatePbufferSurface; -const GLMessage_Function GLMessage::eglDestroySurface; -const GLMessage_Function GLMessage::eglQuerySurface; -const GLMessage_Function GLMessage::eglCreateContext; -const GLMessage_Function GLMessage::eglDestroyContext; -const GLMessage_Function GLMessage::eglMakeCurrent; -const GLMessage_Function GLMessage::eglGetCurrentContext; -const GLMessage_Function GLMessage::eglGetCurrentSurface; -const GLMessage_Function GLMessage::eglGetCurrentDisplay; -const GLMessage_Function GLMessage::eglQueryContext; -const GLMessage_Function GLMessage::eglWaitGL; -const GLMessage_Function GLMessage::eglWaitNative; -const GLMessage_Function GLMessage::eglSwapBuffers; -const GLMessage_Function GLMessage::eglCopyBuffers; -const GLMessage_Function GLMessage::eglGetError; -const GLMessage_Function GLMessage::eglQueryString; -const GLMessage_Function GLMessage::eglGetProcAddress; -const GLMessage_Function GLMessage::eglSurfaceAttrib; -const GLMessage_Function GLMessage::eglBindTexImage; -const GLMessage_Function GLMessage::eglReleaseTexImage; -const GLMessage_Function GLMessage::eglSwapInterval; -const GLMessage_Function GLMessage::eglBindAPI; -const GLMessage_Function GLMessage::eglQueryAPI; -const GLMessage_Function GLMessage::eglWaitClient; -const GLMessage_Function GLMessage::eglReleaseThread; -const GLMessage_Function GLMessage::eglCreatePbufferFromClientBuffer; -const GLMessage_Function GLMessage::eglLockSurfaceKHR; -const GLMessage_Function GLMessage::eglUnlockSurfaceKHR; -const GLMessage_Function GLMessage::eglCreateImageKHR; -const GLMessage_Function GLMessage::eglDestroyImageKHR; -const GLMessage_Function GLMessage::eglCreateSyncKHR; -const GLMessage_Function GLMessage::eglDestroySyncKHR; -const GLMessage_Function GLMessage::eglClientWaitSyncKHR; -const GLMessage_Function GLMessage::eglGetSyncAttribKHR; -const GLMessage_Function GLMessage::eglSetSwapRectangleANDROID; -const GLMessage_Function GLMessage::eglGetRenderBufferANDROID; -const GLMessage_Function GLMessage::eglGetSystemTimeFrequencyNV; -const GLMessage_Function GLMessage::eglGetSystemTimeNV; -const GLMessage_Function GLMessage::invalid; -const GLMessage_Function GLMessage::glVertexAttribPointerData; -const GLMessage_Function GLMessage::Function_MIN; -const GLMessage_Function GLMessage::Function_MAX; -const int GLMessage::Function_ARRAYSIZE; -#endif // _MSC_VER -bool GLMessage_DataType_Type_IsValid(int value) { - switch(value) { - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - return true; - default: - return false; - } -} - -#ifndef _MSC_VER -const GLMessage_DataType_Type GLMessage_DataType::VOID; -const GLMessage_DataType_Type GLMessage_DataType::CHAR; -const GLMessage_DataType_Type GLMessage_DataType::BYTE; -const GLMessage_DataType_Type GLMessage_DataType::INT; -const GLMessage_DataType_Type GLMessage_DataType::FLOAT; -const GLMessage_DataType_Type GLMessage_DataType::BOOL; -const GLMessage_DataType_Type GLMessage_DataType::ENUM; -const GLMessage_DataType_Type GLMessage_DataType::INT64; -const GLMessage_DataType_Type GLMessage_DataType::Type_MIN; -const GLMessage_DataType_Type GLMessage_DataType::Type_MAX; -const int GLMessage_DataType::Type_ARRAYSIZE; -#endif // _MSC_VER -#ifndef _MSC_VER -const int GLMessage_DataType::kTypeFieldNumber; -const int GLMessage_DataType::kIsArrayFieldNumber; -const int GLMessage_DataType::kIntValueFieldNumber; -const int GLMessage_DataType::kFloatValueFieldNumber; -const int GLMessage_DataType::kCharValueFieldNumber; -const int GLMessage_DataType::kRawBytesFieldNumber; -const int GLMessage_DataType::kBoolValueFieldNumber; -const int GLMessage_DataType::kInt64ValueFieldNumber; -#endif // !_MSC_VER - -GLMessage_DataType::GLMessage_DataType() - : ::google::protobuf::MessageLite() { - SharedCtor(); -} - -void GLMessage_DataType::InitAsDefaultInstance() { -} - -GLMessage_DataType::GLMessage_DataType(const GLMessage_DataType& from) - : ::google::protobuf::MessageLite() { - SharedCtor(); - MergeFrom(from); -} - -void GLMessage_DataType::SharedCtor() { - _cached_size_ = 0; - type_ = 1; - isarray_ = false; - ::memset(_has_bits_, 0, sizeof(_has_bits_)); -} - -GLMessage_DataType::~GLMessage_DataType() { - SharedDtor(); -} - -void GLMessage_DataType::SharedDtor() { - if (this != default_instance_) { - } -} - -void GLMessage_DataType::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const GLMessage_DataType& GLMessage_DataType::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_gltrace_2eproto(); return *default_instance_; -} - -GLMessage_DataType* GLMessage_DataType::default_instance_ = NULL; - -GLMessage_DataType* GLMessage_DataType::New() const { - return new GLMessage_DataType; -} - -void GLMessage_DataType::Clear() { - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { - type_ = 1; - isarray_ = false; - } - intvalue_.Clear(); - floatvalue_.Clear(); - charvalue_.Clear(); - rawbytes_.Clear(); - boolvalue_.Clear(); - int64value_.Clear(); - ::memset(_has_bits_, 0, sizeof(_has_bits_)); -} - -bool GLMessage_DataType::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) return false - ::google::protobuf::uint32 tag; - while ((tag = input->ReadTag()) != 0) { - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // required .android.gltrace.GLMessage.DataType.Type type = 1 [default = VOID]; - case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { - int value; - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>( - input, &value))); - if (::android::gltrace::GLMessage_DataType_Type_IsValid(value)) { - set_type(static_cast< ::android::gltrace::GLMessage_DataType_Type >(value)); - } - } else { - goto handle_uninterpreted; - } - if (input->ExpectTag(16)) goto parse_isArray; - break; - } - - // required bool isArray = 2 [default = false]; - case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { - parse_isArray: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( - input, &isarray_))); - _set_bit(1); - } else { - goto handle_uninterpreted; - } - if (input->ExpectTag(24)) goto parse_intValue; - break; - } - - // repeated int32 intValue = 3; - case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { - parse_intValue: - DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive< - ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( - 1, 24, input, this->mutable_intvalue()))); - } else if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) - == ::google::protobuf::internal::WireFormatLite:: - WIRETYPE_LENGTH_DELIMITED) { - DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline< - ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( - input, this->mutable_intvalue()))); - } else { - goto handle_uninterpreted; - } - if (input->ExpectTag(24)) goto parse_intValue; - if (input->ExpectTag(37)) goto parse_floatValue; - break; - } - - // repeated float floatValue = 4; - case 4: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_FIXED32) { - parse_floatValue: - DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive< - float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>( - 1, 37, input, this->mutable_floatvalue()))); - } else if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) - == ::google::protobuf::internal::WireFormatLite:: - WIRETYPE_LENGTH_DELIMITED) { - DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline< - float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>( - input, this->mutable_floatvalue()))); - } else { - goto handle_uninterpreted; - } - if (input->ExpectTag(37)) goto parse_floatValue; - if (input->ExpectTag(42)) goto parse_charValue; - break; - } - - // repeated bytes charValue = 5; - case 5: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { - parse_charValue: - DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( - input, this->add_charvalue())); - } else { - goto handle_uninterpreted; - } - if (input->ExpectTag(42)) goto parse_charValue; - if (input->ExpectTag(50)) goto parse_rawBytes; - break; - } - - // repeated bytes rawBytes = 6; - case 6: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { - parse_rawBytes: - DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( - input, this->add_rawbytes())); - } else { - goto handle_uninterpreted; - } - if (input->ExpectTag(50)) goto parse_rawBytes; - if (input->ExpectTag(56)) goto parse_boolValue; - break; - } - - // repeated bool boolValue = 7; - case 7: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { - parse_boolValue: - DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive< - bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( - 1, 56, input, this->mutable_boolvalue()))); - } else if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) - == ::google::protobuf::internal::WireFormatLite:: - WIRETYPE_LENGTH_DELIMITED) { - DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline< - bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( - input, this->mutable_boolvalue()))); - } else { - goto handle_uninterpreted; - } - if (input->ExpectTag(56)) goto parse_boolValue; - if (input->ExpectTag(64)) goto parse_int64Value; - break; - } - - // repeated int64 int64Value = 8; - case 8: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { - parse_int64Value: - DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive< - ::google::protobuf::int64, ::google::protobuf::internal::WireFormatLite::TYPE_INT64>( - 1, 64, input, this->mutable_int64value()))); - } else if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) - == ::google::protobuf::internal::WireFormatLite:: - WIRETYPE_LENGTH_DELIMITED) { - DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline< - ::google::protobuf::int64, ::google::protobuf::internal::WireFormatLite::TYPE_INT64>( - input, this->mutable_int64value()))); - } else { - goto handle_uninterpreted; - } - if (input->ExpectTag(64)) goto parse_int64Value; - if (input->ExpectAtEnd()) return true; - break; - } - - default: { - handle_uninterpreted: - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - return true; - } - DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); - break; - } - } - } - return true; -#undef DO_ -} - -void GLMessage_DataType::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // required .android.gltrace.GLMessage.DataType.Type type = 1 [default = VOID]; - if (_has_bit(0)) { - ::google::protobuf::internal::WireFormatLite::WriteEnum( - 1, this->type(), output); - } - - // required bool isArray = 2 [default = false]; - if (_has_bit(1)) { - ::google::protobuf::internal::WireFormatLite::WriteBool(2, this->isarray(), output); - } - - // repeated int32 intValue = 3; - for (int i = 0; i < this->intvalue_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteInt32( - 3, this->intvalue(i), output); - } - - // repeated float floatValue = 4; - for (int i = 0; i < this->floatvalue_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteFloat( - 4, this->floatvalue(i), output); - } - - // repeated bytes charValue = 5; - for (int i = 0; i < this->charvalue_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteBytes( - 5, this->charvalue(i), output); - } - - // repeated bytes rawBytes = 6; - for (int i = 0; i < this->rawbytes_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteBytes( - 6, this->rawbytes(i), output); - } - - // repeated bool boolValue = 7; - for (int i = 0; i < this->boolvalue_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteBool( - 7, this->boolvalue(i), output); - } - - // repeated int64 int64Value = 8; - for (int i = 0; i < this->int64value_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteInt64( - 8, this->int64value(i), output); - } - -} - -int GLMessage_DataType::ByteSize() const { - int total_size = 0; - - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { - // required .android.gltrace.GLMessage.DataType.Type type = 1 [default = VOID]; - if (has_type()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::EnumSize(this->type()); - } - - // required bool isArray = 2 [default = false]; - if (has_isarray()) { - total_size += 1 + 1; - } - - } - // repeated int32 intValue = 3; - { - int data_size = 0; - for (int i = 0; i < this->intvalue_size(); i++) { - data_size += ::google::protobuf::internal::WireFormatLite:: - Int32Size(this->intvalue(i)); - } - total_size += 1 * this->intvalue_size() + data_size; - } - - // repeated float floatValue = 4; - { - int data_size = 0; - data_size = 4 * this->floatvalue_size(); - total_size += 1 * this->floatvalue_size() + data_size; - } - - // repeated bytes charValue = 5; - total_size += 1 * this->charvalue_size(); - for (int i = 0; i < this->charvalue_size(); i++) { - total_size += ::google::protobuf::internal::WireFormatLite::BytesSize( - this->charvalue(i)); - } - - // repeated bytes rawBytes = 6; - total_size += 1 * this->rawbytes_size(); - for (int i = 0; i < this->rawbytes_size(); i++) { - total_size += ::google::protobuf::internal::WireFormatLite::BytesSize( - this->rawbytes(i)); - } - - // repeated bool boolValue = 7; - { - int data_size = 0; - data_size = 1 * this->boolvalue_size(); - total_size += 1 * this->boolvalue_size() + data_size; - } - - // repeated int64 int64Value = 8; - { - int data_size = 0; - for (int i = 0; i < this->int64value_size(); i++) { - data_size += ::google::protobuf::internal::WireFormatLite:: - Int64Size(this->int64value(i)); - } - total_size += 1 * this->int64value_size() + data_size; - } - - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - return total_size; -} - -void GLMessage_DataType::CheckTypeAndMergeFrom( - const ::google::protobuf::MessageLite& from) { - MergeFrom(*::google::protobuf::down_cast<const GLMessage_DataType*>(&from)); -} - -void GLMessage_DataType::MergeFrom(const GLMessage_DataType& from) { - GOOGLE_CHECK_NE(&from, this); - intvalue_.MergeFrom(from.intvalue_); - floatvalue_.MergeFrom(from.floatvalue_); - charvalue_.MergeFrom(from.charvalue_); - rawbytes_.MergeFrom(from.rawbytes_); - boolvalue_.MergeFrom(from.boolvalue_); - int64value_.MergeFrom(from.int64value_); - if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { - if (from._has_bit(0)) { - set_type(from.type()); - } - if (from._has_bit(1)) { - set_isarray(from.isarray()); - } - } -} - -void GLMessage_DataType::CopyFrom(const GLMessage_DataType& from) { - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool GLMessage_DataType::IsInitialized() const { - if ((_has_bits_[0] & 0x00000003) != 0x00000003) return false; - - return true; -} - -void GLMessage_DataType::Swap(GLMessage_DataType* other) { - if (other != this) { - std::swap(type_, other->type_); - std::swap(isarray_, other->isarray_); - intvalue_.Swap(&other->intvalue_); - floatvalue_.Swap(&other->floatvalue_); - charvalue_.Swap(&other->charvalue_); - rawbytes_.Swap(&other->rawbytes_); - boolvalue_.Swap(&other->boolvalue_); - int64value_.Swap(&other->int64value_); - std::swap(_has_bits_[0], other->_has_bits_[0]); - std::swap(_cached_size_, other->_cached_size_); - } -} - -::std::string GLMessage_DataType::GetTypeName() const { - return "android.gltrace.GLMessage.DataType"; -} - - -// ------------------------------------------------------------------- - -#ifndef _MSC_VER -const int GLMessage_FrameBuffer::kWidthFieldNumber; -const int GLMessage_FrameBuffer::kHeightFieldNumber; -const int GLMessage_FrameBuffer::kContentsFieldNumber; -#endif // !_MSC_VER - -GLMessage_FrameBuffer::GLMessage_FrameBuffer() - : ::google::protobuf::MessageLite() { - SharedCtor(); -} - -void GLMessage_FrameBuffer::InitAsDefaultInstance() { -} - -GLMessage_FrameBuffer::GLMessage_FrameBuffer(const GLMessage_FrameBuffer& from) - : ::google::protobuf::MessageLite() { - SharedCtor(); - MergeFrom(from); -} - -void GLMessage_FrameBuffer::SharedCtor() { - _cached_size_ = 0; - width_ = 0; - height_ = 0; - ::memset(_has_bits_, 0, sizeof(_has_bits_)); -} - -GLMessage_FrameBuffer::~GLMessage_FrameBuffer() { - SharedDtor(); -} - -void GLMessage_FrameBuffer::SharedDtor() { - if (this != default_instance_) { - } -} - -void GLMessage_FrameBuffer::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const GLMessage_FrameBuffer& GLMessage_FrameBuffer::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_gltrace_2eproto(); return *default_instance_; -} - -GLMessage_FrameBuffer* GLMessage_FrameBuffer::default_instance_ = NULL; - -GLMessage_FrameBuffer* GLMessage_FrameBuffer::New() const { - return new GLMessage_FrameBuffer; -} - -void GLMessage_FrameBuffer::Clear() { - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { - width_ = 0; - height_ = 0; - } - contents_.Clear(); - ::memset(_has_bits_, 0, sizeof(_has_bits_)); -} - -bool GLMessage_FrameBuffer::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) return false - ::google::protobuf::uint32 tag; - while ((tag = input->ReadTag()) != 0) { - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // required int32 width = 1; - case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( - input, &width_))); - _set_bit(0); - } else { - goto handle_uninterpreted; - } - if (input->ExpectTag(16)) goto parse_height; - break; - } - - // required int32 height = 2; - case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { - parse_height: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( - input, &height_))); - _set_bit(1); - } else { - goto handle_uninterpreted; - } - if (input->ExpectTag(26)) goto parse_contents; - break; - } - - // repeated bytes contents = 3; - case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { - parse_contents: - DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( - input, this->add_contents())); - } else { - goto handle_uninterpreted; - } - if (input->ExpectTag(26)) goto parse_contents; - if (input->ExpectAtEnd()) return true; - break; - } - - default: { - handle_uninterpreted: - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - return true; - } - DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); - break; - } - } - } - return true; -#undef DO_ -} - -void GLMessage_FrameBuffer::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // required int32 width = 1; - if (_has_bit(0)) { - ::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->width(), output); - } - - // required int32 height = 2; - if (_has_bit(1)) { - ::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->height(), output); - } - - // repeated bytes contents = 3; - for (int i = 0; i < this->contents_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteBytes( - 3, this->contents(i), output); - } - -} - -int GLMessage_FrameBuffer::ByteSize() const { - int total_size = 0; - - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { - // required int32 width = 1; - if (has_width()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::Int32Size( - this->width()); - } - - // required int32 height = 2; - if (has_height()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::Int32Size( - this->height()); - } - - } - // repeated bytes contents = 3; - total_size += 1 * this->contents_size(); - for (int i = 0; i < this->contents_size(); i++) { - total_size += ::google::protobuf::internal::WireFormatLite::BytesSize( - this->contents(i)); - } - - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - return total_size; -} - -void GLMessage_FrameBuffer::CheckTypeAndMergeFrom( - const ::google::protobuf::MessageLite& from) { - MergeFrom(*::google::protobuf::down_cast<const GLMessage_FrameBuffer*>(&from)); -} - -void GLMessage_FrameBuffer::MergeFrom(const GLMessage_FrameBuffer& from) { - GOOGLE_CHECK_NE(&from, this); - contents_.MergeFrom(from.contents_); - if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { - if (from._has_bit(0)) { - set_width(from.width()); - } - if (from._has_bit(1)) { - set_height(from.height()); - } - } -} - -void GLMessage_FrameBuffer::CopyFrom(const GLMessage_FrameBuffer& from) { - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool GLMessage_FrameBuffer::IsInitialized() const { - if ((_has_bits_[0] & 0x00000003) != 0x00000003) return false; - - return true; -} - -void GLMessage_FrameBuffer::Swap(GLMessage_FrameBuffer* other) { - if (other != this) { - std::swap(width_, other->width_); - std::swap(height_, other->height_); - contents_.Swap(&other->contents_); - std::swap(_has_bits_[0], other->_has_bits_[0]); - std::swap(_cached_size_, other->_cached_size_); - } -} - -::std::string GLMessage_FrameBuffer::GetTypeName() const { - return "android.gltrace.GLMessage.FrameBuffer"; -} - - -// ------------------------------------------------------------------- - -#ifndef _MSC_VER -const int GLMessage::kContextIdFieldNumber; -const int GLMessage::kStartTimeFieldNumber; -const int GLMessage::kDurationFieldNumber; -const int GLMessage::kFunctionFieldNumber; -const int GLMessage::kArgsFieldNumber; -const int GLMessage::kReturnValueFieldNumber; -const int GLMessage::kFbFieldNumber; -const int GLMessage::kThreadtimeFieldNumber; -#endif // !_MSC_VER - -GLMessage::GLMessage() - : ::google::protobuf::MessageLite() { - SharedCtor(); -} - -void GLMessage::InitAsDefaultInstance() { - returnvalue_ = const_cast< ::android::gltrace::GLMessage_DataType*>(&::android::gltrace::GLMessage_DataType::default_instance()); - fb_ = const_cast< ::android::gltrace::GLMessage_FrameBuffer*>(&::android::gltrace::GLMessage_FrameBuffer::default_instance()); -} - -GLMessage::GLMessage(const GLMessage& from) - : ::google::protobuf::MessageLite() { - SharedCtor(); - MergeFrom(from); -} - -void GLMessage::SharedCtor() { - _cached_size_ = 0; - context_id_ = 0; - start_time_ = GOOGLE_LONGLONG(0); - duration_ = 0; - function_ = 3000; - returnvalue_ = NULL; - fb_ = NULL; - threadtime_ = 0; - ::memset(_has_bits_, 0, sizeof(_has_bits_)); -} - -GLMessage::~GLMessage() { - SharedDtor(); -} - -void GLMessage::SharedDtor() { - if (this != default_instance_) { - delete returnvalue_; - delete fb_; - } -} - -void GLMessage::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const GLMessage& GLMessage::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_gltrace_2eproto(); return *default_instance_; -} - -GLMessage* GLMessage::default_instance_ = NULL; - -GLMessage* GLMessage::New() const { - return new GLMessage; -} - -void GLMessage::Clear() { - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { - context_id_ = 0; - start_time_ = GOOGLE_LONGLONG(0); - duration_ = 0; - function_ = 3000; - if (_has_bit(5)) { - if (returnvalue_ != NULL) returnvalue_->::android::gltrace::GLMessage_DataType::Clear(); - } - if (_has_bit(6)) { - if (fb_ != NULL) fb_->::android::gltrace::GLMessage_FrameBuffer::Clear(); - } - threadtime_ = 0; - } - args_.Clear(); - ::memset(_has_bits_, 0, sizeof(_has_bits_)); -} - -bool GLMessage::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) return false - ::google::protobuf::uint32 tag; - while ((tag = input->ReadTag()) != 0) { - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // required int32 context_id = 1; - case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( - input, &context_id_))); - _set_bit(0); - } else { - goto handle_uninterpreted; - } - if (input->ExpectTag(16)) goto parse_start_time; - break; - } - - // required int64 start_time = 2; - case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { - parse_start_time: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::int64, ::google::protobuf::internal::WireFormatLite::TYPE_INT64>( - input, &start_time_))); - _set_bit(1); - } else { - goto handle_uninterpreted; - } - if (input->ExpectTag(24)) goto parse_duration; - break; - } - - // required int32 duration = 3; - case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { - parse_duration: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( - input, &duration_))); - _set_bit(2); - } else { - goto handle_uninterpreted; - } - if (input->ExpectTag(32)) goto parse_function; - break; - } - - // required .android.gltrace.GLMessage.Function function = 4 [default = invalid]; - case 4: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { - parse_function: - int value; - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>( - input, &value))); - if (::android::gltrace::GLMessage_Function_IsValid(value)) { - set_function(static_cast< ::android::gltrace::GLMessage_Function >(value)); - } - } else { - goto handle_uninterpreted; - } - if (input->ExpectTag(42)) goto parse_args; - break; - } - - // repeated .android.gltrace.GLMessage.DataType args = 5; - case 5: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { - parse_args: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_args())); - } else { - goto handle_uninterpreted; - } - if (input->ExpectTag(42)) goto parse_args; - if (input->ExpectTag(50)) goto parse_returnValue; - break; - } - - // optional .android.gltrace.GLMessage.DataType returnValue = 6; - case 6: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { - parse_returnValue: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_returnvalue())); - } else { - goto handle_uninterpreted; - } - if (input->ExpectTag(58)) goto parse_fb; - break; - } - - // optional .android.gltrace.GLMessage.FrameBuffer fb = 7; - case 7: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { - parse_fb: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_fb())); - } else { - goto handle_uninterpreted; - } - if (input->ExpectTag(64)) goto parse_threadtime; - break; - } - - // optional int32 threadtime = 8; - case 8: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { - parse_threadtime: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( - input, &threadtime_))); - _set_bit(7); - } else { - goto handle_uninterpreted; - } - if (input->ExpectAtEnd()) return true; - break; - } - - default: { - handle_uninterpreted: - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - return true; - } - DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); - break; - } - } - } - return true; -#undef DO_ -} - -void GLMessage::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // required int32 context_id = 1; - if (_has_bit(0)) { - ::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->context_id(), output); - } - - // required int64 start_time = 2; - if (_has_bit(1)) { - ::google::protobuf::internal::WireFormatLite::WriteInt64(2, this->start_time(), output); - } - - // required int32 duration = 3; - if (_has_bit(2)) { - ::google::protobuf::internal::WireFormatLite::WriteInt32(3, this->duration(), output); - } - - // required .android.gltrace.GLMessage.Function function = 4 [default = invalid]; - if (_has_bit(3)) { - ::google::protobuf::internal::WireFormatLite::WriteEnum( - 4, this->function(), output); - } - - // repeated .android.gltrace.GLMessage.DataType args = 5; - for (int i = 0; i < this->args_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessage( - 5, this->args(i), output); - } - - // optional .android.gltrace.GLMessage.DataType returnValue = 6; - if (_has_bit(5)) { - ::google::protobuf::internal::WireFormatLite::WriteMessage( - 6, this->returnvalue(), output); - } - - // optional .android.gltrace.GLMessage.FrameBuffer fb = 7; - if (_has_bit(6)) { - ::google::protobuf::internal::WireFormatLite::WriteMessage( - 7, this->fb(), output); - } - - // optional int32 threadtime = 8; - if (_has_bit(7)) { - ::google::protobuf::internal::WireFormatLite::WriteInt32(8, this->threadtime(), output); - } - -} - -int GLMessage::ByteSize() const { - int total_size = 0; - - if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { - // required int32 context_id = 1; - if (has_context_id()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::Int32Size( - this->context_id()); - } - - // required int64 start_time = 2; - if (has_start_time()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::Int64Size( - this->start_time()); - } - - // required int32 duration = 3; - if (has_duration()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::Int32Size( - this->duration()); - } - - // required .android.gltrace.GLMessage.Function function = 4 [default = invalid]; - if (has_function()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::EnumSize(this->function()); - } - - // optional .android.gltrace.GLMessage.DataType returnValue = 6; - if (has_returnvalue()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( - this->returnvalue()); - } - - // optional .android.gltrace.GLMessage.FrameBuffer fb = 7; - if (has_fb()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( - this->fb()); - } - - // optional int32 threadtime = 8; - if (has_threadtime()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::Int32Size( - this->threadtime()); - } - - } - // repeated .android.gltrace.GLMessage.DataType args = 5; - total_size += 1 * this->args_size(); - for (int i = 0; i < this->args_size(); i++) { - total_size += - ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( - this->args(i)); - } - - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - return total_size; -} - -void GLMessage::CheckTypeAndMergeFrom( - const ::google::protobuf::MessageLite& from) { - MergeFrom(*::google::protobuf::down_cast<const GLMessage*>(&from)); -} - -void GLMessage::MergeFrom(const GLMessage& from) { - GOOGLE_CHECK_NE(&from, this); - args_.MergeFrom(from.args_); - if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { - if (from._has_bit(0)) { - set_context_id(from.context_id()); - } - if (from._has_bit(1)) { - set_start_time(from.start_time()); - } - if (from._has_bit(2)) { - set_duration(from.duration()); - } - if (from._has_bit(3)) { - set_function(from.function()); - } - if (from._has_bit(5)) { - mutable_returnvalue()->::android::gltrace::GLMessage_DataType::MergeFrom(from.returnvalue()); - } - if (from._has_bit(6)) { - mutable_fb()->::android::gltrace::GLMessage_FrameBuffer::MergeFrom(from.fb()); - } - if (from._has_bit(7)) { - set_threadtime(from.threadtime()); - } - } -} - -void GLMessage::CopyFrom(const GLMessage& from) { - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool GLMessage::IsInitialized() const { - if ((_has_bits_[0] & 0x0000000f) != 0x0000000f) return false; - - for (int i = 0; i < args_size(); i++) { - if (!this->args(i).IsInitialized()) return false; - } - if (has_returnvalue()) { - if (!this->returnvalue().IsInitialized()) return false; - } - if (has_fb()) { - if (!this->fb().IsInitialized()) return false; - } - return true; -} - -void GLMessage::Swap(GLMessage* other) { - if (other != this) { - std::swap(context_id_, other->context_id_); - std::swap(start_time_, other->start_time_); - std::swap(duration_, other->duration_); - std::swap(function_, other->function_); - args_.Swap(&other->args_); - std::swap(returnvalue_, other->returnvalue_); - std::swap(fb_, other->fb_); - std::swap(threadtime_, other->threadtime_); - std::swap(_has_bits_[0], other->_has_bits_[0]); - std::swap(_cached_size_, other->_cached_size_); - } -} - -::std::string GLMessage::GetTypeName() const { - return "android.gltrace.GLMessage"; -} - - -// @@protoc_insertion_point(namespace_scope) - -} // namespace gltrace -} // namespace android - -// @@protoc_insertion_point(global_scope) diff --git a/opengl/libs/GLES_trace/src/gltrace.pb.h b/opengl/libs/GLES_trace/src/gltrace.pb.h deleted file mode 100644 index 9bc7c58ce4..0000000000 --- a/opengl/libs/GLES_trace/src/gltrace.pb.h +++ /dev/null @@ -1,2525 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: gltrace.proto - -#ifndef PROTOBUF_gltrace_2eproto__INCLUDED -#define PROTOBUF_gltrace_2eproto__INCLUDED - -#include <string> - -#include <google/protobuf/stubs/common.h> - -#if GOOGLE_PROTOBUF_VERSION < 2003000 -#error This file was generated by a newer version of protoc which is -#error incompatible with your Protocol Buffer headers. Please update -#error your headers. -#endif -#if 2003000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION -#error This file was generated by an older version of protoc which is -#error incompatible with your Protocol Buffer headers. Please -#error regenerate this file with a newer version of protoc. -#endif - -#include <google/protobuf/generated_message_util.h> -#include <google/protobuf/repeated_field.h> -#include <google/protobuf/extension_set.h> -// @@protoc_insertion_point(includes) - -namespace android { -namespace gltrace { - -// Internal implementation detail -- do not call these. -void protobuf_AddDesc_gltrace_2eproto(); -void protobuf_AssignDesc_gltrace_2eproto(); -void protobuf_ShutdownFile_gltrace_2eproto(); - -class GLMessage; -class GLMessage_DataType; -class GLMessage_FrameBuffer; - -enum GLMessage_DataType_Type { - GLMessage_DataType_Type_VOID = 1, - GLMessage_DataType_Type_CHAR = 2, - GLMessage_DataType_Type_BYTE = 3, - GLMessage_DataType_Type_INT = 4, - GLMessage_DataType_Type_FLOAT = 5, - GLMessage_DataType_Type_BOOL = 6, - GLMessage_DataType_Type_ENUM = 7, - GLMessage_DataType_Type_INT64 = 8 -}; -bool GLMessage_DataType_Type_IsValid(int value); -const GLMessage_DataType_Type GLMessage_DataType_Type_Type_MIN = GLMessage_DataType_Type_VOID; -const GLMessage_DataType_Type GLMessage_DataType_Type_Type_MAX = GLMessage_DataType_Type_INT64; -const int GLMessage_DataType_Type_Type_ARRAYSIZE = GLMessage_DataType_Type_Type_MAX + 1; - -enum GLMessage_Function { - GLMessage_Function_glActiveTexture = 0, - GLMessage_Function_glAlphaFunc = 1, - GLMessage_Function_glAlphaFuncx = 2, - GLMessage_Function_glAlphaFuncxOES = 3, - GLMessage_Function_glAttachShader = 4, - GLMessage_Function_glBeginPerfMonitorAMD = 5, - GLMessage_Function_glBindAttribLocation = 6, - GLMessage_Function_glBindBuffer = 7, - GLMessage_Function_glBindFramebuffer = 8, - GLMessage_Function_glBindFramebufferOES = 9, - GLMessage_Function_glBindRenderbuffer = 10, - GLMessage_Function_glBindRenderbufferOES = 11, - GLMessage_Function_glBindTexture = 12, - GLMessage_Function_glBindVertexArrayOES = 13, - GLMessage_Function_glBlendColor = 14, - GLMessage_Function_glBlendEquation = 15, - GLMessage_Function_glBlendEquationOES = 16, - GLMessage_Function_glBlendEquationSeparate = 17, - GLMessage_Function_glBlendEquationSeparateOES = 18, - GLMessage_Function_glBlendFunc = 19, - GLMessage_Function_glBlendFuncSeparate = 20, - GLMessage_Function_glBlendFuncSeparateOES = 21, - GLMessage_Function_glBufferData = 22, - GLMessage_Function_glBufferSubData = 23, - GLMessage_Function_glCheckFramebufferStatus = 24, - GLMessage_Function_glCheckFramebufferStatusOES = 25, - GLMessage_Function_glClearColor = 26, - GLMessage_Function_glClearColorx = 27, - GLMessage_Function_glClearColorxOES = 28, - GLMessage_Function_glClearDepthf = 29, - GLMessage_Function_glClearDepthfOES = 30, - GLMessage_Function_glClearDepthx = 31, - GLMessage_Function_glClearDepthxOES = 32, - GLMessage_Function_glClear = 33, - GLMessage_Function_glClearStencil = 34, - GLMessage_Function_glClientActiveTexture = 35, - GLMessage_Function_glClipPlanef = 36, - GLMessage_Function_glClipPlanefIMG = 37, - GLMessage_Function_glClipPlanefOES = 38, - GLMessage_Function_glClipPlanex = 39, - GLMessage_Function_glClipPlanexIMG = 40, - GLMessage_Function_glClipPlanexOES = 41, - GLMessage_Function_glColor4f = 42, - GLMessage_Function_glColor4ub = 43, - GLMessage_Function_glColor4x = 44, - GLMessage_Function_glColor4xOES = 45, - GLMessage_Function_glColorMask = 46, - GLMessage_Function_glColorPointer = 47, - GLMessage_Function_glCompileShader = 48, - GLMessage_Function_glCompressedTexImage2D = 49, - GLMessage_Function_glCompressedTexImage3DOES = 50, - GLMessage_Function_glCompressedTexSubImage2D = 51, - GLMessage_Function_glCompressedTexSubImage3DOES = 52, - GLMessage_Function_glCopyTexImage2D = 53, - GLMessage_Function_glCopyTexSubImage2D = 54, - GLMessage_Function_glCopyTexSubImage3DOES = 55, - GLMessage_Function_glCoverageMaskNV = 56, - GLMessage_Function_glCoverageOperationNV = 57, - GLMessage_Function_glCreateProgram = 58, - GLMessage_Function_glCreateShader = 59, - GLMessage_Function_glCullFace = 60, - GLMessage_Function_glCurrentPaletteMatrixOES = 61, - GLMessage_Function_glDeleteBuffers = 62, - GLMessage_Function_glDeleteFencesNV = 63, - GLMessage_Function_glDeleteFramebuffers = 64, - GLMessage_Function_glDeleteFramebuffersOES = 65, - GLMessage_Function_glDeletePerfMonitorsAMD = 66, - GLMessage_Function_glDeleteProgram = 67, - GLMessage_Function_glDeleteRenderbuffers = 68, - GLMessage_Function_glDeleteRenderbuffersOES = 69, - GLMessage_Function_glDeleteShader = 70, - GLMessage_Function_glDeleteTextures = 71, - GLMessage_Function_glDeleteVertexArraysOES = 72, - GLMessage_Function_glDepthFunc = 73, - GLMessage_Function_glDepthMask = 74, - GLMessage_Function_glDepthRangef = 75, - GLMessage_Function_glDepthRangefOES = 76, - GLMessage_Function_glDepthRangex = 77, - GLMessage_Function_glDepthRangexOES = 78, - GLMessage_Function_glDetachShader = 79, - GLMessage_Function_glDisableClientState = 80, - GLMessage_Function_glDisableDriverControlQCOM = 81, - GLMessage_Function_glDisable = 82, - GLMessage_Function_glDisableVertexAttribArray = 83, - GLMessage_Function_glDiscardFramebufferEXT = 84, - GLMessage_Function_glDrawArrays = 85, - GLMessage_Function_glDrawElements = 86, - GLMessage_Function_glDrawTexfOES = 87, - GLMessage_Function_glDrawTexfvOES = 88, - GLMessage_Function_glDrawTexiOES = 89, - GLMessage_Function_glDrawTexivOES = 90, - GLMessage_Function_glDrawTexsOES = 91, - GLMessage_Function_glDrawTexsvOES = 92, - GLMessage_Function_glDrawTexxOES = 93, - GLMessage_Function_glDrawTexxvOES = 94, - GLMessage_Function_glEGLImageTargetRenderbufferStorageOES = 95, - GLMessage_Function_glEGLImageTargetTexture2DOES = 96, - GLMessage_Function_glEnableClientState = 97, - GLMessage_Function_glEnableDriverControlQCOM = 98, - GLMessage_Function_glEnable = 99, - GLMessage_Function_glEnableVertexAttribArray = 100, - GLMessage_Function_glEndPerfMonitorAMD = 101, - GLMessage_Function_glEndTilingQCOM = 102, - GLMessage_Function_glExtGetBufferPointervQCOM = 103, - GLMessage_Function_glExtGetBuffersQCOM = 104, - GLMessage_Function_glExtGetFramebuffersQCOM = 105, - GLMessage_Function_glExtGetProgramBinarySourceQCOM = 106, - GLMessage_Function_glExtGetProgramsQCOM = 107, - GLMessage_Function_glExtGetRenderbuffersQCOM = 108, - GLMessage_Function_glExtGetShadersQCOM = 109, - GLMessage_Function_glExtGetTexLevelParameterivQCOM = 110, - GLMessage_Function_glExtGetTexSubImageQCOM = 111, - GLMessage_Function_glExtGetTexturesQCOM = 112, - GLMessage_Function_glExtIsProgramBinaryQCOM = 113, - GLMessage_Function_glExtTexObjectStateOverrideiQCOM = 114, - GLMessage_Function_glFinishFenceNV = 115, - GLMessage_Function_glFinish = 116, - GLMessage_Function_glFlush = 117, - GLMessage_Function_glFogf = 118, - GLMessage_Function_glFogfv = 119, - GLMessage_Function_glFogx = 120, - GLMessage_Function_glFogxOES = 121, - GLMessage_Function_glFogxv = 122, - GLMessage_Function_glFogxvOES = 123, - GLMessage_Function_glFramebufferRenderbuffer = 124, - GLMessage_Function_glFramebufferRenderbufferOES = 125, - GLMessage_Function_glFramebufferTexture2D = 126, - GLMessage_Function_glFramebufferTexture2DMultisampleIMG = 127, - GLMessage_Function_glFramebufferTexture2DOES = 128, - GLMessage_Function_glFramebufferTexture3DOES = 129, - GLMessage_Function_glFrontFace = 130, - GLMessage_Function_glFrustumf = 131, - GLMessage_Function_glFrustumfOES = 132, - GLMessage_Function_glFrustumx = 133, - GLMessage_Function_glFrustumxOES = 134, - GLMessage_Function_glGenBuffers = 135, - GLMessage_Function_glGenerateMipmap = 136, - GLMessage_Function_glGenerateMipmapOES = 137, - GLMessage_Function_glGenFencesNV = 138, - GLMessage_Function_glGenFramebuffers = 139, - GLMessage_Function_glGenFramebuffersOES = 140, - GLMessage_Function_glGenPerfMonitorsAMD = 141, - GLMessage_Function_glGenRenderbuffers = 142, - GLMessage_Function_glGenRenderbuffersOES = 143, - GLMessage_Function_glGenTextures = 144, - GLMessage_Function_glGenVertexArraysOES = 145, - GLMessage_Function_glGetActiveAttrib = 146, - GLMessage_Function_glGetActiveUniform = 147, - GLMessage_Function_glGetAttachedShaders = 148, - GLMessage_Function_glGetAttribLocation = 149, - GLMessage_Function_glGetBooleanv = 150, - GLMessage_Function_glGetBufferParameteriv = 151, - GLMessage_Function_glGetBufferPointervOES = 152, - GLMessage_Function_glGetClipPlanef = 153, - GLMessage_Function_glGetClipPlanefOES = 154, - GLMessage_Function_glGetClipPlanex = 155, - GLMessage_Function_glGetClipPlanexOES = 156, - GLMessage_Function_glGetDriverControlsQCOM = 157, - GLMessage_Function_glGetDriverControlStringQCOM = 158, - GLMessage_Function_glGetError = 159, - GLMessage_Function_glGetFenceivNV = 160, - GLMessage_Function_glGetFixedv = 161, - GLMessage_Function_glGetFixedvOES = 162, - GLMessage_Function_glGetFloatv = 163, - GLMessage_Function_glGetFramebufferAttachmentParameteriv = 164, - GLMessage_Function_glGetFramebufferAttachmentParameterivOES = 165, - GLMessage_Function_glGetIntegerv = 166, - GLMessage_Function_glGetLightfv = 167, - GLMessage_Function_glGetLightxv = 168, - GLMessage_Function_glGetLightxvOES = 169, - GLMessage_Function_glGetMaterialfv = 170, - GLMessage_Function_glGetMaterialxv = 171, - GLMessage_Function_glGetMaterialxvOES = 172, - GLMessage_Function_glGetPerfMonitorCounterDataAMD = 173, - GLMessage_Function_glGetPerfMonitorCounterInfoAMD = 174, - GLMessage_Function_glGetPerfMonitorCountersAMD = 175, - GLMessage_Function_glGetPerfMonitorCounterStringAMD = 176, - GLMessage_Function_glGetPerfMonitorGroupsAMD = 177, - GLMessage_Function_glGetPerfMonitorGroupStringAMD = 178, - GLMessage_Function_glGetPointerv = 179, - GLMessage_Function_glGetProgramBinaryOES = 180, - GLMessage_Function_glGetProgramInfoLog = 181, - GLMessage_Function_glGetProgramiv = 182, - GLMessage_Function_glGetRenderbufferParameteriv = 183, - GLMessage_Function_glGetRenderbufferParameterivOES = 184, - GLMessage_Function_glGetShaderInfoLog = 185, - GLMessage_Function_glGetShaderiv = 186, - GLMessage_Function_glGetShaderPrecisionFormat = 187, - GLMessage_Function_glGetShaderSource = 188, - GLMessage_Function_glGetString = 189, - GLMessage_Function_glGetTexEnvfv = 190, - GLMessage_Function_glGetTexEnviv = 191, - GLMessage_Function_glGetTexEnvxv = 192, - GLMessage_Function_glGetTexEnvxvOES = 193, - GLMessage_Function_glGetTexGenfvOES = 194, - GLMessage_Function_glGetTexGenivOES = 195, - GLMessage_Function_glGetTexGenxvOES = 196, - GLMessage_Function_glGetTexParameterfv = 197, - GLMessage_Function_glGetTexParameteriv = 198, - GLMessage_Function_glGetTexParameterxv = 199, - GLMessage_Function_glGetTexParameterxvOES = 200, - GLMessage_Function_glGetUniformfv = 201, - GLMessage_Function_glGetUniformiv = 202, - GLMessage_Function_glGetUniformLocation = 203, - GLMessage_Function_glGetVertexAttribfv = 204, - GLMessage_Function_glGetVertexAttribiv = 205, - GLMessage_Function_glGetVertexAttribPointerv = 206, - GLMessage_Function_glHint = 207, - GLMessage_Function_glIsBuffer = 208, - GLMessage_Function_glIsEnabled = 209, - GLMessage_Function_glIsFenceNV = 210, - GLMessage_Function_glIsFramebuffer = 211, - GLMessage_Function_glIsFramebufferOES = 212, - GLMessage_Function_glIsProgram = 213, - GLMessage_Function_glIsRenderbuffer = 214, - GLMessage_Function_glIsRenderbufferOES = 215, - GLMessage_Function_glIsShader = 216, - GLMessage_Function_glIsTexture = 217, - GLMessage_Function_glIsVertexArrayOES = 218, - GLMessage_Function_glLightf = 219, - GLMessage_Function_glLightfv = 220, - GLMessage_Function_glLightModelf = 221, - GLMessage_Function_glLightModelfv = 222, - GLMessage_Function_glLightModelx = 223, - GLMessage_Function_glLightModelxOES = 224, - GLMessage_Function_glLightModelxv = 225, - GLMessage_Function_glLightModelxvOES = 226, - GLMessage_Function_glLightx = 227, - GLMessage_Function_glLightxOES = 228, - GLMessage_Function_glLightxv = 229, - GLMessage_Function_glLightxvOES = 230, - GLMessage_Function_glLineWidth = 231, - GLMessage_Function_glLineWidthx = 232, - GLMessage_Function_glLineWidthxOES = 233, - GLMessage_Function_glLinkProgram = 234, - GLMessage_Function_glLoadIdentity = 235, - GLMessage_Function_glLoadMatrixf = 236, - GLMessage_Function_glLoadMatrixx = 237, - GLMessage_Function_glLoadMatrixxOES = 238, - GLMessage_Function_glLoadPaletteFromModelViewMatrixOES = 239, - GLMessage_Function_glLogicOp = 240, - GLMessage_Function_glMapBufferOES = 241, - GLMessage_Function_glMaterialf = 242, - GLMessage_Function_glMaterialfv = 243, - GLMessage_Function_glMaterialx = 244, - GLMessage_Function_glMaterialxOES = 245, - GLMessage_Function_glMaterialxv = 246, - GLMessage_Function_glMaterialxvOES = 247, - GLMessage_Function_glMatrixIndexPointerOES = 248, - GLMessage_Function_glMatrixMode = 249, - GLMessage_Function_glMultiDrawArraysEXT = 250, - GLMessage_Function_glMultiDrawElementsEXT = 251, - GLMessage_Function_glMultiTexCoord4f = 252, - GLMessage_Function_glMultiTexCoord4x = 253, - GLMessage_Function_glMultiTexCoord4xOES = 254, - GLMessage_Function_glMultMatrixf = 255, - GLMessage_Function_glMultMatrixx = 256, - GLMessage_Function_glMultMatrixxOES = 257, - GLMessage_Function_glNormal3f = 258, - GLMessage_Function_glNormal3x = 259, - GLMessage_Function_glNormal3xOES = 260, - GLMessage_Function_glNormalPointer = 261, - GLMessage_Function_glOrthof = 262, - GLMessage_Function_glOrthofOES = 263, - GLMessage_Function_glOrthox = 264, - GLMessage_Function_glOrthoxOES = 265, - GLMessage_Function_glPixelStorei = 266, - GLMessage_Function_glPointParameterf = 267, - GLMessage_Function_glPointParameterfv = 268, - GLMessage_Function_glPointParameterx = 269, - GLMessage_Function_glPointParameterxOES = 270, - GLMessage_Function_glPointParameterxv = 271, - GLMessage_Function_glPointParameterxvOES = 272, - GLMessage_Function_glPointSize = 273, - GLMessage_Function_glPointSizePointerOES = 274, - GLMessage_Function_glPointSizex = 275, - GLMessage_Function_glPointSizexOES = 276, - GLMessage_Function_glPolygonOffset = 277, - GLMessage_Function_glPolygonOffsetx = 278, - GLMessage_Function_glPolygonOffsetxOES = 279, - GLMessage_Function_glPopMatrix = 280, - GLMessage_Function_glProgramBinaryOES = 281, - GLMessage_Function_glPushMatrix = 282, - GLMessage_Function_glQueryMatrixxOES = 283, - GLMessage_Function_glReadPixels = 284, - GLMessage_Function_glReleaseShaderCompiler = 285, - GLMessage_Function_glRenderbufferStorage = 286, - GLMessage_Function_glRenderbufferStorageMultisampleIMG = 287, - GLMessage_Function_glRenderbufferStorageOES = 288, - GLMessage_Function_glRotatef = 289, - GLMessage_Function_glRotatex = 290, - GLMessage_Function_glRotatexOES = 291, - GLMessage_Function_glSampleCoverage = 292, - GLMessage_Function_glSampleCoveragex = 293, - GLMessage_Function_glSampleCoveragexOES = 294, - GLMessage_Function_glScalef = 295, - GLMessage_Function_glScalex = 296, - GLMessage_Function_glScalexOES = 297, - GLMessage_Function_glScissor = 298, - GLMessage_Function_glSelectPerfMonitorCountersAMD = 299, - GLMessage_Function_glSetFenceNV = 300, - GLMessage_Function_glShadeModel = 301, - GLMessage_Function_glShaderBinary = 302, - GLMessage_Function_glShaderSource = 303, - GLMessage_Function_glStartTilingQCOM = 304, - GLMessage_Function_glStencilFunc = 305, - GLMessage_Function_glStencilFuncSeparate = 306, - GLMessage_Function_glStencilMask = 307, - GLMessage_Function_glStencilMaskSeparate = 308, - GLMessage_Function_glStencilOp = 309, - GLMessage_Function_glStencilOpSeparate = 310, - GLMessage_Function_glTestFenceNV = 311, - GLMessage_Function_glTexCoordPointer = 312, - GLMessage_Function_glTexEnvf = 313, - GLMessage_Function_glTexEnvfv = 314, - GLMessage_Function_glTexEnvi = 315, - GLMessage_Function_glTexEnviv = 316, - GLMessage_Function_glTexEnvx = 317, - GLMessage_Function_glTexEnvxOES = 318, - GLMessage_Function_glTexEnvxv = 319, - GLMessage_Function_glTexEnvxvOES = 320, - GLMessage_Function_glTexGenfOES = 321, - GLMessage_Function_glTexGenfvOES = 322, - GLMessage_Function_glTexGeniOES = 323, - GLMessage_Function_glTexGenivOES = 324, - GLMessage_Function_glTexGenxOES = 325, - GLMessage_Function_glTexGenxvOES = 326, - GLMessage_Function_glTexImage2D = 327, - GLMessage_Function_glTexImage3DOES = 328, - GLMessage_Function_glTexParameterf = 329, - GLMessage_Function_glTexParameterfv = 330, - GLMessage_Function_glTexParameteri = 331, - GLMessage_Function_glTexParameteriv = 332, - GLMessage_Function_glTexParameterx = 333, - GLMessage_Function_glTexParameterxOES = 334, - GLMessage_Function_glTexParameterxv = 335, - GLMessage_Function_glTexParameterxvOES = 336, - GLMessage_Function_glTexSubImage2D = 337, - GLMessage_Function_glTexSubImage3DOES = 338, - GLMessage_Function_glTranslatef = 339, - GLMessage_Function_glTranslatex = 340, - GLMessage_Function_glTranslatexOES = 341, - GLMessage_Function_glUniform1f = 342, - GLMessage_Function_glUniform1fv = 343, - GLMessage_Function_glUniform1i = 344, - GLMessage_Function_glUniform1iv = 345, - GLMessage_Function_glUniform2f = 346, - GLMessage_Function_glUniform2fv = 347, - GLMessage_Function_glUniform2i = 348, - GLMessage_Function_glUniform2iv = 349, - GLMessage_Function_glUniform3f = 350, - GLMessage_Function_glUniform3fv = 351, - GLMessage_Function_glUniform3i = 352, - GLMessage_Function_glUniform3iv = 353, - GLMessage_Function_glUniform4f = 354, - GLMessage_Function_glUniform4fv = 355, - GLMessage_Function_glUniform4i = 356, - GLMessage_Function_glUniform4iv = 357, - GLMessage_Function_glUniformMatrix2fv = 358, - GLMessage_Function_glUniformMatrix3fv = 359, - GLMessage_Function_glUniformMatrix4fv = 360, - GLMessage_Function_glUnmapBufferOES = 361, - GLMessage_Function_glUseProgram = 362, - GLMessage_Function_glValidateProgram = 363, - GLMessage_Function_glVertexAttrib1f = 364, - GLMessage_Function_glVertexAttrib1fv = 365, - GLMessage_Function_glVertexAttrib2f = 366, - GLMessage_Function_glVertexAttrib2fv = 367, - GLMessage_Function_glVertexAttrib3f = 368, - GLMessage_Function_glVertexAttrib3fv = 369, - GLMessage_Function_glVertexAttrib4f = 370, - GLMessage_Function_glVertexAttrib4fv = 371, - GLMessage_Function_glVertexAttribPointer = 372, - GLMessage_Function_glVertexPointer = 373, - GLMessage_Function_glViewport = 374, - GLMessage_Function_glWeightPointerOES = 375, - GLMessage_Function_glReadBuffer = 376, - GLMessage_Function_glDrawRangeElements = 377, - GLMessage_Function_glTexImage3D = 378, - GLMessage_Function_glTexSubImage3D = 379, - GLMessage_Function_glCopyTexSubImage3D = 380, - GLMessage_Function_glCompressedTexImage3D = 381, - GLMessage_Function_glCompressedTexSubImage3D = 382, - GLMessage_Function_glGenQueries = 383, - GLMessage_Function_glDeleteQueries = 384, - GLMessage_Function_glIsQuery = 385, - GLMessage_Function_glBeginQuery = 386, - GLMessage_Function_glEndQuery = 387, - GLMessage_Function_glGetQueryiv = 388, - GLMessage_Function_glGetQueryObjectuiv = 389, - GLMessage_Function_glUnmapBuffer = 390, - GLMessage_Function_glGetBufferPointerv = 391, - GLMessage_Function_glDrawBuffers = 392, - GLMessage_Function_glUniformMatrix2x3fv = 393, - GLMessage_Function_glUniformMatrix3x2fv = 394, - GLMessage_Function_glUniformMatrix2x4fv = 395, - GLMessage_Function_glUniformMatrix4x2fv = 396, - GLMessage_Function_glUniformMatrix3x4fv = 397, - GLMessage_Function_glUniformMatrix4x3fv = 398, - GLMessage_Function_glBlitFramebuffer = 399, - GLMessage_Function_glRenderbufferStorageMultisample = 400, - GLMessage_Function_glFramebufferTextureLayer = 401, - GLMessage_Function_glMapBufferRange = 402, - GLMessage_Function_glFlushMappedBufferRange = 403, - GLMessage_Function_glBindVertexArray = 404, - GLMessage_Function_glDeleteVertexArrays = 405, - GLMessage_Function_glGenVertexArrays = 406, - GLMessage_Function_glIsVertexArray = 407, - GLMessage_Function_glGetIntegeri_v = 408, - GLMessage_Function_glBeginTransformFeedback = 409, - GLMessage_Function_glEndTransformFeedback = 410, - GLMessage_Function_glBindBufferRange = 411, - GLMessage_Function_glBindBufferBase = 412, - GLMessage_Function_glTransformFeedbackVaryings = 413, - GLMessage_Function_glGetTransformFeedbackVarying = 414, - GLMessage_Function_glVertexAttribIPointer = 415, - GLMessage_Function_glGetVertexAttribIiv = 416, - GLMessage_Function_glGetVertexAttribIuiv = 417, - GLMessage_Function_glVertexAttribI4i = 418, - GLMessage_Function_glVertexAttribI4ui = 419, - GLMessage_Function_glVertexAttribI4iv = 420, - GLMessage_Function_glVertexAttribI4uiv = 421, - GLMessage_Function_glGetUniformuiv = 422, - GLMessage_Function_glGetFragDataLocation = 423, - GLMessage_Function_glUniform1ui = 424, - GLMessage_Function_glUniform2ui = 425, - GLMessage_Function_glUniform3ui = 426, - GLMessage_Function_glUniform4ui = 427, - GLMessage_Function_glUniform1uiv = 428, - GLMessage_Function_glUniform2uiv = 429, - GLMessage_Function_glUniform3uiv = 430, - GLMessage_Function_glUniform4uiv = 431, - GLMessage_Function_glClearBufferiv = 432, - GLMessage_Function_glClearBufferuiv = 433, - GLMessage_Function_glClearBufferfv = 434, - GLMessage_Function_glClearBufferfi = 435, - GLMessage_Function_glGetStringi = 436, - GLMessage_Function_glCopyBufferSubData = 437, - GLMessage_Function_glGetUniformIndices = 438, - GLMessage_Function_glGetActiveUniformsiv = 439, - GLMessage_Function_glGetUniformBlockIndex = 440, - GLMessage_Function_glGetActiveUniformBlockiv = 441, - GLMessage_Function_glGetActiveUniformBlockName = 442, - GLMessage_Function_glUniformBlockBinding = 443, - GLMessage_Function_glDrawArraysInstanced = 444, - GLMessage_Function_glDrawElementsInstanced = 445, - GLMessage_Function_glFenceSync = 446, - GLMessage_Function_glIsSync = 447, - GLMessage_Function_glDeleteSync = 448, - GLMessage_Function_glClientWaitSync = 449, - GLMessage_Function_glWaitSync = 450, - GLMessage_Function_glGetInteger64v = 451, - GLMessage_Function_glGetSynciv = 452, - GLMessage_Function_glGetInteger64i_v = 453, - GLMessage_Function_glGetBufferParameteri64v = 454, - GLMessage_Function_glGenSamplers = 455, - GLMessage_Function_glDeleteSamplers = 456, - GLMessage_Function_glIsSampler = 457, - GLMessage_Function_glBindSampler = 458, - GLMessage_Function_glSamplerParameteri = 459, - GLMessage_Function_glSamplerParameteriv = 460, - GLMessage_Function_glSamplerParameterf = 461, - GLMessage_Function_glSamplerParameterfv = 462, - GLMessage_Function_glGetSamplerParameteriv = 463, - GLMessage_Function_glGetSamplerParameterfv = 464, - GLMessage_Function_glVertexAttribDivisor = 465, - GLMessage_Function_glBindTransformFeedback = 466, - GLMessage_Function_glDeleteTransformFeedbacks = 467, - GLMessage_Function_glGenTransformFeedbacks = 468, - GLMessage_Function_glIsTransformFeedback = 469, - GLMessage_Function_glPauseTransformFeedback = 470, - GLMessage_Function_glResumeTransformFeedback = 471, - GLMessage_Function_glGetProgramBinary = 472, - GLMessage_Function_glProgramBinary = 473, - GLMessage_Function_glProgramParameteri = 474, - GLMessage_Function_glInvalidateFramebuffer = 475, - GLMessage_Function_glInvalidateSubFramebuffer = 476, - GLMessage_Function_glTexStorage2D = 477, - GLMessage_Function_glTexStorage3D = 478, - GLMessage_Function_glGetInternalformativ = 479, - GLMessage_Function_glBeginPerfQueryINTEL = 480, - GLMessage_Function_glCreatePerfQueryINTEL = 481, - GLMessage_Function_glDeletePerfQueryINTEL = 482, - GLMessage_Function_glEndPerfQueryINTEL = 483, - GLMessage_Function_glGetFirstPerfQueryIdINTEL = 484, - GLMessage_Function_glGetNextPerfQueryIdINTEL = 485, - GLMessage_Function_glGetPerfCounterInfoINTEL = 486, - GLMessage_Function_glGetPerfQueryDataINTEL = 487, - GLMessage_Function_glGetPerfQueryIdByNameINTEL = 488, - GLMessage_Function_glGetPerfQueryInfoINTEL = 489, - GLMessage_Function_glBlendBarrierKHR = 490, - GLMessage_Function_glBlendBarrierNV = 491, - GLMessage_Function_glBlendParameteriNV = 492, - GLMessage_Function_glBlitFramebufferNV = 493, - GLMessage_Function_glFenceSyncAPPLE = 494, - GLMessage_Function_glIsSyncAPPLE = 495, - GLMessage_Function_glDeleteSyncAPPLE = 496, - GLMessage_Function_glClientWaitSyncAPPLE = 497, - GLMessage_Function_glWaitSyncAPPLE = 498, - GLMessage_Function_glGetInteger64vAPPLE = 499, - GLMessage_Function_glGetSyncivAPPLE = 500, - GLMessage_Function_glCopyBufferSubDataNV = 501, - GLMessage_Function_glActiveShaderProgramEXT = 502, - GLMessage_Function_glAlphaFuncQCOM = 503, - GLMessage_Function_glBeginQueryEXT = 504, - GLMessage_Function_glBindProgramPipelineEXT = 505, - GLMessage_Function_glBlitFramebufferANGLE = 506, - GLMessage_Function_glCreateShaderProgramvEXT = 507, - GLMessage_Function_glDeleteProgramPipelinesEXT = 508, - GLMessage_Function_glDeleteQueriesEXT = 509, - GLMessage_Function_glDrawBuffersNV = 510, - GLMessage_Function_glEndQueryEXT = 511, - GLMessage_Function_glFramebufferTexture2DMultisampleEXT = 512, - GLMessage_Function_glGenProgramPipelinesEXT = 513, - GLMessage_Function_glGenQueriesEXT = 514, - GLMessage_Function_glGetGraphicsResetStatusEXT = 515, - GLMessage_Function_glGetObjectLabelEXT = 516, - GLMessage_Function_glGetProgramPipelineInfoLogEXT = 517, - GLMessage_Function_glGetProgramPipelineivEXT = 518, - GLMessage_Function_glGetQueryObjectuivEXT = 519, - GLMessage_Function_glGetQueryivEXT = 520, - GLMessage_Function_glGetnUniformfvEXT = 521, - GLMessage_Function_glGetnUniformivEXT = 521, - GLMessage_Function_glInsertEventMarkerEXT = 522, - GLMessage_Function_glIsProgramPipelineEXT = 523, - GLMessage_Function_glIsQueryEXT = 524, - GLMessage_Function_glLabelObjectEXT = 525, - GLMessage_Function_glPopGroupMarkerEXT = 526, - GLMessage_Function_glProgramParameteriEXT = 527, - GLMessage_Function_glProgramUniform1fEXT = 528, - GLMessage_Function_glProgramUniform1fvEXT = 529, - GLMessage_Function_glProgramUniform1iEXT = 530, - GLMessage_Function_glProgramUniform1ivEXT = 531, - GLMessage_Function_glProgramUniform2fEXT = 532, - GLMessage_Function_glProgramUniform2fvEXT = 533, - GLMessage_Function_glProgramUniform2iEXT = 534, - GLMessage_Function_glProgramUniform2ivEXT = 535, - GLMessage_Function_glProgramUniform3fEXT = 536, - GLMessage_Function_glProgramUniform3fvEXT = 537, - GLMessage_Function_glProgramUniform3iEXT = 538, - GLMessage_Function_glProgramUniform3ivEXT = 539, - GLMessage_Function_glProgramUniform4fEXT = 540, - GLMessage_Function_glProgramUniform4fvEXT = 541, - GLMessage_Function_glProgramUniform4iEXT = 542, - GLMessage_Function_glProgramUniform4ivEXT = 543, - GLMessage_Function_glProgramUniformMatrix2fvEXT = 544, - GLMessage_Function_glProgramUniformMatrix3fvEXT = 545, - GLMessage_Function_glProgramUniformMatrix4fvEXT = 546, - GLMessage_Function_glPushGroupMarkerEXT = 547, - GLMessage_Function_glReadBufferNV = 548, - GLMessage_Function_glReadnPixelsEXT = 549, - GLMessage_Function_glRenderbufferStorageMultisampleANGLE = 550, - GLMessage_Function_glRenderbufferStorageMultisampleAPPLE = 551, - GLMessage_Function_glRenderbufferStorageMultisampleEXT = 552, - GLMessage_Function_glResolveMultisampleFramebufferAPPLE = 553, - GLMessage_Function_glTexStorage1DEXT = 554, - GLMessage_Function_glTexStorage2DEXT = 555, - GLMessage_Function_glTexStorage3DEXT = 556, - GLMessage_Function_glTextureStorage1DEXT = 557, - GLMessage_Function_glTextureStorage2DEXT = 558, - GLMessage_Function_glTextureStorage3DEXT = 559, - GLMessage_Function_glUseProgramStagesEXT = 560, - GLMessage_Function_glValidateProgramPipelineEXT = 561, - GLMessage_Function_glCopyTextureLevelsAPPLE = 562, - GLMessage_Function_glDebugMessageControlKHR = 563, - GLMessage_Function_glDebugMessageInsertKHR = 564, - GLMessage_Function_glDebugMessageCallbackKHR = 565, - GLMessage_Function_glGetDebugMessageLogKHR = 566, - GLMessage_Function_glPushDebugGroupKHR = 567, - GLMessage_Function_glPopDebugGroupKHR = 568, - GLMessage_Function_glObjectLabelKHR = 569, - GLMessage_Function_glGetObjectLabelKHR = 570, - GLMessage_Function_glObjectPtrLabelKHR = 571, - GLMessage_Function_glGetObjectPtrLabelKHR = 572, - GLMessage_Function_glGetPointervKHR = 573, - GLMessage_Function_glDrawArraysInstancedANGLE = 574, - GLMessage_Function_glDrawElementsInstancedANGLE = 575, - GLMessage_Function_glVertexAttribDivisorANGLE = 576, - GLMessage_Function_glDrawArraysInstancedEXT = 577, - GLMessage_Function_glDrawElementsInstancedEXT = 578, - GLMessage_Function_glVertexAttribDivisorEXT = 579, - GLMessage_Function_glDrawArraysInstancedNV = 580, - GLMessage_Function_glDrawElementsInstancedNV = 581, - GLMessage_Function_glVertexAttribDivisorNV = 582, - GLMessage_Function_glDrawBuffersEXT = 583, - GLMessage_Function_glReadBufferIndexedEXT = 584, - GLMessage_Function_glDrawBuffersIndexedEXT = 585, - GLMessage_Function_glGetIntegeri_vEXT = 586, - GLMessage_Function_glMapBufferRangeEXT = 587, - GLMessage_Function_glFlushMappedBufferRangeEXT = 588, - GLMessage_Function_glQueryCounterEXT = 589, - GLMessage_Function_glGetQueryObjecti64vEXT = 590, - GLMessage_Function_glGetQueryObjectivEXT = 591, - GLMessage_Function_glGetQueryObjectui64vEXT = 592, - GLMessage_Function_glGetTranslatedShaderSourceANGLE = 593, - GLMessage_Function_glMinSampleShadingOES = 594, - GLMessage_Function_glMultiTexCoord1bOES = 595, - GLMessage_Function_glMultiTexCoord1bvOES = 596, - GLMessage_Function_glMultiTexCoord2bOES = 597, - GLMessage_Function_glMultiTexCoord2bvOES = 598, - GLMessage_Function_glMultiTexCoord3bOES = 599, - GLMessage_Function_glMultiTexCoord3bvOES = 600, - GLMessage_Function_glMultiTexCoord4bOES = 601, - GLMessage_Function_glMultiTexCoord4bvOES = 602, - GLMessage_Function_glTexCoord1bOES = 603, - GLMessage_Function_glTexCoord1bvOES = 604, - GLMessage_Function_glTexCoord2bOES = 605, - GLMessage_Function_glTexCoord2bvOES = 606, - GLMessage_Function_glTexCoord3bOES = 607, - GLMessage_Function_glTexCoord3bvOES = 608, - GLMessage_Function_glTexCoord4bOES = 609, - GLMessage_Function_glTexCoord4bvOES = 610, - GLMessage_Function_glVertex2bOES = 611, - GLMessage_Function_glVertex2bvOES = 612, - GLMessage_Function_glVertex3bOES = 613, - GLMessage_Function_glVertex3bvOES = 614, - GLMessage_Function_glVertex4bOES = 615, - GLMessage_Function_glVertex4bvOES = 616, - GLMessage_Function_glProgramUniform1uiEXT = 617, - GLMessage_Function_glProgramUniform2uiEXT = 618, - GLMessage_Function_glProgramUniform3uiEXT = 619, - GLMessage_Function_glProgramUniform4uiEXT = 620, - GLMessage_Function_glProgramUniform1uivEXT = 621, - GLMessage_Function_glProgramUniform2uivEXT = 622, - GLMessage_Function_glProgramUniform3uivEXT = 623, - GLMessage_Function_glProgramUniform4uivEXT = 624, - GLMessage_Function_glProgramUniformMatrix2x3fvEXT = 625, - GLMessage_Function_glProgramUniformMatrix3x2fvEXT = 626, - GLMessage_Function_glProgramUniformMatrix2x4fvEXT = 627, - GLMessage_Function_glProgramUniformMatrix4x2fvEXT = 628, - GLMessage_Function_glProgramUniformMatrix3x4fvEXT = 629, - GLMessage_Function_glProgramUniformMatrix4x3fvEXT = 630, - GLMessage_Function_glRenderbufferStorageMultisampleNV = 631, - GLMessage_Function_glSampleCoverageOES = 632, - GLMessage_Function_glTexStorage3DMultisampleOES = 633, - GLMessage_Function_glUniformMatrix2x3fvNV = 634, - GLMessage_Function_glUniformMatrix3x2fvNV = 635, - GLMessage_Function_glUniformMatrix2x4fvNV = 636, - GLMessage_Function_glUniformMatrix4x2fvNV = 637, - GLMessage_Function_glUniformMatrix3x4fvNV = 638, - GLMessage_Function_glUniformMatrix4x3fvNV = 639, - GLMessage_Function_glActiveShaderProgram = 640, - GLMessage_Function_glBindImageTexture = 641, - GLMessage_Function_glBindProgramPipeline = 642, - GLMessage_Function_glBindVertexBuffer = 643, - GLMessage_Function_glCreateShaderProgramv = 644, - GLMessage_Function_glDeleteProgramPipelines = 645, - GLMessage_Function_glDispatchCompute = 646, - GLMessage_Function_glDispatchComputeIndirect = 647, - GLMessage_Function_glDrawArraysIndirect = 648, - GLMessage_Function_glDrawElementsIndirect = 649, - GLMessage_Function_glFramebufferParameteri = 650, - GLMessage_Function_glGenProgramPipelines = 651, - GLMessage_Function_glGetBooleani_v = 652, - GLMessage_Function_glGetFramebufferParameteriv = 653, - GLMessage_Function_glGetMultisamplefv = 654, - GLMessage_Function_glGetProgramInterfaceiv = 655, - GLMessage_Function_glGetProgramPipelineInfoLog = 656, - GLMessage_Function_glGetProgramPipelineiv = 657, - GLMessage_Function_glGetProgramResourceIndex = 658, - GLMessage_Function_glGetProgramResourceLocation = 659, - GLMessage_Function_glGetProgramResourceName = 660, - GLMessage_Function_glGetProgramResourceiv = 661, - GLMessage_Function_glGetTexLevelParameterfv = 662, - GLMessage_Function_glGetTexLevelParameteriv = 663, - GLMessage_Function_glIsProgramPipeline = 664, - GLMessage_Function_glMemoryBarrier = 665, - GLMessage_Function_glMemoryBarrierByRegion = 666, - GLMessage_Function_glProgramUniform1f = 667, - GLMessage_Function_glProgramUniform1fv = 668, - GLMessage_Function_glProgramUniform1i = 669, - GLMessage_Function_glProgramUniform1iv = 670, - GLMessage_Function_glProgramUniform1ui = 671, - GLMessage_Function_glProgramUniform1uiv = 672, - GLMessage_Function_glProgramUniform2f = 673, - GLMessage_Function_glProgramUniform2fv = 674, - GLMessage_Function_glProgramUniform2i = 675, - GLMessage_Function_glProgramUniform2iv = 676, - GLMessage_Function_glProgramUniform2ui = 677, - GLMessage_Function_glProgramUniform2uiv = 678, - GLMessage_Function_glProgramUniform3f = 679, - GLMessage_Function_glProgramUniform3fv = 680, - GLMessage_Function_glProgramUniform3i = 681, - GLMessage_Function_glProgramUniform3iv = 682, - GLMessage_Function_glProgramUniform3ui = 683, - GLMessage_Function_glProgramUniform3uiv = 684, - GLMessage_Function_glProgramUniform4f = 685, - GLMessage_Function_glProgramUniform4fv = 686, - GLMessage_Function_glProgramUniform4i = 687, - GLMessage_Function_glProgramUniform4iv = 688, - GLMessage_Function_glProgramUniform4ui = 689, - GLMessage_Function_glProgramUniform4uiv = 690, - GLMessage_Function_glProgramUniformMatrix2fv = 691, - GLMessage_Function_glProgramUniformMatrix2x3fv = 692, - GLMessage_Function_glProgramUniformMatrix2x4fv = 693, - GLMessage_Function_glProgramUniformMatrix3fv = 694, - GLMessage_Function_glProgramUniformMatrix3x2fv = 695, - GLMessage_Function_glProgramUniformMatrix3x4fv = 696, - GLMessage_Function_glProgramUniformMatrix4fv = 697, - GLMessage_Function_glProgramUniformMatrix4x2fv = 698, - GLMessage_Function_glProgramUniformMatrix4x3fv = 699, - GLMessage_Function_glSampleMaski = 700, - GLMessage_Function_glTexStorage2DMultisample = 701, - GLMessage_Function_glUseProgramStages = 702, - GLMessage_Function_glValidateProgramPipeline = 703, - GLMessage_Function_glVertexAttribBinding = 704, - GLMessage_Function_glVertexAttribFormat = 705, - GLMessage_Function_glVertexAttribIFormat = 706, - GLMessage_Function_glVertexBindingDivisor = 707, - GLMessage_Function_glBlendEquationSeparateiEXT = 708, - GLMessage_Function_glBlendEquationiEXT = 709, - GLMessage_Function_glBlendFuncSeparateiEXT = 710, - GLMessage_Function_glBlendFunciEXT = 711, - GLMessage_Function_glColorMaskiEXT = 712, - GLMessage_Function_glCopyImageSubDataEXT = 713, - GLMessage_Function_glDisableiEXT = 714, - GLMessage_Function_glEnableiEXT = 715, - GLMessage_Function_glFramebufferTextureEXT = 716, - GLMessage_Function_glGetSamplerParameterIivEXT = 717, - GLMessage_Function_glGetSamplerParameterIuivEXT = 718, - GLMessage_Function_glGetTexParameterIivEXT = 719, - GLMessage_Function_glGetTexParameterIuivEXT = 720, - GLMessage_Function_glIsEnablediEXT = 721, - GLMessage_Function_glPatchParameteriEXT = 722, - GLMessage_Function_glPrimitiveBoundingBoxEXT = 723, - GLMessage_Function_glSamplerParameterIivEXT = 724, - GLMessage_Function_glSamplerParameterIuivEXT = 725, - GLMessage_Function_glTexBufferEXT = 726, - GLMessage_Function_glTexBufferRangeEXT = 727, - GLMessage_Function_glTexParameterIivEXT = 728, - GLMessage_Function_glTexParameterIuivEXT = 729, - GLMessage_Function_glTextureViewEXT = 730, - GLMessage_Function_eglGetDisplay = 2000, - GLMessage_Function_eglInitialize = 2001, - GLMessage_Function_eglTerminate = 2002, - GLMessage_Function_eglGetConfigs = 2003, - GLMessage_Function_eglChooseConfig = 2004, - GLMessage_Function_eglGetConfigAttrib = 2005, - GLMessage_Function_eglCreateWindowSurface = 2006, - GLMessage_Function_eglCreatePixmapSurface = 2007, - GLMessage_Function_eglCreatePbufferSurface = 2008, - GLMessage_Function_eglDestroySurface = 2009, - GLMessage_Function_eglQuerySurface = 2010, - GLMessage_Function_eglCreateContext = 2011, - GLMessage_Function_eglDestroyContext = 2012, - GLMessage_Function_eglMakeCurrent = 2013, - GLMessage_Function_eglGetCurrentContext = 2014, - GLMessage_Function_eglGetCurrentSurface = 2015, - GLMessage_Function_eglGetCurrentDisplay = 2016, - GLMessage_Function_eglQueryContext = 2017, - GLMessage_Function_eglWaitGL = 2018, - GLMessage_Function_eglWaitNative = 2019, - GLMessage_Function_eglSwapBuffers = 2020, - GLMessage_Function_eglCopyBuffers = 2021, - GLMessage_Function_eglGetError = 2022, - GLMessage_Function_eglQueryString = 2023, - GLMessage_Function_eglGetProcAddress = 2024, - GLMessage_Function_eglSurfaceAttrib = 2025, - GLMessage_Function_eglBindTexImage = 2026, - GLMessage_Function_eglReleaseTexImage = 2027, - GLMessage_Function_eglSwapInterval = 2028, - GLMessage_Function_eglBindAPI = 2029, - GLMessage_Function_eglQueryAPI = 2030, - GLMessage_Function_eglWaitClient = 2031, - GLMessage_Function_eglReleaseThread = 2032, - GLMessage_Function_eglCreatePbufferFromClientBuffer = 2033, - GLMessage_Function_eglLockSurfaceKHR = 2034, - GLMessage_Function_eglUnlockSurfaceKHR = 2035, - GLMessage_Function_eglCreateImageKHR = 2036, - GLMessage_Function_eglDestroyImageKHR = 2037, - GLMessage_Function_eglCreateSyncKHR = 2038, - GLMessage_Function_eglDestroySyncKHR = 2039, - GLMessage_Function_eglClientWaitSyncKHR = 2040, - GLMessage_Function_eglGetSyncAttribKHR = 2041, - GLMessage_Function_eglSetSwapRectangleANDROID = 2042, - GLMessage_Function_eglGetRenderBufferANDROID = 2043, - GLMessage_Function_eglGetSystemTimeFrequencyNV = 2044, - GLMessage_Function_eglGetSystemTimeNV = 2045, - GLMessage_Function_invalid = 3000, - GLMessage_Function_glVertexAttribPointerData = 3001 -}; -bool GLMessage_Function_IsValid(int value); -const GLMessage_Function GLMessage_Function_Function_MIN = GLMessage_Function_glActiveTexture; -const GLMessage_Function GLMessage_Function_Function_MAX = GLMessage_Function_glVertexAttribPointerData; -const int GLMessage_Function_Function_ARRAYSIZE = GLMessage_Function_Function_MAX + 1; - -// =================================================================== - -class GLMessage_DataType : public ::google::protobuf::MessageLite { - public: - GLMessage_DataType(); - virtual ~GLMessage_DataType(); - - GLMessage_DataType(const GLMessage_DataType& from); - - inline GLMessage_DataType& operator=(const GLMessage_DataType& from) { - CopyFrom(from); - return *this; - } - - static const GLMessage_DataType& default_instance(); - - void Swap(GLMessage_DataType* other); - - // implements Message ---------------------------------------------- - - GLMessage_DataType* New() const; - void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from); - void CopyFrom(const GLMessage_DataType& from); - void MergeFrom(const GLMessage_DataType& from); - void Clear(); - bool IsInitialized() const; - - int ByteSize() const; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input); - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const; - int GetCachedSize() const { return _cached_size_; } - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const; - public: - - ::std::string GetTypeName() const; - - // nested types ---------------------------------------------------- - - typedef GLMessage_DataType_Type Type; - static const Type VOID = GLMessage_DataType_Type_VOID; - static const Type CHAR = GLMessage_DataType_Type_CHAR; - static const Type BYTE = GLMessage_DataType_Type_BYTE; - static const Type INT = GLMessage_DataType_Type_INT; - static const Type FLOAT = GLMessage_DataType_Type_FLOAT; - static const Type BOOL = GLMessage_DataType_Type_BOOL; - static const Type ENUM = GLMessage_DataType_Type_ENUM; - static const Type INT64 = GLMessage_DataType_Type_INT64; - static inline bool Type_IsValid(int value) { - return GLMessage_DataType_Type_IsValid(value); - } - static const Type Type_MIN = - GLMessage_DataType_Type_Type_MIN; - static const Type Type_MAX = - GLMessage_DataType_Type_Type_MAX; - static const int Type_ARRAYSIZE = - GLMessage_DataType_Type_Type_ARRAYSIZE; - - // accessors ------------------------------------------------------- - - // required .android.gltrace.GLMessage.DataType.Type type = 1 [default = VOID]; - inline bool has_type() const; - inline void clear_type(); - static const int kTypeFieldNumber = 1; - inline ::android::gltrace::GLMessage_DataType_Type type() const; - inline void set_type(::android::gltrace::GLMessage_DataType_Type value); - - // required bool isArray = 2 [default = false]; - inline bool has_isarray() const; - inline void clear_isarray(); - static const int kIsArrayFieldNumber = 2; - inline bool isarray() const; - inline void set_isarray(bool value); - - // repeated int32 intValue = 3; - inline int intvalue_size() const; - inline void clear_intvalue(); - static const int kIntValueFieldNumber = 3; - inline ::google::protobuf::int32 intvalue(int index) const; - inline void set_intvalue(int index, ::google::protobuf::int32 value); - inline void add_intvalue(::google::protobuf::int32 value); - inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >& - intvalue() const; - inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >* - mutable_intvalue(); - - // repeated float floatValue = 4; - inline int floatvalue_size() const; - inline void clear_floatvalue(); - static const int kFloatValueFieldNumber = 4; - inline float floatvalue(int index) const; - inline void set_floatvalue(int index, float value); - inline void add_floatvalue(float value); - inline const ::google::protobuf::RepeatedField< float >& - floatvalue() const; - inline ::google::protobuf::RepeatedField< float >* - mutable_floatvalue(); - - // repeated bytes charValue = 5; - inline int charvalue_size() const; - inline void clear_charvalue(); - static const int kCharValueFieldNumber = 5; - inline const ::std::string& charvalue(int index) const; - inline ::std::string* mutable_charvalue(int index); - inline void set_charvalue(int index, const ::std::string& value); - inline void set_charvalue(int index, const char* value); - inline void set_charvalue(int index, const void* value, size_t size); - inline ::std::string* add_charvalue(); - inline void add_charvalue(const ::std::string& value); - inline void add_charvalue(const char* value); - inline void add_charvalue(const void* value, size_t size); - inline const ::google::protobuf::RepeatedPtrField< ::std::string>& charvalue() const; - inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_charvalue(); - - // repeated bytes rawBytes = 6; - inline int rawbytes_size() const; - inline void clear_rawbytes(); - static const int kRawBytesFieldNumber = 6; - inline const ::std::string& rawbytes(int index) const; - inline ::std::string* mutable_rawbytes(int index); - inline void set_rawbytes(int index, const ::std::string& value); - inline void set_rawbytes(int index, const char* value); - inline void set_rawbytes(int index, const void* value, size_t size); - inline ::std::string* add_rawbytes(); - inline void add_rawbytes(const ::std::string& value); - inline void add_rawbytes(const char* value); - inline void add_rawbytes(const void* value, size_t size); - inline const ::google::protobuf::RepeatedPtrField< ::std::string>& rawbytes() const; - inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_rawbytes(); - - // repeated bool boolValue = 7; - inline int boolvalue_size() const; - inline void clear_boolvalue(); - static const int kBoolValueFieldNumber = 7; - inline bool boolvalue(int index) const; - inline void set_boolvalue(int index, bool value); - inline void add_boolvalue(bool value); - inline const ::google::protobuf::RepeatedField< bool >& - boolvalue() const; - inline ::google::protobuf::RepeatedField< bool >* - mutable_boolvalue(); - - // repeated int64 int64Value = 8; - inline int int64value_size() const; - inline void clear_int64value(); - static const int kInt64ValueFieldNumber = 8; - inline ::google::protobuf::int64 int64value(int index) const; - inline void set_int64value(int index, ::google::protobuf::int64 value); - inline void add_int64value(::google::protobuf::int64 value); - inline const ::google::protobuf::RepeatedField< ::google::protobuf::int64 >& - int64value() const; - inline ::google::protobuf::RepeatedField< ::google::protobuf::int64 >* - mutable_int64value(); - - // @@protoc_insertion_point(class_scope:android.gltrace.GLMessage.DataType) - private: - mutable int _cached_size_; - - int type_; - bool isarray_; - ::google::protobuf::RepeatedField< ::google::protobuf::int32 > intvalue_; - ::google::protobuf::RepeatedField< float > floatvalue_; - ::google::protobuf::RepeatedPtrField< ::std::string> charvalue_; - ::google::protobuf::RepeatedPtrField< ::std::string> rawbytes_; - ::google::protobuf::RepeatedField< bool > boolvalue_; - ::google::protobuf::RepeatedField< ::google::protobuf::int64 > int64value_; - friend void protobuf_AddDesc_gltrace_2eproto(); - friend void protobuf_AssignDesc_gltrace_2eproto(); - friend void protobuf_ShutdownFile_gltrace_2eproto(); - - ::google::protobuf::uint32 _has_bits_[(8 + 31) / 32]; - - // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? - inline bool _has_bit(int index) const { - return (_has_bits_[index / 32] & (1u << (index % 32))) != 0; - } - inline void _set_bit(int index) { - _has_bits_[index / 32] |= (1u << (index % 32)); - } - inline void _clear_bit(int index) { - _has_bits_[index / 32] &= ~(1u << (index % 32)); - } - - void InitAsDefaultInstance(); - static GLMessage_DataType* default_instance_; -}; -// ------------------------------------------------------------------- - -class GLMessage_FrameBuffer : public ::google::protobuf::MessageLite { - public: - GLMessage_FrameBuffer(); - virtual ~GLMessage_FrameBuffer(); - - GLMessage_FrameBuffer(const GLMessage_FrameBuffer& from); - - inline GLMessage_FrameBuffer& operator=(const GLMessage_FrameBuffer& from) { - CopyFrom(from); - return *this; - } - - static const GLMessage_FrameBuffer& default_instance(); - - void Swap(GLMessage_FrameBuffer* other); - - // implements Message ---------------------------------------------- - - GLMessage_FrameBuffer* New() const; - void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from); - void CopyFrom(const GLMessage_FrameBuffer& from); - void MergeFrom(const GLMessage_FrameBuffer& from); - void Clear(); - bool IsInitialized() const; - - int ByteSize() const; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input); - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const; - int GetCachedSize() const { return _cached_size_; } - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const; - public: - - ::std::string GetTypeName() const; - - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - - // required int32 width = 1; - inline bool has_width() const; - inline void clear_width(); - static const int kWidthFieldNumber = 1; - inline ::google::protobuf::int32 width() const; - inline void set_width(::google::protobuf::int32 value); - - // required int32 height = 2; - inline bool has_height() const; - inline void clear_height(); - static const int kHeightFieldNumber = 2; - inline ::google::protobuf::int32 height() const; - inline void set_height(::google::protobuf::int32 value); - - // repeated bytes contents = 3; - inline int contents_size() const; - inline void clear_contents(); - static const int kContentsFieldNumber = 3; - inline const ::std::string& contents(int index) const; - inline ::std::string* mutable_contents(int index); - inline void set_contents(int index, const ::std::string& value); - inline void set_contents(int index, const char* value); - inline void set_contents(int index, const void* value, size_t size); - inline ::std::string* add_contents(); - inline void add_contents(const ::std::string& value); - inline void add_contents(const char* value); - inline void add_contents(const void* value, size_t size); - inline const ::google::protobuf::RepeatedPtrField< ::std::string>& contents() const; - inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_contents(); - - // @@protoc_insertion_point(class_scope:android.gltrace.GLMessage.FrameBuffer) - private: - mutable int _cached_size_; - - ::google::protobuf::int32 width_; - ::google::protobuf::int32 height_; - ::google::protobuf::RepeatedPtrField< ::std::string> contents_; - friend void protobuf_AddDesc_gltrace_2eproto(); - friend void protobuf_AssignDesc_gltrace_2eproto(); - friend void protobuf_ShutdownFile_gltrace_2eproto(); - - ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32]; - - // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? - inline bool _has_bit(int index) const { - return (_has_bits_[index / 32] & (1u << (index % 32))) != 0; - } - inline void _set_bit(int index) { - _has_bits_[index / 32] |= (1u << (index % 32)); - } - inline void _clear_bit(int index) { - _has_bits_[index / 32] &= ~(1u << (index % 32)); - } - - void InitAsDefaultInstance(); - static GLMessage_FrameBuffer* default_instance_; -}; -// ------------------------------------------------------------------- - -class GLMessage : public ::google::protobuf::MessageLite { - public: - GLMessage(); - virtual ~GLMessage(); - - GLMessage(const GLMessage& from); - - inline GLMessage& operator=(const GLMessage& from) { - CopyFrom(from); - return *this; - } - - static const GLMessage& default_instance(); - - void Swap(GLMessage* other); - - // implements Message ---------------------------------------------- - - GLMessage* New() const; - void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from); - void CopyFrom(const GLMessage& from); - void MergeFrom(const GLMessage& from); - void Clear(); - bool IsInitialized() const; - - int ByteSize() const; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input); - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const; - int GetCachedSize() const { return _cached_size_; } - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const; - public: - - ::std::string GetTypeName() const; - - // nested types ---------------------------------------------------- - - typedef GLMessage_DataType DataType; - typedef GLMessage_FrameBuffer FrameBuffer; - - typedef GLMessage_Function Function; - static const Function glActiveTexture = GLMessage_Function_glActiveTexture; - static const Function glAlphaFunc = GLMessage_Function_glAlphaFunc; - static const Function glAlphaFuncx = GLMessage_Function_glAlphaFuncx; - static const Function glAlphaFuncxOES = GLMessage_Function_glAlphaFuncxOES; - static const Function glAttachShader = GLMessage_Function_glAttachShader; - static const Function glBeginPerfMonitorAMD = GLMessage_Function_glBeginPerfMonitorAMD; - static const Function glBindAttribLocation = GLMessage_Function_glBindAttribLocation; - static const Function glBindBuffer = GLMessage_Function_glBindBuffer; - static const Function glBindFramebuffer = GLMessage_Function_glBindFramebuffer; - static const Function glBindFramebufferOES = GLMessage_Function_glBindFramebufferOES; - static const Function glBindRenderbuffer = GLMessage_Function_glBindRenderbuffer; - static const Function glBindRenderbufferOES = GLMessage_Function_glBindRenderbufferOES; - static const Function glBindTexture = GLMessage_Function_glBindTexture; - static const Function glBindVertexArrayOES = GLMessage_Function_glBindVertexArrayOES; - static const Function glBlendColor = GLMessage_Function_glBlendColor; - static const Function glBlendEquation = GLMessage_Function_glBlendEquation; - static const Function glBlendEquationOES = GLMessage_Function_glBlendEquationOES; - static const Function glBlendEquationSeparate = GLMessage_Function_glBlendEquationSeparate; - static const Function glBlendEquationSeparateOES = GLMessage_Function_glBlendEquationSeparateOES; - static const Function glBlendFunc = GLMessage_Function_glBlendFunc; - static const Function glBlendFuncSeparate = GLMessage_Function_glBlendFuncSeparate; - static const Function glBlendFuncSeparateOES = GLMessage_Function_glBlendFuncSeparateOES; - static const Function glBufferData = GLMessage_Function_glBufferData; - static const Function glBufferSubData = GLMessage_Function_glBufferSubData; - static const Function glCheckFramebufferStatus = GLMessage_Function_glCheckFramebufferStatus; - static const Function glCheckFramebufferStatusOES = GLMessage_Function_glCheckFramebufferStatusOES; - static const Function glClearColor = GLMessage_Function_glClearColor; - static const Function glClearColorx = GLMessage_Function_glClearColorx; - static const Function glClearColorxOES = GLMessage_Function_glClearColorxOES; - static const Function glClearDepthf = GLMessage_Function_glClearDepthf; - static const Function glClearDepthfOES = GLMessage_Function_glClearDepthfOES; - static const Function glClearDepthx = GLMessage_Function_glClearDepthx; - static const Function glClearDepthxOES = GLMessage_Function_glClearDepthxOES; - static const Function glClear = GLMessage_Function_glClear; - static const Function glClearStencil = GLMessage_Function_glClearStencil; - static const Function glClientActiveTexture = GLMessage_Function_glClientActiveTexture; - static const Function glClipPlanef = GLMessage_Function_glClipPlanef; - static const Function glClipPlanefIMG = GLMessage_Function_glClipPlanefIMG; - static const Function glClipPlanefOES = GLMessage_Function_glClipPlanefOES; - static const Function glClipPlanex = GLMessage_Function_glClipPlanex; - static const Function glClipPlanexIMG = GLMessage_Function_glClipPlanexIMG; - static const Function glClipPlanexOES = GLMessage_Function_glClipPlanexOES; - static const Function glColor4f = GLMessage_Function_glColor4f; - static const Function glColor4ub = GLMessage_Function_glColor4ub; - static const Function glColor4x = GLMessage_Function_glColor4x; - static const Function glColor4xOES = GLMessage_Function_glColor4xOES; - static const Function glColorMask = GLMessage_Function_glColorMask; - static const Function glColorPointer = GLMessage_Function_glColorPointer; - static const Function glCompileShader = GLMessage_Function_glCompileShader; - static const Function glCompressedTexImage2D = GLMessage_Function_glCompressedTexImage2D; - static const Function glCompressedTexImage3DOES = GLMessage_Function_glCompressedTexImage3DOES; - static const Function glCompressedTexSubImage2D = GLMessage_Function_glCompressedTexSubImage2D; - static const Function glCompressedTexSubImage3DOES = GLMessage_Function_glCompressedTexSubImage3DOES; - static const Function glCopyTexImage2D = GLMessage_Function_glCopyTexImage2D; - static const Function glCopyTexSubImage2D = GLMessage_Function_glCopyTexSubImage2D; - static const Function glCopyTexSubImage3DOES = GLMessage_Function_glCopyTexSubImage3DOES; - static const Function glCoverageMaskNV = GLMessage_Function_glCoverageMaskNV; - static const Function glCoverageOperationNV = GLMessage_Function_glCoverageOperationNV; - static const Function glCreateProgram = GLMessage_Function_glCreateProgram; - static const Function glCreateShader = GLMessage_Function_glCreateShader; - static const Function glCullFace = GLMessage_Function_glCullFace; - static const Function glCurrentPaletteMatrixOES = GLMessage_Function_glCurrentPaletteMatrixOES; - static const Function glDeleteBuffers = GLMessage_Function_glDeleteBuffers; - static const Function glDeleteFencesNV = GLMessage_Function_glDeleteFencesNV; - static const Function glDeleteFramebuffers = GLMessage_Function_glDeleteFramebuffers; - static const Function glDeleteFramebuffersOES = GLMessage_Function_glDeleteFramebuffersOES; - static const Function glDeletePerfMonitorsAMD = GLMessage_Function_glDeletePerfMonitorsAMD; - static const Function glDeleteProgram = GLMessage_Function_glDeleteProgram; - static const Function glDeleteRenderbuffers = GLMessage_Function_glDeleteRenderbuffers; - static const Function glDeleteRenderbuffersOES = GLMessage_Function_glDeleteRenderbuffersOES; - static const Function glDeleteShader = GLMessage_Function_glDeleteShader; - static const Function glDeleteTextures = GLMessage_Function_glDeleteTextures; - static const Function glDeleteVertexArraysOES = GLMessage_Function_glDeleteVertexArraysOES; - static const Function glDepthFunc = GLMessage_Function_glDepthFunc; - static const Function glDepthMask = GLMessage_Function_glDepthMask; - static const Function glDepthRangef = GLMessage_Function_glDepthRangef; - static const Function glDepthRangefOES = GLMessage_Function_glDepthRangefOES; - static const Function glDepthRangex = GLMessage_Function_glDepthRangex; - static const Function glDepthRangexOES = GLMessage_Function_glDepthRangexOES; - static const Function glDetachShader = GLMessage_Function_glDetachShader; - static const Function glDisableClientState = GLMessage_Function_glDisableClientState; - static const Function glDisableDriverControlQCOM = GLMessage_Function_glDisableDriverControlQCOM; - static const Function glDisable = GLMessage_Function_glDisable; - static const Function glDisableVertexAttribArray = GLMessage_Function_glDisableVertexAttribArray; - static const Function glDiscardFramebufferEXT = GLMessage_Function_glDiscardFramebufferEXT; - static const Function glDrawArrays = GLMessage_Function_glDrawArrays; - static const Function glDrawElements = GLMessage_Function_glDrawElements; - static const Function glDrawTexfOES = GLMessage_Function_glDrawTexfOES; - static const Function glDrawTexfvOES = GLMessage_Function_glDrawTexfvOES; - static const Function glDrawTexiOES = GLMessage_Function_glDrawTexiOES; - static const Function glDrawTexivOES = GLMessage_Function_glDrawTexivOES; - static const Function glDrawTexsOES = GLMessage_Function_glDrawTexsOES; - static const Function glDrawTexsvOES = GLMessage_Function_glDrawTexsvOES; - static const Function glDrawTexxOES = GLMessage_Function_glDrawTexxOES; - static const Function glDrawTexxvOES = GLMessage_Function_glDrawTexxvOES; - static const Function glEGLImageTargetRenderbufferStorageOES = GLMessage_Function_glEGLImageTargetRenderbufferStorageOES; - static const Function glEGLImageTargetTexture2DOES = GLMessage_Function_glEGLImageTargetTexture2DOES; - static const Function glEnableClientState = GLMessage_Function_glEnableClientState; - static const Function glEnableDriverControlQCOM = GLMessage_Function_glEnableDriverControlQCOM; - static const Function glEnable = GLMessage_Function_glEnable; - static const Function glEnableVertexAttribArray = GLMessage_Function_glEnableVertexAttribArray; - static const Function glEndPerfMonitorAMD = GLMessage_Function_glEndPerfMonitorAMD; - static const Function glEndTilingQCOM = GLMessage_Function_glEndTilingQCOM; - static const Function glExtGetBufferPointervQCOM = GLMessage_Function_glExtGetBufferPointervQCOM; - static const Function glExtGetBuffersQCOM = GLMessage_Function_glExtGetBuffersQCOM; - static const Function glExtGetFramebuffersQCOM = GLMessage_Function_glExtGetFramebuffersQCOM; - static const Function glExtGetProgramBinarySourceQCOM = GLMessage_Function_glExtGetProgramBinarySourceQCOM; - static const Function glExtGetProgramsQCOM = GLMessage_Function_glExtGetProgramsQCOM; - static const Function glExtGetRenderbuffersQCOM = GLMessage_Function_glExtGetRenderbuffersQCOM; - static const Function glExtGetShadersQCOM = GLMessage_Function_glExtGetShadersQCOM; - static const Function glExtGetTexLevelParameterivQCOM = GLMessage_Function_glExtGetTexLevelParameterivQCOM; - static const Function glExtGetTexSubImageQCOM = GLMessage_Function_glExtGetTexSubImageQCOM; - static const Function glExtGetTexturesQCOM = GLMessage_Function_glExtGetTexturesQCOM; - static const Function glExtIsProgramBinaryQCOM = GLMessage_Function_glExtIsProgramBinaryQCOM; - static const Function glExtTexObjectStateOverrideiQCOM = GLMessage_Function_glExtTexObjectStateOverrideiQCOM; - static const Function glFinishFenceNV = GLMessage_Function_glFinishFenceNV; - static const Function glFinish = GLMessage_Function_glFinish; - static const Function glFlush = GLMessage_Function_glFlush; - static const Function glFogf = GLMessage_Function_glFogf; - static const Function glFogfv = GLMessage_Function_glFogfv; - static const Function glFogx = GLMessage_Function_glFogx; - static const Function glFogxOES = GLMessage_Function_glFogxOES; - static const Function glFogxv = GLMessage_Function_glFogxv; - static const Function glFogxvOES = GLMessage_Function_glFogxvOES; - static const Function glFramebufferRenderbuffer = GLMessage_Function_glFramebufferRenderbuffer; - static const Function glFramebufferRenderbufferOES = GLMessage_Function_glFramebufferRenderbufferOES; - static const Function glFramebufferTexture2D = GLMessage_Function_glFramebufferTexture2D; - static const Function glFramebufferTexture2DMultisampleIMG = GLMessage_Function_glFramebufferTexture2DMultisampleIMG; - static const Function glFramebufferTexture2DOES = GLMessage_Function_glFramebufferTexture2DOES; - static const Function glFramebufferTexture3DOES = GLMessage_Function_glFramebufferTexture3DOES; - static const Function glFrontFace = GLMessage_Function_glFrontFace; - static const Function glFrustumf = GLMessage_Function_glFrustumf; - static const Function glFrustumfOES = GLMessage_Function_glFrustumfOES; - static const Function glFrustumx = GLMessage_Function_glFrustumx; - static const Function glFrustumxOES = GLMessage_Function_glFrustumxOES; - static const Function glGenBuffers = GLMessage_Function_glGenBuffers; - static const Function glGenerateMipmap = GLMessage_Function_glGenerateMipmap; - static const Function glGenerateMipmapOES = GLMessage_Function_glGenerateMipmapOES; - static const Function glGenFencesNV = GLMessage_Function_glGenFencesNV; - static const Function glGenFramebuffers = GLMessage_Function_glGenFramebuffers; - static const Function glGenFramebuffersOES = GLMessage_Function_glGenFramebuffersOES; - static const Function glGenPerfMonitorsAMD = GLMessage_Function_glGenPerfMonitorsAMD; - static const Function glGenRenderbuffers = GLMessage_Function_glGenRenderbuffers; - static const Function glGenRenderbuffersOES = GLMessage_Function_glGenRenderbuffersOES; - static const Function glGenTextures = GLMessage_Function_glGenTextures; - static const Function glGenVertexArraysOES = GLMessage_Function_glGenVertexArraysOES; - static const Function glGetActiveAttrib = GLMessage_Function_glGetActiveAttrib; - static const Function glGetActiveUniform = GLMessage_Function_glGetActiveUniform; - static const Function glGetAttachedShaders = GLMessage_Function_glGetAttachedShaders; - static const Function glGetAttribLocation = GLMessage_Function_glGetAttribLocation; - static const Function glGetBooleanv = GLMessage_Function_glGetBooleanv; - static const Function glGetBufferParameteriv = GLMessage_Function_glGetBufferParameteriv; - static const Function glGetBufferPointervOES = GLMessage_Function_glGetBufferPointervOES; - static const Function glGetClipPlanef = GLMessage_Function_glGetClipPlanef; - static const Function glGetClipPlanefOES = GLMessage_Function_glGetClipPlanefOES; - static const Function glGetClipPlanex = GLMessage_Function_glGetClipPlanex; - static const Function glGetClipPlanexOES = GLMessage_Function_glGetClipPlanexOES; - static const Function glGetDriverControlsQCOM = GLMessage_Function_glGetDriverControlsQCOM; - static const Function glGetDriverControlStringQCOM = GLMessage_Function_glGetDriverControlStringQCOM; - static const Function glGetError = GLMessage_Function_glGetError; - static const Function glGetFenceivNV = GLMessage_Function_glGetFenceivNV; - static const Function glGetFixedv = GLMessage_Function_glGetFixedv; - static const Function glGetFixedvOES = GLMessage_Function_glGetFixedvOES; - static const Function glGetFloatv = GLMessage_Function_glGetFloatv; - static const Function glGetFramebufferAttachmentParameteriv = GLMessage_Function_glGetFramebufferAttachmentParameteriv; - static const Function glGetFramebufferAttachmentParameterivOES = GLMessage_Function_glGetFramebufferAttachmentParameterivOES; - static const Function glGetIntegerv = GLMessage_Function_glGetIntegerv; - static const Function glGetLightfv = GLMessage_Function_glGetLightfv; - static const Function glGetLightxv = GLMessage_Function_glGetLightxv; - static const Function glGetLightxvOES = GLMessage_Function_glGetLightxvOES; - static const Function glGetMaterialfv = GLMessage_Function_glGetMaterialfv; - static const Function glGetMaterialxv = GLMessage_Function_glGetMaterialxv; - static const Function glGetMaterialxvOES = GLMessage_Function_glGetMaterialxvOES; - static const Function glGetPerfMonitorCounterDataAMD = GLMessage_Function_glGetPerfMonitorCounterDataAMD; - static const Function glGetPerfMonitorCounterInfoAMD = GLMessage_Function_glGetPerfMonitorCounterInfoAMD; - static const Function glGetPerfMonitorCountersAMD = GLMessage_Function_glGetPerfMonitorCountersAMD; - static const Function glGetPerfMonitorCounterStringAMD = GLMessage_Function_glGetPerfMonitorCounterStringAMD; - static const Function glGetPerfMonitorGroupsAMD = GLMessage_Function_glGetPerfMonitorGroupsAMD; - static const Function glGetPerfMonitorGroupStringAMD = GLMessage_Function_glGetPerfMonitorGroupStringAMD; - static const Function glGetPointerv = GLMessage_Function_glGetPointerv; - static const Function glGetProgramBinaryOES = GLMessage_Function_glGetProgramBinaryOES; - static const Function glGetProgramInfoLog = GLMessage_Function_glGetProgramInfoLog; - static const Function glGetProgramiv = GLMessage_Function_glGetProgramiv; - static const Function glGetRenderbufferParameteriv = GLMessage_Function_glGetRenderbufferParameteriv; - static const Function glGetRenderbufferParameterivOES = GLMessage_Function_glGetRenderbufferParameterivOES; - static const Function glGetShaderInfoLog = GLMessage_Function_glGetShaderInfoLog; - static const Function glGetShaderiv = GLMessage_Function_glGetShaderiv; - static const Function glGetShaderPrecisionFormat = GLMessage_Function_glGetShaderPrecisionFormat; - static const Function glGetShaderSource = GLMessage_Function_glGetShaderSource; - static const Function glGetString = GLMessage_Function_glGetString; - static const Function glGetTexEnvfv = GLMessage_Function_glGetTexEnvfv; - static const Function glGetTexEnviv = GLMessage_Function_glGetTexEnviv; - static const Function glGetTexEnvxv = GLMessage_Function_glGetTexEnvxv; - static const Function glGetTexEnvxvOES = GLMessage_Function_glGetTexEnvxvOES; - static const Function glGetTexGenfvOES = GLMessage_Function_glGetTexGenfvOES; - static const Function glGetTexGenivOES = GLMessage_Function_glGetTexGenivOES; - static const Function glGetTexGenxvOES = GLMessage_Function_glGetTexGenxvOES; - static const Function glGetTexParameterfv = GLMessage_Function_glGetTexParameterfv; - static const Function glGetTexParameteriv = GLMessage_Function_glGetTexParameteriv; - static const Function glGetTexParameterxv = GLMessage_Function_glGetTexParameterxv; - static const Function glGetTexParameterxvOES = GLMessage_Function_glGetTexParameterxvOES; - static const Function glGetUniformfv = GLMessage_Function_glGetUniformfv; - static const Function glGetUniformiv = GLMessage_Function_glGetUniformiv; - static const Function glGetUniformLocation = GLMessage_Function_glGetUniformLocation; - static const Function glGetVertexAttribfv = GLMessage_Function_glGetVertexAttribfv; - static const Function glGetVertexAttribiv = GLMessage_Function_glGetVertexAttribiv; - static const Function glGetVertexAttribPointerv = GLMessage_Function_glGetVertexAttribPointerv; - static const Function glHint = GLMessage_Function_glHint; - static const Function glIsBuffer = GLMessage_Function_glIsBuffer; - static const Function glIsEnabled = GLMessage_Function_glIsEnabled; - static const Function glIsFenceNV = GLMessage_Function_glIsFenceNV; - static const Function glIsFramebuffer = GLMessage_Function_glIsFramebuffer; - static const Function glIsFramebufferOES = GLMessage_Function_glIsFramebufferOES; - static const Function glIsProgram = GLMessage_Function_glIsProgram; - static const Function glIsRenderbuffer = GLMessage_Function_glIsRenderbuffer; - static const Function glIsRenderbufferOES = GLMessage_Function_glIsRenderbufferOES; - static const Function glIsShader = GLMessage_Function_glIsShader; - static const Function glIsTexture = GLMessage_Function_glIsTexture; - static const Function glIsVertexArrayOES = GLMessage_Function_glIsVertexArrayOES; - static const Function glLightf = GLMessage_Function_glLightf; - static const Function glLightfv = GLMessage_Function_glLightfv; - static const Function glLightModelf = GLMessage_Function_glLightModelf; - static const Function glLightModelfv = GLMessage_Function_glLightModelfv; - static const Function glLightModelx = GLMessage_Function_glLightModelx; - static const Function glLightModelxOES = GLMessage_Function_glLightModelxOES; - static const Function glLightModelxv = GLMessage_Function_glLightModelxv; - static const Function glLightModelxvOES = GLMessage_Function_glLightModelxvOES; - static const Function glLightx = GLMessage_Function_glLightx; - static const Function glLightxOES = GLMessage_Function_glLightxOES; - static const Function glLightxv = GLMessage_Function_glLightxv; - static const Function glLightxvOES = GLMessage_Function_glLightxvOES; - static const Function glLineWidth = GLMessage_Function_glLineWidth; - static const Function glLineWidthx = GLMessage_Function_glLineWidthx; - static const Function glLineWidthxOES = GLMessage_Function_glLineWidthxOES; - static const Function glLinkProgram = GLMessage_Function_glLinkProgram; - static const Function glLoadIdentity = GLMessage_Function_glLoadIdentity; - static const Function glLoadMatrixf = GLMessage_Function_glLoadMatrixf; - static const Function glLoadMatrixx = GLMessage_Function_glLoadMatrixx; - static const Function glLoadMatrixxOES = GLMessage_Function_glLoadMatrixxOES; - static const Function glLoadPaletteFromModelViewMatrixOES = GLMessage_Function_glLoadPaletteFromModelViewMatrixOES; - static const Function glLogicOp = GLMessage_Function_glLogicOp; - static const Function glMapBufferOES = GLMessage_Function_glMapBufferOES; - static const Function glMaterialf = GLMessage_Function_glMaterialf; - static const Function glMaterialfv = GLMessage_Function_glMaterialfv; - static const Function glMaterialx = GLMessage_Function_glMaterialx; - static const Function glMaterialxOES = GLMessage_Function_glMaterialxOES; - static const Function glMaterialxv = GLMessage_Function_glMaterialxv; - static const Function glMaterialxvOES = GLMessage_Function_glMaterialxvOES; - static const Function glMatrixIndexPointerOES = GLMessage_Function_glMatrixIndexPointerOES; - static const Function glMatrixMode = GLMessage_Function_glMatrixMode; - static const Function glMultiDrawArraysEXT = GLMessage_Function_glMultiDrawArraysEXT; - static const Function glMultiDrawElementsEXT = GLMessage_Function_glMultiDrawElementsEXT; - static const Function glMultiTexCoord4f = GLMessage_Function_glMultiTexCoord4f; - static const Function glMultiTexCoord4x = GLMessage_Function_glMultiTexCoord4x; - static const Function glMultiTexCoord4xOES = GLMessage_Function_glMultiTexCoord4xOES; - static const Function glMultMatrixf = GLMessage_Function_glMultMatrixf; - static const Function glMultMatrixx = GLMessage_Function_glMultMatrixx; - static const Function glMultMatrixxOES = GLMessage_Function_glMultMatrixxOES; - static const Function glNormal3f = GLMessage_Function_glNormal3f; - static const Function glNormal3x = GLMessage_Function_glNormal3x; - static const Function glNormal3xOES = GLMessage_Function_glNormal3xOES; - static const Function glNormalPointer = GLMessage_Function_glNormalPointer; - static const Function glOrthof = GLMessage_Function_glOrthof; - static const Function glOrthofOES = GLMessage_Function_glOrthofOES; - static const Function glOrthox = GLMessage_Function_glOrthox; - static const Function glOrthoxOES = GLMessage_Function_glOrthoxOES; - static const Function glPixelStorei = GLMessage_Function_glPixelStorei; - static const Function glPointParameterf = GLMessage_Function_glPointParameterf; - static const Function glPointParameterfv = GLMessage_Function_glPointParameterfv; - static const Function glPointParameterx = GLMessage_Function_glPointParameterx; - static const Function glPointParameterxOES = GLMessage_Function_glPointParameterxOES; - static const Function glPointParameterxv = GLMessage_Function_glPointParameterxv; - static const Function glPointParameterxvOES = GLMessage_Function_glPointParameterxvOES; - static const Function glPointSize = GLMessage_Function_glPointSize; - static const Function glPointSizePointerOES = GLMessage_Function_glPointSizePointerOES; - static const Function glPointSizex = GLMessage_Function_glPointSizex; - static const Function glPointSizexOES = GLMessage_Function_glPointSizexOES; - static const Function glPolygonOffset = GLMessage_Function_glPolygonOffset; - static const Function glPolygonOffsetx = GLMessage_Function_glPolygonOffsetx; - static const Function glPolygonOffsetxOES = GLMessage_Function_glPolygonOffsetxOES; - static const Function glPopMatrix = GLMessage_Function_glPopMatrix; - static const Function glProgramBinaryOES = GLMessage_Function_glProgramBinaryOES; - static const Function glPushMatrix = GLMessage_Function_glPushMatrix; - static const Function glQueryMatrixxOES = GLMessage_Function_glQueryMatrixxOES; - static const Function glReadPixels = GLMessage_Function_glReadPixels; - static const Function glReleaseShaderCompiler = GLMessage_Function_glReleaseShaderCompiler; - static const Function glRenderbufferStorage = GLMessage_Function_glRenderbufferStorage; - static const Function glRenderbufferStorageMultisampleIMG = GLMessage_Function_glRenderbufferStorageMultisampleIMG; - static const Function glRenderbufferStorageOES = GLMessage_Function_glRenderbufferStorageOES; - static const Function glRotatef = GLMessage_Function_glRotatef; - static const Function glRotatex = GLMessage_Function_glRotatex; - static const Function glRotatexOES = GLMessage_Function_glRotatexOES; - static const Function glSampleCoverage = GLMessage_Function_glSampleCoverage; - static const Function glSampleCoveragex = GLMessage_Function_glSampleCoveragex; - static const Function glSampleCoveragexOES = GLMessage_Function_glSampleCoveragexOES; - static const Function glScalef = GLMessage_Function_glScalef; - static const Function glScalex = GLMessage_Function_glScalex; - static const Function glScalexOES = GLMessage_Function_glScalexOES; - static const Function glScissor = GLMessage_Function_glScissor; - static const Function glSelectPerfMonitorCountersAMD = GLMessage_Function_glSelectPerfMonitorCountersAMD; - static const Function glSetFenceNV = GLMessage_Function_glSetFenceNV; - static const Function glShadeModel = GLMessage_Function_glShadeModel; - static const Function glShaderBinary = GLMessage_Function_glShaderBinary; - static const Function glShaderSource = GLMessage_Function_glShaderSource; - static const Function glStartTilingQCOM = GLMessage_Function_glStartTilingQCOM; - static const Function glStencilFunc = GLMessage_Function_glStencilFunc; - static const Function glStencilFuncSeparate = GLMessage_Function_glStencilFuncSeparate; - static const Function glStencilMask = GLMessage_Function_glStencilMask; - static const Function glStencilMaskSeparate = GLMessage_Function_glStencilMaskSeparate; - static const Function glStencilOp = GLMessage_Function_glStencilOp; - static const Function glStencilOpSeparate = GLMessage_Function_glStencilOpSeparate; - static const Function glTestFenceNV = GLMessage_Function_glTestFenceNV; - static const Function glTexCoordPointer = GLMessage_Function_glTexCoordPointer; - static const Function glTexEnvf = GLMessage_Function_glTexEnvf; - static const Function glTexEnvfv = GLMessage_Function_glTexEnvfv; - static const Function glTexEnvi = GLMessage_Function_glTexEnvi; - static const Function glTexEnviv = GLMessage_Function_glTexEnviv; - static const Function glTexEnvx = GLMessage_Function_glTexEnvx; - static const Function glTexEnvxOES = GLMessage_Function_glTexEnvxOES; - static const Function glTexEnvxv = GLMessage_Function_glTexEnvxv; - static const Function glTexEnvxvOES = GLMessage_Function_glTexEnvxvOES; - static const Function glTexGenfOES = GLMessage_Function_glTexGenfOES; - static const Function glTexGenfvOES = GLMessage_Function_glTexGenfvOES; - static const Function glTexGeniOES = GLMessage_Function_glTexGeniOES; - static const Function glTexGenivOES = GLMessage_Function_glTexGenivOES; - static const Function glTexGenxOES = GLMessage_Function_glTexGenxOES; - static const Function glTexGenxvOES = GLMessage_Function_glTexGenxvOES; - static const Function glTexImage2D = GLMessage_Function_glTexImage2D; - static const Function glTexImage3DOES = GLMessage_Function_glTexImage3DOES; - static const Function glTexParameterf = GLMessage_Function_glTexParameterf; - static const Function glTexParameterfv = GLMessage_Function_glTexParameterfv; - static const Function glTexParameteri = GLMessage_Function_glTexParameteri; - static const Function glTexParameteriv = GLMessage_Function_glTexParameteriv; - static const Function glTexParameterx = GLMessage_Function_glTexParameterx; - static const Function glTexParameterxOES = GLMessage_Function_glTexParameterxOES; - static const Function glTexParameterxv = GLMessage_Function_glTexParameterxv; - static const Function glTexParameterxvOES = GLMessage_Function_glTexParameterxvOES; - static const Function glTexSubImage2D = GLMessage_Function_glTexSubImage2D; - static const Function glTexSubImage3DOES = GLMessage_Function_glTexSubImage3DOES; - static const Function glTranslatef = GLMessage_Function_glTranslatef; - static const Function glTranslatex = GLMessage_Function_glTranslatex; - static const Function glTranslatexOES = GLMessage_Function_glTranslatexOES; - static const Function glUniform1f = GLMessage_Function_glUniform1f; - static const Function glUniform1fv = GLMessage_Function_glUniform1fv; - static const Function glUniform1i = GLMessage_Function_glUniform1i; - static const Function glUniform1iv = GLMessage_Function_glUniform1iv; - static const Function glUniform2f = GLMessage_Function_glUniform2f; - static const Function glUniform2fv = GLMessage_Function_glUniform2fv; - static const Function glUniform2i = GLMessage_Function_glUniform2i; - static const Function glUniform2iv = GLMessage_Function_glUniform2iv; - static const Function glUniform3f = GLMessage_Function_glUniform3f; - static const Function glUniform3fv = GLMessage_Function_glUniform3fv; - static const Function glUniform3i = GLMessage_Function_glUniform3i; - static const Function glUniform3iv = GLMessage_Function_glUniform3iv; - static const Function glUniform4f = GLMessage_Function_glUniform4f; - static const Function glUniform4fv = GLMessage_Function_glUniform4fv; - static const Function glUniform4i = GLMessage_Function_glUniform4i; - static const Function glUniform4iv = GLMessage_Function_glUniform4iv; - static const Function glUniformMatrix2fv = GLMessage_Function_glUniformMatrix2fv; - static const Function glUniformMatrix3fv = GLMessage_Function_glUniformMatrix3fv; - static const Function glUniformMatrix4fv = GLMessage_Function_glUniformMatrix4fv; - static const Function glUnmapBufferOES = GLMessage_Function_glUnmapBufferOES; - static const Function glUseProgram = GLMessage_Function_glUseProgram; - static const Function glValidateProgram = GLMessage_Function_glValidateProgram; - static const Function glVertexAttrib1f = GLMessage_Function_glVertexAttrib1f; - static const Function glVertexAttrib1fv = GLMessage_Function_glVertexAttrib1fv; - static const Function glVertexAttrib2f = GLMessage_Function_glVertexAttrib2f; - static const Function glVertexAttrib2fv = GLMessage_Function_glVertexAttrib2fv; - static const Function glVertexAttrib3f = GLMessage_Function_glVertexAttrib3f; - static const Function glVertexAttrib3fv = GLMessage_Function_glVertexAttrib3fv; - static const Function glVertexAttrib4f = GLMessage_Function_glVertexAttrib4f; - static const Function glVertexAttrib4fv = GLMessage_Function_glVertexAttrib4fv; - static const Function glVertexAttribPointer = GLMessage_Function_glVertexAttribPointer; - static const Function glVertexPointer = GLMessage_Function_glVertexPointer; - static const Function glViewport = GLMessage_Function_glViewport; - static const Function glWeightPointerOES = GLMessage_Function_glWeightPointerOES; - static const Function glReadBuffer = GLMessage_Function_glReadBuffer; - static const Function glDrawRangeElements = GLMessage_Function_glDrawRangeElements; - static const Function glTexImage3D = GLMessage_Function_glTexImage3D; - static const Function glTexSubImage3D = GLMessage_Function_glTexSubImage3D; - static const Function glCopyTexSubImage3D = GLMessage_Function_glCopyTexSubImage3D; - static const Function glCompressedTexImage3D = GLMessage_Function_glCompressedTexImage3D; - static const Function glCompressedTexSubImage3D = GLMessage_Function_glCompressedTexSubImage3D; - static const Function glGenQueries = GLMessage_Function_glGenQueries; - static const Function glDeleteQueries = GLMessage_Function_glDeleteQueries; - static const Function glIsQuery = GLMessage_Function_glIsQuery; - static const Function glBeginQuery = GLMessage_Function_glBeginQuery; - static const Function glEndQuery = GLMessage_Function_glEndQuery; - static const Function glGetQueryiv = GLMessage_Function_glGetQueryiv; - static const Function glGetQueryObjectuiv = GLMessage_Function_glGetQueryObjectuiv; - static const Function glUnmapBuffer = GLMessage_Function_glUnmapBuffer; - static const Function glGetBufferPointerv = GLMessage_Function_glGetBufferPointerv; - static const Function glDrawBuffers = GLMessage_Function_glDrawBuffers; - static const Function glUniformMatrix2x3fv = GLMessage_Function_glUniformMatrix2x3fv; - static const Function glUniformMatrix3x2fv = GLMessage_Function_glUniformMatrix3x2fv; - static const Function glUniformMatrix2x4fv = GLMessage_Function_glUniformMatrix2x4fv; - static const Function glUniformMatrix4x2fv = GLMessage_Function_glUniformMatrix4x2fv; - static const Function glUniformMatrix3x4fv = GLMessage_Function_glUniformMatrix3x4fv; - static const Function glUniformMatrix4x3fv = GLMessage_Function_glUniformMatrix4x3fv; - static const Function glBlitFramebuffer = GLMessage_Function_glBlitFramebuffer; - static const Function glRenderbufferStorageMultisample = GLMessage_Function_glRenderbufferStorageMultisample; - static const Function glFramebufferTextureLayer = GLMessage_Function_glFramebufferTextureLayer; - static const Function glMapBufferRange = GLMessage_Function_glMapBufferRange; - static const Function glFlushMappedBufferRange = GLMessage_Function_glFlushMappedBufferRange; - static const Function glBindVertexArray = GLMessage_Function_glBindVertexArray; - static const Function glDeleteVertexArrays = GLMessage_Function_glDeleteVertexArrays; - static const Function glGenVertexArrays = GLMessage_Function_glGenVertexArrays; - static const Function glIsVertexArray = GLMessage_Function_glIsVertexArray; - static const Function glGetIntegeri_v = GLMessage_Function_glGetIntegeri_v; - static const Function glBeginTransformFeedback = GLMessage_Function_glBeginTransformFeedback; - static const Function glEndTransformFeedback = GLMessage_Function_glEndTransformFeedback; - static const Function glBindBufferRange = GLMessage_Function_glBindBufferRange; - static const Function glBindBufferBase = GLMessage_Function_glBindBufferBase; - static const Function glTransformFeedbackVaryings = GLMessage_Function_glTransformFeedbackVaryings; - static const Function glGetTransformFeedbackVarying = GLMessage_Function_glGetTransformFeedbackVarying; - static const Function glVertexAttribIPointer = GLMessage_Function_glVertexAttribIPointer; - static const Function glGetVertexAttribIiv = GLMessage_Function_glGetVertexAttribIiv; - static const Function glGetVertexAttribIuiv = GLMessage_Function_glGetVertexAttribIuiv; - static const Function glVertexAttribI4i = GLMessage_Function_glVertexAttribI4i; - static const Function glVertexAttribI4ui = GLMessage_Function_glVertexAttribI4ui; - static const Function glVertexAttribI4iv = GLMessage_Function_glVertexAttribI4iv; - static const Function glVertexAttribI4uiv = GLMessage_Function_glVertexAttribI4uiv; - static const Function glGetUniformuiv = GLMessage_Function_glGetUniformuiv; - static const Function glGetFragDataLocation = GLMessage_Function_glGetFragDataLocation; - static const Function glUniform1ui = GLMessage_Function_glUniform1ui; - static const Function glUniform2ui = GLMessage_Function_glUniform2ui; - static const Function glUniform3ui = GLMessage_Function_glUniform3ui; - static const Function glUniform4ui = GLMessage_Function_glUniform4ui; - static const Function glUniform1uiv = GLMessage_Function_glUniform1uiv; - static const Function glUniform2uiv = GLMessage_Function_glUniform2uiv; - static const Function glUniform3uiv = GLMessage_Function_glUniform3uiv; - static const Function glUniform4uiv = GLMessage_Function_glUniform4uiv; - static const Function glClearBufferiv = GLMessage_Function_glClearBufferiv; - static const Function glClearBufferuiv = GLMessage_Function_glClearBufferuiv; - static const Function glClearBufferfv = GLMessage_Function_glClearBufferfv; - static const Function glClearBufferfi = GLMessage_Function_glClearBufferfi; - static const Function glGetStringi = GLMessage_Function_glGetStringi; - static const Function glCopyBufferSubData = GLMessage_Function_glCopyBufferSubData; - static const Function glGetUniformIndices = GLMessage_Function_glGetUniformIndices; - static const Function glGetActiveUniformsiv = GLMessage_Function_glGetActiveUniformsiv; - static const Function glGetUniformBlockIndex = GLMessage_Function_glGetUniformBlockIndex; - static const Function glGetActiveUniformBlockiv = GLMessage_Function_glGetActiveUniformBlockiv; - static const Function glGetActiveUniformBlockName = GLMessage_Function_glGetActiveUniformBlockName; - static const Function glUniformBlockBinding = GLMessage_Function_glUniformBlockBinding; - static const Function glDrawArraysInstanced = GLMessage_Function_glDrawArraysInstanced; - static const Function glDrawElementsInstanced = GLMessage_Function_glDrawElementsInstanced; - static const Function glFenceSync = GLMessage_Function_glFenceSync; - static const Function glIsSync = GLMessage_Function_glIsSync; - static const Function glDeleteSync = GLMessage_Function_glDeleteSync; - static const Function glClientWaitSync = GLMessage_Function_glClientWaitSync; - static const Function glWaitSync = GLMessage_Function_glWaitSync; - static const Function glGetInteger64v = GLMessage_Function_glGetInteger64v; - static const Function glGetSynciv = GLMessage_Function_glGetSynciv; - static const Function glGetInteger64i_v = GLMessage_Function_glGetInteger64i_v; - static const Function glGetBufferParameteri64v = GLMessage_Function_glGetBufferParameteri64v; - static const Function glGenSamplers = GLMessage_Function_glGenSamplers; - static const Function glDeleteSamplers = GLMessage_Function_glDeleteSamplers; - static const Function glIsSampler = GLMessage_Function_glIsSampler; - static const Function glBindSampler = GLMessage_Function_glBindSampler; - static const Function glSamplerParameteri = GLMessage_Function_glSamplerParameteri; - static const Function glSamplerParameteriv = GLMessage_Function_glSamplerParameteriv; - static const Function glSamplerParameterf = GLMessage_Function_glSamplerParameterf; - static const Function glSamplerParameterfv = GLMessage_Function_glSamplerParameterfv; - static const Function glGetSamplerParameteriv = GLMessage_Function_glGetSamplerParameteriv; - static const Function glGetSamplerParameterfv = GLMessage_Function_glGetSamplerParameterfv; - static const Function glVertexAttribDivisor = GLMessage_Function_glVertexAttribDivisor; - static const Function glBindTransformFeedback = GLMessage_Function_glBindTransformFeedback; - static const Function glDeleteTransformFeedbacks = GLMessage_Function_glDeleteTransformFeedbacks; - static const Function glGenTransformFeedbacks = GLMessage_Function_glGenTransformFeedbacks; - static const Function glIsTransformFeedback = GLMessage_Function_glIsTransformFeedback; - static const Function glPauseTransformFeedback = GLMessage_Function_glPauseTransformFeedback; - static const Function glResumeTransformFeedback = GLMessage_Function_glResumeTransformFeedback; - static const Function glGetProgramBinary = GLMessage_Function_glGetProgramBinary; - static const Function glProgramBinary = GLMessage_Function_glProgramBinary; - static const Function glProgramParameteri = GLMessage_Function_glProgramParameteri; - static const Function glInvalidateFramebuffer = GLMessage_Function_glInvalidateFramebuffer; - static const Function glInvalidateSubFramebuffer = GLMessage_Function_glInvalidateSubFramebuffer; - static const Function glTexStorage2D = GLMessage_Function_glTexStorage2D; - static const Function glTexStorage3D = GLMessage_Function_glTexStorage3D; - static const Function glGetInternalformativ = GLMessage_Function_glGetInternalformativ; - static const Function glBeginPerfQueryINTEL = GLMessage_Function_glBeginPerfQueryINTEL; - static const Function glCreatePerfQueryINTEL = GLMessage_Function_glCreatePerfQueryINTEL; - static const Function glDeletePerfQueryINTEL = GLMessage_Function_glDeletePerfQueryINTEL; - static const Function glEndPerfQueryINTEL = GLMessage_Function_glEndPerfQueryINTEL; - static const Function glGetFirstPerfQueryIdINTEL = GLMessage_Function_glGetFirstPerfQueryIdINTEL; - static const Function glGetNextPerfQueryIdINTEL = GLMessage_Function_glGetNextPerfQueryIdINTEL; - static const Function glGetPerfCounterInfoINTEL = GLMessage_Function_glGetPerfCounterInfoINTEL; - static const Function glGetPerfQueryDataINTEL = GLMessage_Function_glGetPerfQueryDataINTEL; - static const Function glGetPerfQueryIdByNameINTEL = GLMessage_Function_glGetPerfQueryIdByNameINTEL; - static const Function glGetPerfQueryInfoINTEL = GLMessage_Function_glGetPerfQueryInfoINTEL; - static const Function glBlendBarrierKHR = GLMessage_Function_glBlendBarrierKHR; - static const Function glBlendBarrierNV = GLMessage_Function_glBlendBarrierNV; - static const Function glBlendParameteriNV = GLMessage_Function_glBlendParameteriNV; - static const Function glBlitFramebufferNV = GLMessage_Function_glBlitFramebufferNV; - static const Function glFenceSyncAPPLE = GLMessage_Function_glFenceSyncAPPLE; - static const Function glIsSyncAPPLE = GLMessage_Function_glIsSyncAPPLE; - static const Function glDeleteSyncAPPLE = GLMessage_Function_glDeleteSyncAPPLE; - static const Function glClientWaitSyncAPPLE = GLMessage_Function_glClientWaitSyncAPPLE; - static const Function glWaitSyncAPPLE = GLMessage_Function_glWaitSyncAPPLE; - static const Function glGetInteger64vAPPLE = GLMessage_Function_glGetInteger64vAPPLE; - static const Function glGetSyncivAPPLE = GLMessage_Function_glGetSyncivAPPLE; - static const Function glCopyBufferSubDataNV = GLMessage_Function_glCopyBufferSubDataNV; - static const Function glActiveShaderProgramEXT = GLMessage_Function_glActiveShaderProgramEXT; - static const Function glAlphaFuncQCOM = GLMessage_Function_glAlphaFuncQCOM; - static const Function glBeginQueryEXT = GLMessage_Function_glBeginQueryEXT; - static const Function glBindProgramPipelineEXT = GLMessage_Function_glBindProgramPipelineEXT; - static const Function glBlitFramebufferANGLE = GLMessage_Function_glBlitFramebufferANGLE; - static const Function glCreateShaderProgramvEXT = GLMessage_Function_glCreateShaderProgramvEXT; - static const Function glDeleteProgramPipelinesEXT = GLMessage_Function_glDeleteProgramPipelinesEXT; - static const Function glDeleteQueriesEXT = GLMessage_Function_glDeleteQueriesEXT; - static const Function glDrawBuffersNV = GLMessage_Function_glDrawBuffersNV; - static const Function glEndQueryEXT = GLMessage_Function_glEndQueryEXT; - static const Function glFramebufferTexture2DMultisampleEXT = GLMessage_Function_glFramebufferTexture2DMultisampleEXT; - static const Function glGenProgramPipelinesEXT = GLMessage_Function_glGenProgramPipelinesEXT; - static const Function glGenQueriesEXT = GLMessage_Function_glGenQueriesEXT; - static const Function glGetGraphicsResetStatusEXT = GLMessage_Function_glGetGraphicsResetStatusEXT; - static const Function glGetObjectLabelEXT = GLMessage_Function_glGetObjectLabelEXT; - static const Function glGetProgramPipelineInfoLogEXT = GLMessage_Function_glGetProgramPipelineInfoLogEXT; - static const Function glGetProgramPipelineivEXT = GLMessage_Function_glGetProgramPipelineivEXT; - static const Function glGetQueryObjectuivEXT = GLMessage_Function_glGetQueryObjectuivEXT; - static const Function glGetQueryivEXT = GLMessage_Function_glGetQueryivEXT; - static const Function glGetnUniformfvEXT = GLMessage_Function_glGetnUniformfvEXT; - static const Function glGetnUniformivEXT = GLMessage_Function_glGetnUniformivEXT; - static const Function glInsertEventMarkerEXT = GLMessage_Function_glInsertEventMarkerEXT; - static const Function glIsProgramPipelineEXT = GLMessage_Function_glIsProgramPipelineEXT; - static const Function glIsQueryEXT = GLMessage_Function_glIsQueryEXT; - static const Function glLabelObjectEXT = GLMessage_Function_glLabelObjectEXT; - static const Function glPopGroupMarkerEXT = GLMessage_Function_glPopGroupMarkerEXT; - static const Function glProgramParameteriEXT = GLMessage_Function_glProgramParameteriEXT; - static const Function glProgramUniform1fEXT = GLMessage_Function_glProgramUniform1fEXT; - static const Function glProgramUniform1fvEXT = GLMessage_Function_glProgramUniform1fvEXT; - static const Function glProgramUniform1iEXT = GLMessage_Function_glProgramUniform1iEXT; - static const Function glProgramUniform1ivEXT = GLMessage_Function_glProgramUniform1ivEXT; - static const Function glProgramUniform2fEXT = GLMessage_Function_glProgramUniform2fEXT; - static const Function glProgramUniform2fvEXT = GLMessage_Function_glProgramUniform2fvEXT; - static const Function glProgramUniform2iEXT = GLMessage_Function_glProgramUniform2iEXT; - static const Function glProgramUniform2ivEXT = GLMessage_Function_glProgramUniform2ivEXT; - static const Function glProgramUniform3fEXT = GLMessage_Function_glProgramUniform3fEXT; - static const Function glProgramUniform3fvEXT = GLMessage_Function_glProgramUniform3fvEXT; - static const Function glProgramUniform3iEXT = GLMessage_Function_glProgramUniform3iEXT; - static const Function glProgramUniform3ivEXT = GLMessage_Function_glProgramUniform3ivEXT; - static const Function glProgramUniform4fEXT = GLMessage_Function_glProgramUniform4fEXT; - static const Function glProgramUniform4fvEXT = GLMessage_Function_glProgramUniform4fvEXT; - static const Function glProgramUniform4iEXT = GLMessage_Function_glProgramUniform4iEXT; - static const Function glProgramUniform4ivEXT = GLMessage_Function_glProgramUniform4ivEXT; - static const Function glProgramUniformMatrix2fvEXT = GLMessage_Function_glProgramUniformMatrix2fvEXT; - static const Function glProgramUniformMatrix3fvEXT = GLMessage_Function_glProgramUniformMatrix3fvEXT; - static const Function glProgramUniformMatrix4fvEXT = GLMessage_Function_glProgramUniformMatrix4fvEXT; - static const Function glPushGroupMarkerEXT = GLMessage_Function_glPushGroupMarkerEXT; - static const Function glReadBufferNV = GLMessage_Function_glReadBufferNV; - static const Function glReadnPixelsEXT = GLMessage_Function_glReadnPixelsEXT; - static const Function glRenderbufferStorageMultisampleANGLE = GLMessage_Function_glRenderbufferStorageMultisampleANGLE; - static const Function glRenderbufferStorageMultisampleAPPLE = GLMessage_Function_glRenderbufferStorageMultisampleAPPLE; - static const Function glRenderbufferStorageMultisampleEXT = GLMessage_Function_glRenderbufferStorageMultisampleEXT; - static const Function glResolveMultisampleFramebufferAPPLE = GLMessage_Function_glResolveMultisampleFramebufferAPPLE; - static const Function glTexStorage1DEXT = GLMessage_Function_glTexStorage1DEXT; - static const Function glTexStorage2DEXT = GLMessage_Function_glTexStorage2DEXT; - static const Function glTexStorage3DEXT = GLMessage_Function_glTexStorage3DEXT; - static const Function glTextureStorage1DEXT = GLMessage_Function_glTextureStorage1DEXT; - static const Function glTextureStorage2DEXT = GLMessage_Function_glTextureStorage2DEXT; - static const Function glTextureStorage3DEXT = GLMessage_Function_glTextureStorage3DEXT; - static const Function glUseProgramStagesEXT = GLMessage_Function_glUseProgramStagesEXT; - static const Function glValidateProgramPipelineEXT = GLMessage_Function_glValidateProgramPipelineEXT; - static const Function glCopyTextureLevelsAPPLE = GLMessage_Function_glCopyTextureLevelsAPPLE; - static const Function glDebugMessageControlKHR = GLMessage_Function_glDebugMessageControlKHR; - static const Function glDebugMessageInsertKHR = GLMessage_Function_glDebugMessageInsertKHR; - static const Function glDebugMessageCallbackKHR = GLMessage_Function_glDebugMessageCallbackKHR; - static const Function glGetDebugMessageLogKHR = GLMessage_Function_glGetDebugMessageLogKHR; - static const Function glPushDebugGroupKHR = GLMessage_Function_glPushDebugGroupKHR; - static const Function glPopDebugGroupKHR = GLMessage_Function_glPopDebugGroupKHR; - static const Function glObjectLabelKHR = GLMessage_Function_glObjectLabelKHR; - static const Function glGetObjectLabelKHR = GLMessage_Function_glGetObjectLabelKHR; - static const Function glObjectPtrLabelKHR = GLMessage_Function_glObjectPtrLabelKHR; - static const Function glGetObjectPtrLabelKHR = GLMessage_Function_glGetObjectPtrLabelKHR; - static const Function glGetPointervKHR = GLMessage_Function_glGetPointervKHR; - static const Function glDrawArraysInstancedANGLE = GLMessage_Function_glDrawArraysInstancedANGLE; - static const Function glDrawElementsInstancedANGLE = GLMessage_Function_glDrawElementsInstancedANGLE; - static const Function glVertexAttribDivisorANGLE = GLMessage_Function_glVertexAttribDivisorANGLE; - static const Function glDrawArraysInstancedEXT = GLMessage_Function_glDrawArraysInstancedEXT; - static const Function glDrawElementsInstancedEXT = GLMessage_Function_glDrawElementsInstancedEXT; - static const Function glVertexAttribDivisorEXT = GLMessage_Function_glVertexAttribDivisorEXT; - static const Function glDrawArraysInstancedNV = GLMessage_Function_glDrawArraysInstancedNV; - static const Function glDrawElementsInstancedNV = GLMessage_Function_glDrawElementsInstancedNV; - static const Function glVertexAttribDivisorNV = GLMessage_Function_glVertexAttribDivisorNV; - static const Function glDrawBuffersEXT = GLMessage_Function_glDrawBuffersEXT; - static const Function glReadBufferIndexedEXT = GLMessage_Function_glReadBufferIndexedEXT; - static const Function glDrawBuffersIndexedEXT = GLMessage_Function_glDrawBuffersIndexedEXT; - static const Function glGetIntegeri_vEXT = GLMessage_Function_glGetIntegeri_vEXT; - static const Function glMapBufferRangeEXT = GLMessage_Function_glMapBufferRangeEXT; - static const Function glFlushMappedBufferRangeEXT = GLMessage_Function_glFlushMappedBufferRangeEXT; - static const Function glQueryCounterEXT = GLMessage_Function_glQueryCounterEXT; - static const Function glGetQueryObjecti64vEXT = GLMessage_Function_glGetQueryObjecti64vEXT; - static const Function glGetQueryObjectivEXT = GLMessage_Function_glGetQueryObjectivEXT; - static const Function glGetQueryObjectui64vEXT = GLMessage_Function_glGetQueryObjectui64vEXT; - static const Function glGetTranslatedShaderSourceANGLE = GLMessage_Function_glGetTranslatedShaderSourceANGLE; - static const Function glMinSampleShadingOES = GLMessage_Function_glMinSampleShadingOES; - static const Function glMultiTexCoord1bOES = GLMessage_Function_glMultiTexCoord1bOES; - static const Function glMultiTexCoord1bvOES = GLMessage_Function_glMultiTexCoord1bvOES; - static const Function glMultiTexCoord2bOES = GLMessage_Function_glMultiTexCoord2bOES; - static const Function glMultiTexCoord2bvOES = GLMessage_Function_glMultiTexCoord2bvOES; - static const Function glMultiTexCoord3bOES = GLMessage_Function_glMultiTexCoord3bOES; - static const Function glMultiTexCoord3bvOES = GLMessage_Function_glMultiTexCoord3bvOES; - static const Function glMultiTexCoord4bOES = GLMessage_Function_glMultiTexCoord4bOES; - static const Function glMultiTexCoord4bvOES = GLMessage_Function_glMultiTexCoord4bvOES; - static const Function glTexCoord1bOES = GLMessage_Function_glTexCoord1bOES; - static const Function glTexCoord1bvOES = GLMessage_Function_glTexCoord1bvOES; - static const Function glTexCoord2bOES = GLMessage_Function_glTexCoord2bOES; - static const Function glTexCoord2bvOES = GLMessage_Function_glTexCoord2bvOES; - static const Function glTexCoord3bOES = GLMessage_Function_glTexCoord3bOES; - static const Function glTexCoord3bvOES = GLMessage_Function_glTexCoord3bvOES; - static const Function glTexCoord4bOES = GLMessage_Function_glTexCoord4bOES; - static const Function glTexCoord4bvOES = GLMessage_Function_glTexCoord4bvOES; - static const Function glVertex2bOES = GLMessage_Function_glVertex2bOES; - static const Function glVertex2bvOES = GLMessage_Function_glVertex2bvOES; - static const Function glVertex3bOES = GLMessage_Function_glVertex3bOES; - static const Function glVertex3bvOES = GLMessage_Function_glVertex3bvOES; - static const Function glVertex4bOES = GLMessage_Function_glVertex4bOES; - static const Function glVertex4bvOES = GLMessage_Function_glVertex4bvOES; - static const Function glProgramUniform1uiEXT = GLMessage_Function_glProgramUniform1uiEXT; - static const Function glProgramUniform2uiEXT = GLMessage_Function_glProgramUniform2uiEXT; - static const Function glProgramUniform3uiEXT = GLMessage_Function_glProgramUniform3uiEXT; - static const Function glProgramUniform4uiEXT = GLMessage_Function_glProgramUniform4uiEXT; - static const Function glProgramUniform1uivEXT = GLMessage_Function_glProgramUniform1uivEXT; - static const Function glProgramUniform2uivEXT = GLMessage_Function_glProgramUniform2uivEXT; - static const Function glProgramUniform3uivEXT = GLMessage_Function_glProgramUniform3uivEXT; - static const Function glProgramUniform4uivEXT = GLMessage_Function_glProgramUniform4uivEXT; - static const Function glProgramUniformMatrix2x3fvEXT = GLMessage_Function_glProgramUniformMatrix2x3fvEXT; - static const Function glProgramUniformMatrix3x2fvEXT = GLMessage_Function_glProgramUniformMatrix3x2fvEXT; - static const Function glProgramUniformMatrix2x4fvEXT = GLMessage_Function_glProgramUniformMatrix2x4fvEXT; - static const Function glProgramUniformMatrix4x2fvEXT = GLMessage_Function_glProgramUniformMatrix4x2fvEXT; - static const Function glProgramUniformMatrix3x4fvEXT = GLMessage_Function_glProgramUniformMatrix3x4fvEXT; - static const Function glProgramUniformMatrix4x3fvEXT = GLMessage_Function_glProgramUniformMatrix4x3fvEXT; - static const Function glRenderbufferStorageMultisampleNV = GLMessage_Function_glRenderbufferStorageMultisampleNV; - static const Function glSampleCoverageOES = GLMessage_Function_glSampleCoverageOES; - static const Function glTexStorage3DMultisampleOES = GLMessage_Function_glTexStorage3DMultisampleOES; - static const Function glUniformMatrix2x3fvNV = GLMessage_Function_glUniformMatrix2x3fvNV; - static const Function glUniformMatrix3x2fvNV = GLMessage_Function_glUniformMatrix3x2fvNV; - static const Function glUniformMatrix2x4fvNV = GLMessage_Function_glUniformMatrix2x4fvNV; - static const Function glUniformMatrix4x2fvNV = GLMessage_Function_glUniformMatrix4x2fvNV; - static const Function glUniformMatrix3x4fvNV = GLMessage_Function_glUniformMatrix3x4fvNV; - static const Function glUniformMatrix4x3fvNV = GLMessage_Function_glUniformMatrix4x3fvNV; - static const Function glActiveShaderProgram = GLMessage_Function_glActiveShaderProgram; - static const Function glBindImageTexture = GLMessage_Function_glBindImageTexture; - static const Function glBindProgramPipeline = GLMessage_Function_glBindProgramPipeline; - static const Function glBindVertexBuffer = GLMessage_Function_glBindVertexBuffer; - static const Function glCreateShaderProgramv = GLMessage_Function_glCreateShaderProgramv; - static const Function glDeleteProgramPipelines = GLMessage_Function_glDeleteProgramPipelines; - static const Function glDispatchCompute = GLMessage_Function_glDispatchCompute; - static const Function glDispatchComputeIndirect = GLMessage_Function_glDispatchComputeIndirect; - static const Function glDrawArraysIndirect = GLMessage_Function_glDrawArraysIndirect; - static const Function glDrawElementsIndirect = GLMessage_Function_glDrawElementsIndirect; - static const Function glFramebufferParameteri = GLMessage_Function_glFramebufferParameteri; - static const Function glGenProgramPipelines = GLMessage_Function_glGenProgramPipelines; - static const Function glGetBooleani_v = GLMessage_Function_glGetBooleani_v; - static const Function glGetFramebufferParameteriv = GLMessage_Function_glGetFramebufferParameteriv; - static const Function glGetMultisamplefv = GLMessage_Function_glGetMultisamplefv; - static const Function glGetProgramInterfaceiv = GLMessage_Function_glGetProgramInterfaceiv; - static const Function glGetProgramPipelineInfoLog = GLMessage_Function_glGetProgramPipelineInfoLog; - static const Function glGetProgramPipelineiv = GLMessage_Function_glGetProgramPipelineiv; - static const Function glGetProgramResourceIndex = GLMessage_Function_glGetProgramResourceIndex; - static const Function glGetProgramResourceLocation = GLMessage_Function_glGetProgramResourceLocation; - static const Function glGetProgramResourceName = GLMessage_Function_glGetProgramResourceName; - static const Function glGetProgramResourceiv = GLMessage_Function_glGetProgramResourceiv; - static const Function glGetTexLevelParameterfv = GLMessage_Function_glGetTexLevelParameterfv; - static const Function glGetTexLevelParameteriv = GLMessage_Function_glGetTexLevelParameteriv; - static const Function glIsProgramPipeline = GLMessage_Function_glIsProgramPipeline; - static const Function glMemoryBarrier = GLMessage_Function_glMemoryBarrier; - static const Function glMemoryBarrierByRegion = GLMessage_Function_glMemoryBarrierByRegion; - static const Function glProgramUniform1f = GLMessage_Function_glProgramUniform1f; - static const Function glProgramUniform1fv = GLMessage_Function_glProgramUniform1fv; - static const Function glProgramUniform1i = GLMessage_Function_glProgramUniform1i; - static const Function glProgramUniform1iv = GLMessage_Function_glProgramUniform1iv; - static const Function glProgramUniform1ui = GLMessage_Function_glProgramUniform1ui; - static const Function glProgramUniform1uiv = GLMessage_Function_glProgramUniform1uiv; - static const Function glProgramUniform2f = GLMessage_Function_glProgramUniform2f; - static const Function glProgramUniform2fv = GLMessage_Function_glProgramUniform2fv; - static const Function glProgramUniform2i = GLMessage_Function_glProgramUniform2i; - static const Function glProgramUniform2iv = GLMessage_Function_glProgramUniform2iv; - static const Function glProgramUniform2ui = GLMessage_Function_glProgramUniform2ui; - static const Function glProgramUniform2uiv = GLMessage_Function_glProgramUniform2uiv; - static const Function glProgramUniform3f = GLMessage_Function_glProgramUniform3f; - static const Function glProgramUniform3fv = GLMessage_Function_glProgramUniform3fv; - static const Function glProgramUniform3i = GLMessage_Function_glProgramUniform3i; - static const Function glProgramUniform3iv = GLMessage_Function_glProgramUniform3iv; - static const Function glProgramUniform3ui = GLMessage_Function_glProgramUniform3ui; - static const Function glProgramUniform3uiv = GLMessage_Function_glProgramUniform3uiv; - static const Function glProgramUniform4f = GLMessage_Function_glProgramUniform4f; - static const Function glProgramUniform4fv = GLMessage_Function_glProgramUniform4fv; - static const Function glProgramUniform4i = GLMessage_Function_glProgramUniform4i; - static const Function glProgramUniform4iv = GLMessage_Function_glProgramUniform4iv; - static const Function glProgramUniform4ui = GLMessage_Function_glProgramUniform4ui; - static const Function glProgramUniform4uiv = GLMessage_Function_glProgramUniform4uiv; - static const Function glProgramUniformMatrix2fv = GLMessage_Function_glProgramUniformMatrix2fv; - static const Function glProgramUniformMatrix2x3fv = GLMessage_Function_glProgramUniformMatrix2x3fv; - static const Function glProgramUniformMatrix2x4fv = GLMessage_Function_glProgramUniformMatrix2x4fv; - static const Function glProgramUniformMatrix3fv = GLMessage_Function_glProgramUniformMatrix3fv; - static const Function glProgramUniformMatrix3x2fv = GLMessage_Function_glProgramUniformMatrix3x2fv; - static const Function glProgramUniformMatrix3x4fv = GLMessage_Function_glProgramUniformMatrix3x4fv; - static const Function glProgramUniformMatrix4fv = GLMessage_Function_glProgramUniformMatrix4fv; - static const Function glProgramUniformMatrix4x2fv = GLMessage_Function_glProgramUniformMatrix4x2fv; - static const Function glProgramUniformMatrix4x3fv = GLMessage_Function_glProgramUniformMatrix4x3fv; - static const Function glSampleMaski = GLMessage_Function_glSampleMaski; - static const Function glTexStorage2DMultisample = GLMessage_Function_glTexStorage2DMultisample; - static const Function glUseProgramStages = GLMessage_Function_glUseProgramStages; - static const Function glValidateProgramPipeline = GLMessage_Function_glValidateProgramPipeline; - static const Function glVertexAttribBinding = GLMessage_Function_glVertexAttribBinding; - static const Function glVertexAttribFormat = GLMessage_Function_glVertexAttribFormat; - static const Function glVertexAttribIFormat = GLMessage_Function_glVertexAttribIFormat; - static const Function glVertexBindingDivisor = GLMessage_Function_glVertexBindingDivisor; - static const Function glBlendEquationSeparateiEXT = GLMessage_Function_glBlendEquationSeparateiEXT; - static const Function glBlendEquationiEXT = GLMessage_Function_glBlendEquationiEXT; - static const Function glBlendFuncSeparateiEXT = GLMessage_Function_glBlendFuncSeparateiEXT; - static const Function glBlendFunciEXT = GLMessage_Function_glBlendFunciEXT; - static const Function glColorMaskiEXT = GLMessage_Function_glColorMaskiEXT; - static const Function glCopyImageSubDataEXT = GLMessage_Function_glCopyImageSubDataEXT; - static const Function glDisableiEXT = GLMessage_Function_glDisableiEXT; - static const Function glEnableiEXT = GLMessage_Function_glEnableiEXT; - static const Function glFramebufferTextureEXT = GLMessage_Function_glFramebufferTextureEXT; - static const Function glGetSamplerParameterIivEXT = GLMessage_Function_glGetSamplerParameterIivEXT; - static const Function glGetSamplerParameterIuivEXT = GLMessage_Function_glGetSamplerParameterIuivEXT; - static const Function glGetTexParameterIivEXT = GLMessage_Function_glGetTexParameterIivEXT; - static const Function glGetTexParameterIuivEXT = GLMessage_Function_glGetTexParameterIuivEXT; - static const Function glIsEnablediEXT = GLMessage_Function_glIsEnablediEXT; - static const Function glPatchParameteriEXT = GLMessage_Function_glPatchParameteriEXT; - static const Function glPrimitiveBoundingBoxEXT = GLMessage_Function_glPrimitiveBoundingBoxEXT; - static const Function glSamplerParameterIivEXT = GLMessage_Function_glSamplerParameterIivEXT; - static const Function glSamplerParameterIuivEXT = GLMessage_Function_glSamplerParameterIuivEXT; - static const Function glTexBufferEXT = GLMessage_Function_glTexBufferEXT; - static const Function glTexBufferRangeEXT = GLMessage_Function_glTexBufferRangeEXT; - static const Function glTexParameterIivEXT = GLMessage_Function_glTexParameterIivEXT; - static const Function glTexParameterIuivEXT = GLMessage_Function_glTexParameterIuivEXT; - static const Function glTextureViewEXT = GLMessage_Function_glTextureViewEXT; - static const Function eglGetDisplay = GLMessage_Function_eglGetDisplay; - static const Function eglInitialize = GLMessage_Function_eglInitialize; - static const Function eglTerminate = GLMessage_Function_eglTerminate; - static const Function eglGetConfigs = GLMessage_Function_eglGetConfigs; - static const Function eglChooseConfig = GLMessage_Function_eglChooseConfig; - static const Function eglGetConfigAttrib = GLMessage_Function_eglGetConfigAttrib; - static const Function eglCreateWindowSurface = GLMessage_Function_eglCreateWindowSurface; - static const Function eglCreatePixmapSurface = GLMessage_Function_eglCreatePixmapSurface; - static const Function eglCreatePbufferSurface = GLMessage_Function_eglCreatePbufferSurface; - static const Function eglDestroySurface = GLMessage_Function_eglDestroySurface; - static const Function eglQuerySurface = GLMessage_Function_eglQuerySurface; - static const Function eglCreateContext = GLMessage_Function_eglCreateContext; - static const Function eglDestroyContext = GLMessage_Function_eglDestroyContext; - static const Function eglMakeCurrent = GLMessage_Function_eglMakeCurrent; - static const Function eglGetCurrentContext = GLMessage_Function_eglGetCurrentContext; - static const Function eglGetCurrentSurface = GLMessage_Function_eglGetCurrentSurface; - static const Function eglGetCurrentDisplay = GLMessage_Function_eglGetCurrentDisplay; - static const Function eglQueryContext = GLMessage_Function_eglQueryContext; - static const Function eglWaitGL = GLMessage_Function_eglWaitGL; - static const Function eglWaitNative = GLMessage_Function_eglWaitNative; - static const Function eglSwapBuffers = GLMessage_Function_eglSwapBuffers; - static const Function eglCopyBuffers = GLMessage_Function_eglCopyBuffers; - static const Function eglGetError = GLMessage_Function_eglGetError; - static const Function eglQueryString = GLMessage_Function_eglQueryString; - static const Function eglGetProcAddress = GLMessage_Function_eglGetProcAddress; - static const Function eglSurfaceAttrib = GLMessage_Function_eglSurfaceAttrib; - static const Function eglBindTexImage = GLMessage_Function_eglBindTexImage; - static const Function eglReleaseTexImage = GLMessage_Function_eglReleaseTexImage; - static const Function eglSwapInterval = GLMessage_Function_eglSwapInterval; - static const Function eglBindAPI = GLMessage_Function_eglBindAPI; - static const Function eglQueryAPI = GLMessage_Function_eglQueryAPI; - static const Function eglWaitClient = GLMessage_Function_eglWaitClient; - static const Function eglReleaseThread = GLMessage_Function_eglReleaseThread; - static const Function eglCreatePbufferFromClientBuffer = GLMessage_Function_eglCreatePbufferFromClientBuffer; - static const Function eglLockSurfaceKHR = GLMessage_Function_eglLockSurfaceKHR; - static const Function eglUnlockSurfaceKHR = GLMessage_Function_eglUnlockSurfaceKHR; - static const Function eglCreateImageKHR = GLMessage_Function_eglCreateImageKHR; - static const Function eglDestroyImageKHR = GLMessage_Function_eglDestroyImageKHR; - static const Function eglCreateSyncKHR = GLMessage_Function_eglCreateSyncKHR; - static const Function eglDestroySyncKHR = GLMessage_Function_eglDestroySyncKHR; - static const Function eglClientWaitSyncKHR = GLMessage_Function_eglClientWaitSyncKHR; - static const Function eglGetSyncAttribKHR = GLMessage_Function_eglGetSyncAttribKHR; - static const Function eglSetSwapRectangleANDROID = GLMessage_Function_eglSetSwapRectangleANDROID; - static const Function eglGetRenderBufferANDROID = GLMessage_Function_eglGetRenderBufferANDROID; - static const Function eglGetSystemTimeFrequencyNV = GLMessage_Function_eglGetSystemTimeFrequencyNV; - static const Function eglGetSystemTimeNV = GLMessage_Function_eglGetSystemTimeNV; - static const Function invalid = GLMessage_Function_invalid; - static const Function glVertexAttribPointerData = GLMessage_Function_glVertexAttribPointerData; - static inline bool Function_IsValid(int value) { - return GLMessage_Function_IsValid(value); - } - static const Function Function_MIN = - GLMessage_Function_Function_MIN; - static const Function Function_MAX = - GLMessage_Function_Function_MAX; - static const int Function_ARRAYSIZE = - GLMessage_Function_Function_ARRAYSIZE; - - // accessors ------------------------------------------------------- - - // required int32 context_id = 1; - inline bool has_context_id() const; - inline void clear_context_id(); - static const int kContextIdFieldNumber = 1; - inline ::google::protobuf::int32 context_id() const; - inline void set_context_id(::google::protobuf::int32 value); - - // required int64 start_time = 2; - inline bool has_start_time() const; - inline void clear_start_time(); - static const int kStartTimeFieldNumber = 2; - inline ::google::protobuf::int64 start_time() const; - inline void set_start_time(::google::protobuf::int64 value); - - // required int32 duration = 3; - inline bool has_duration() const; - inline void clear_duration(); - static const int kDurationFieldNumber = 3; - inline ::google::protobuf::int32 duration() const; - inline void set_duration(::google::protobuf::int32 value); - - // required .android.gltrace.GLMessage.Function function = 4 [default = invalid]; - inline bool has_function() const; - inline void clear_function(); - static const int kFunctionFieldNumber = 4; - inline ::android::gltrace::GLMessage_Function function() const; - inline void set_function(::android::gltrace::GLMessage_Function value); - - // repeated .android.gltrace.GLMessage.DataType args = 5; - inline int args_size() const; - inline void clear_args(); - static const int kArgsFieldNumber = 5; - inline const ::android::gltrace::GLMessage_DataType& args(int index) const; - inline ::android::gltrace::GLMessage_DataType* mutable_args(int index); - inline ::android::gltrace::GLMessage_DataType* add_args(); - inline const ::google::protobuf::RepeatedPtrField< ::android::gltrace::GLMessage_DataType >& - args() const; - inline ::google::protobuf::RepeatedPtrField< ::android::gltrace::GLMessage_DataType >* - mutable_args(); - - // optional .android.gltrace.GLMessage.DataType returnValue = 6; - inline bool has_returnvalue() const; - inline void clear_returnvalue(); - static const int kReturnValueFieldNumber = 6; - inline const ::android::gltrace::GLMessage_DataType& returnvalue() const; - inline ::android::gltrace::GLMessage_DataType* mutable_returnvalue(); - - // optional .android.gltrace.GLMessage.FrameBuffer fb = 7; - inline bool has_fb() const; - inline void clear_fb(); - static const int kFbFieldNumber = 7; - inline const ::android::gltrace::GLMessage_FrameBuffer& fb() const; - inline ::android::gltrace::GLMessage_FrameBuffer* mutable_fb(); - - // optional int32 threadtime = 8; - inline bool has_threadtime() const; - inline void clear_threadtime(); - static const int kThreadtimeFieldNumber = 8; - inline ::google::protobuf::int32 threadtime() const; - inline void set_threadtime(::google::protobuf::int32 value); - - // @@protoc_insertion_point(class_scope:android.gltrace.GLMessage) - private: - mutable int _cached_size_; - - ::google::protobuf::int32 context_id_; - ::google::protobuf::int64 start_time_; - ::google::protobuf::int32 duration_; - int function_; - ::google::protobuf::RepeatedPtrField< ::android::gltrace::GLMessage_DataType > args_; - ::android::gltrace::GLMessage_DataType* returnvalue_; - ::android::gltrace::GLMessage_FrameBuffer* fb_; - ::google::protobuf::int32 threadtime_; - friend void protobuf_AddDesc_gltrace_2eproto(); - friend void protobuf_AssignDesc_gltrace_2eproto(); - friend void protobuf_ShutdownFile_gltrace_2eproto(); - - ::google::protobuf::uint32 _has_bits_[(8 + 31) / 32]; - - // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? - inline bool _has_bit(int index) const { - return (_has_bits_[index / 32] & (1u << (index % 32))) != 0; - } - inline void _set_bit(int index) { - _has_bits_[index / 32] |= (1u << (index % 32)); - } - inline void _clear_bit(int index) { - _has_bits_[index / 32] &= ~(1u << (index % 32)); - } - - void InitAsDefaultInstance(); - static GLMessage* default_instance_; -}; -// =================================================================== - - -// =================================================================== - -// GLMessage_DataType - -// required .android.gltrace.GLMessage.DataType.Type type = 1 [default = VOID]; -inline bool GLMessage_DataType::has_type() const { - return _has_bit(0); -} -inline void GLMessage_DataType::clear_type() { - type_ = 1; - _clear_bit(0); -} -inline ::android::gltrace::GLMessage_DataType_Type GLMessage_DataType::type() const { - return static_cast< ::android::gltrace::GLMessage_DataType_Type >(type_); -} -inline void GLMessage_DataType::set_type(::android::gltrace::GLMessage_DataType_Type value) { - GOOGLE_DCHECK(::android::gltrace::GLMessage_DataType_Type_IsValid(value)); - _set_bit(0); - type_ = value; -} - -// required bool isArray = 2 [default = false]; -inline bool GLMessage_DataType::has_isarray() const { - return _has_bit(1); -} -inline void GLMessage_DataType::clear_isarray() { - isarray_ = false; - _clear_bit(1); -} -inline bool GLMessage_DataType::isarray() const { - return isarray_; -} -inline void GLMessage_DataType::set_isarray(bool value) { - _set_bit(1); - isarray_ = value; -} - -// repeated int32 intValue = 3; -inline int GLMessage_DataType::intvalue_size() const { - return intvalue_.size(); -} -inline void GLMessage_DataType::clear_intvalue() { - intvalue_.Clear(); -} -inline ::google::protobuf::int32 GLMessage_DataType::intvalue(int index) const { - return intvalue_.Get(index); -} -inline void GLMessage_DataType::set_intvalue(int index, ::google::protobuf::int32 value) { - intvalue_.Set(index, value); -} -inline void GLMessage_DataType::add_intvalue(::google::protobuf::int32 value) { - intvalue_.Add(value); -} -inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >& -GLMessage_DataType::intvalue() const { - return intvalue_; -} -inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >* -GLMessage_DataType::mutable_intvalue() { - return &intvalue_; -} - -// repeated float floatValue = 4; -inline int GLMessage_DataType::floatvalue_size() const { - return floatvalue_.size(); -} -inline void GLMessage_DataType::clear_floatvalue() { - floatvalue_.Clear(); -} -inline float GLMessage_DataType::floatvalue(int index) const { - return floatvalue_.Get(index); -} -inline void GLMessage_DataType::set_floatvalue(int index, float value) { - floatvalue_.Set(index, value); -} -inline void GLMessage_DataType::add_floatvalue(float value) { - floatvalue_.Add(value); -} -inline const ::google::protobuf::RepeatedField< float >& -GLMessage_DataType::floatvalue() const { - return floatvalue_; -} -inline ::google::protobuf::RepeatedField< float >* -GLMessage_DataType::mutable_floatvalue() { - return &floatvalue_; -} - -// repeated bytes charValue = 5; -inline int GLMessage_DataType::charvalue_size() const { - return charvalue_.size(); -} -inline void GLMessage_DataType::clear_charvalue() { - charvalue_.Clear(); -} -inline const ::std::string& GLMessage_DataType::charvalue(int index) const { - return charvalue_.Get(index); -} -inline ::std::string* GLMessage_DataType::mutable_charvalue(int index) { - return charvalue_.Mutable(index); -} -inline void GLMessage_DataType::set_charvalue(int index, const ::std::string& value) { - charvalue_.Mutable(index)->assign(value); -} -inline void GLMessage_DataType::set_charvalue(int index, const char* value) { - charvalue_.Mutable(index)->assign(value); -} -inline void GLMessage_DataType::set_charvalue(int index, const void* value, size_t size) { - charvalue_.Mutable(index)->assign( - reinterpret_cast<const char*>(value), size); -} -inline ::std::string* GLMessage_DataType::add_charvalue() { - return charvalue_.Add(); -} -inline void GLMessage_DataType::add_charvalue(const ::std::string& value) { - charvalue_.Add()->assign(value); -} -inline void GLMessage_DataType::add_charvalue(const char* value) { - charvalue_.Add()->assign(value); -} -inline void GLMessage_DataType::add_charvalue(const void* value, size_t size) { - charvalue_.Add()->assign(reinterpret_cast<const char*>(value), size); -} -inline const ::google::protobuf::RepeatedPtrField< ::std::string>& -GLMessage_DataType::charvalue() const { - return charvalue_; -} -inline ::google::protobuf::RepeatedPtrField< ::std::string>* -GLMessage_DataType::mutable_charvalue() { - return &charvalue_; -} - -// repeated bytes rawBytes = 6; -inline int GLMessage_DataType::rawbytes_size() const { - return rawbytes_.size(); -} -inline void GLMessage_DataType::clear_rawbytes() { - rawbytes_.Clear(); -} -inline const ::std::string& GLMessage_DataType::rawbytes(int index) const { - return rawbytes_.Get(index); -} -inline ::std::string* GLMessage_DataType::mutable_rawbytes(int index) { - return rawbytes_.Mutable(index); -} -inline void GLMessage_DataType::set_rawbytes(int index, const ::std::string& value) { - rawbytes_.Mutable(index)->assign(value); -} -inline void GLMessage_DataType::set_rawbytes(int index, const char* value) { - rawbytes_.Mutable(index)->assign(value); -} -inline void GLMessage_DataType::set_rawbytes(int index, const void* value, size_t size) { - rawbytes_.Mutable(index)->assign( - reinterpret_cast<const char*>(value), size); -} -inline ::std::string* GLMessage_DataType::add_rawbytes() { - return rawbytes_.Add(); -} -inline void GLMessage_DataType::add_rawbytes(const ::std::string& value) { - rawbytes_.Add()->assign(value); -} -inline void GLMessage_DataType::add_rawbytes(const char* value) { - rawbytes_.Add()->assign(value); -} -inline void GLMessage_DataType::add_rawbytes(const void* value, size_t size) { - rawbytes_.Add()->assign(reinterpret_cast<const char*>(value), size); -} -inline const ::google::protobuf::RepeatedPtrField< ::std::string>& -GLMessage_DataType::rawbytes() const { - return rawbytes_; -} -inline ::google::protobuf::RepeatedPtrField< ::std::string>* -GLMessage_DataType::mutable_rawbytes() { - return &rawbytes_; -} - -// repeated bool boolValue = 7; -inline int GLMessage_DataType::boolvalue_size() const { - return boolvalue_.size(); -} -inline void GLMessage_DataType::clear_boolvalue() { - boolvalue_.Clear(); -} -inline bool GLMessage_DataType::boolvalue(int index) const { - return boolvalue_.Get(index); -} -inline void GLMessage_DataType::set_boolvalue(int index, bool value) { - boolvalue_.Set(index, value); -} -inline void GLMessage_DataType::add_boolvalue(bool value) { - boolvalue_.Add(value); -} -inline const ::google::protobuf::RepeatedField< bool >& -GLMessage_DataType::boolvalue() const { - return boolvalue_; -} -inline ::google::protobuf::RepeatedField< bool >* -GLMessage_DataType::mutable_boolvalue() { - return &boolvalue_; -} - -// repeated int64 int64Value = 8; -inline int GLMessage_DataType::int64value_size() const { - return int64value_.size(); -} -inline void GLMessage_DataType::clear_int64value() { - int64value_.Clear(); -} -inline ::google::protobuf::int64 GLMessage_DataType::int64value(int index) const { - return int64value_.Get(index); -} -inline void GLMessage_DataType::set_int64value(int index, ::google::protobuf::int64 value) { - int64value_.Set(index, value); -} -inline void GLMessage_DataType::add_int64value(::google::protobuf::int64 value) { - int64value_.Add(value); -} -inline const ::google::protobuf::RepeatedField< ::google::protobuf::int64 >& -GLMessage_DataType::int64value() const { - return int64value_; -} -inline ::google::protobuf::RepeatedField< ::google::protobuf::int64 >* -GLMessage_DataType::mutable_int64value() { - return &int64value_; -} - -// ------------------------------------------------------------------- - -// GLMessage_FrameBuffer - -// required int32 width = 1; -inline bool GLMessage_FrameBuffer::has_width() const { - return _has_bit(0); -} -inline void GLMessage_FrameBuffer::clear_width() { - width_ = 0; - _clear_bit(0); -} -inline ::google::protobuf::int32 GLMessage_FrameBuffer::width() const { - return width_; -} -inline void GLMessage_FrameBuffer::set_width(::google::protobuf::int32 value) { - _set_bit(0); - width_ = value; -} - -// required int32 height = 2; -inline bool GLMessage_FrameBuffer::has_height() const { - return _has_bit(1); -} -inline void GLMessage_FrameBuffer::clear_height() { - height_ = 0; - _clear_bit(1); -} -inline ::google::protobuf::int32 GLMessage_FrameBuffer::height() const { - return height_; -} -inline void GLMessage_FrameBuffer::set_height(::google::protobuf::int32 value) { - _set_bit(1); - height_ = value; -} - -// repeated bytes contents = 3; -inline int GLMessage_FrameBuffer::contents_size() const { - return contents_.size(); -} -inline void GLMessage_FrameBuffer::clear_contents() { - contents_.Clear(); -} -inline const ::std::string& GLMessage_FrameBuffer::contents(int index) const { - return contents_.Get(index); -} -inline ::std::string* GLMessage_FrameBuffer::mutable_contents(int index) { - return contents_.Mutable(index); -} -inline void GLMessage_FrameBuffer::set_contents(int index, const ::std::string& value) { - contents_.Mutable(index)->assign(value); -} -inline void GLMessage_FrameBuffer::set_contents(int index, const char* value) { - contents_.Mutable(index)->assign(value); -} -inline void GLMessage_FrameBuffer::set_contents(int index, const void* value, size_t size) { - contents_.Mutable(index)->assign( - reinterpret_cast<const char*>(value), size); -} -inline ::std::string* GLMessage_FrameBuffer::add_contents() { - return contents_.Add(); -} -inline void GLMessage_FrameBuffer::add_contents(const ::std::string& value) { - contents_.Add()->assign(value); -} -inline void GLMessage_FrameBuffer::add_contents(const char* value) { - contents_.Add()->assign(value); -} -inline void GLMessage_FrameBuffer::add_contents(const void* value, size_t size) { - contents_.Add()->assign(reinterpret_cast<const char*>(value), size); -} -inline const ::google::protobuf::RepeatedPtrField< ::std::string>& -GLMessage_FrameBuffer::contents() const { - return contents_; -} -inline ::google::protobuf::RepeatedPtrField< ::std::string>* -GLMessage_FrameBuffer::mutable_contents() { - return &contents_; -} - -// ------------------------------------------------------------------- - -// GLMessage - -// required int32 context_id = 1; -inline bool GLMessage::has_context_id() const { - return _has_bit(0); -} -inline void GLMessage::clear_context_id() { - context_id_ = 0; - _clear_bit(0); -} -inline ::google::protobuf::int32 GLMessage::context_id() const { - return context_id_; -} -inline void GLMessage::set_context_id(::google::protobuf::int32 value) { - _set_bit(0); - context_id_ = value; -} - -// required int64 start_time = 2; -inline bool GLMessage::has_start_time() const { - return _has_bit(1); -} -inline void GLMessage::clear_start_time() { - start_time_ = GOOGLE_LONGLONG(0); - _clear_bit(1); -} -inline ::google::protobuf::int64 GLMessage::start_time() const { - return start_time_; -} -inline void GLMessage::set_start_time(::google::protobuf::int64 value) { - _set_bit(1); - start_time_ = value; -} - -// required int32 duration = 3; -inline bool GLMessage::has_duration() const { - return _has_bit(2); -} -inline void GLMessage::clear_duration() { - duration_ = 0; - _clear_bit(2); -} -inline ::google::protobuf::int32 GLMessage::duration() const { - return duration_; -} -inline void GLMessage::set_duration(::google::protobuf::int32 value) { - _set_bit(2); - duration_ = value; -} - -// required .android.gltrace.GLMessage.Function function = 4 [default = invalid]; -inline bool GLMessage::has_function() const { - return _has_bit(3); -} -inline void GLMessage::clear_function() { - function_ = 3000; - _clear_bit(3); -} -inline ::android::gltrace::GLMessage_Function GLMessage::function() const { - return static_cast< ::android::gltrace::GLMessage_Function >(function_); -} -inline void GLMessage::set_function(::android::gltrace::GLMessage_Function value) { - GOOGLE_DCHECK(::android::gltrace::GLMessage_Function_IsValid(value)); - _set_bit(3); - function_ = value; -} - -// repeated .android.gltrace.GLMessage.DataType args = 5; -inline int GLMessage::args_size() const { - return args_.size(); -} -inline void GLMessage::clear_args() { - args_.Clear(); -} -inline const ::android::gltrace::GLMessage_DataType& GLMessage::args(int index) const { - return args_.Get(index); -} -inline ::android::gltrace::GLMessage_DataType* GLMessage::mutable_args(int index) { - return args_.Mutable(index); -} -inline ::android::gltrace::GLMessage_DataType* GLMessage::add_args() { - return args_.Add(); -} -inline const ::google::protobuf::RepeatedPtrField< ::android::gltrace::GLMessage_DataType >& -GLMessage::args() const { - return args_; -} -inline ::google::protobuf::RepeatedPtrField< ::android::gltrace::GLMessage_DataType >* -GLMessage::mutable_args() { - return &args_; -} - -// optional .android.gltrace.GLMessage.DataType returnValue = 6; -inline bool GLMessage::has_returnvalue() const { - return _has_bit(5); -} -inline void GLMessage::clear_returnvalue() { - if (returnvalue_ != NULL) returnvalue_->::android::gltrace::GLMessage_DataType::Clear(); - _clear_bit(5); -} -inline const ::android::gltrace::GLMessage_DataType& GLMessage::returnvalue() const { - return returnvalue_ != NULL ? *returnvalue_ : *default_instance_->returnvalue_; -} -inline ::android::gltrace::GLMessage_DataType* GLMessage::mutable_returnvalue() { - _set_bit(5); - if (returnvalue_ == NULL) returnvalue_ = new ::android::gltrace::GLMessage_DataType; - return returnvalue_; -} - -// optional .android.gltrace.GLMessage.FrameBuffer fb = 7; -inline bool GLMessage::has_fb() const { - return _has_bit(6); -} -inline void GLMessage::clear_fb() { - if (fb_ != NULL) fb_->::android::gltrace::GLMessage_FrameBuffer::Clear(); - _clear_bit(6); -} -inline const ::android::gltrace::GLMessage_FrameBuffer& GLMessage::fb() const { - return fb_ != NULL ? *fb_ : *default_instance_->fb_; -} -inline ::android::gltrace::GLMessage_FrameBuffer* GLMessage::mutable_fb() { - _set_bit(6); - if (fb_ == NULL) fb_ = new ::android::gltrace::GLMessage_FrameBuffer; - return fb_; -} - -// optional int32 threadtime = 8; -inline bool GLMessage::has_threadtime() const { - return _has_bit(7); -} -inline void GLMessage::clear_threadtime() { - threadtime_ = 0; - _clear_bit(7); -} -inline ::google::protobuf::int32 GLMessage::threadtime() const { - return threadtime_; -} -inline void GLMessage::set_threadtime(::google::protobuf::int32 value) { - _set_bit(7); - threadtime_ = value; -} - - -// @@protoc_insertion_point(namespace_scope) - -} // namespace gltrace -} // namespace android - -// @@protoc_insertion_point(global_scope) - -#endif // PROTOBUF_gltrace_2eproto__INCLUDED diff --git a/opengl/libs/GLES_trace/src/gltrace_api.cpp b/opengl/libs/GLES_trace/src/gltrace_api.cpp index eed3ccfa92..d83b9b4f7f 100644 --- a/opengl/libs/GLES_trace/src/gltrace_api.cpp +++ b/opengl/libs/GLES_trace/src/gltrace_api.cpp @@ -19,7 +19,7 @@ #include <cutils/log.h> #include <utils/Timers.h> -#include "gltrace.pb.h" +#include "frameworks/native/opengl/libs/GLES_trace/proto/gltrace.pb.h" #include "gltrace_context.h" #include "gltrace_fixup.h" #include "gltrace_transport.h" diff --git a/opengl/libs/GLES_trace/src/gltrace_egl.cpp b/opengl/libs/GLES_trace/src/gltrace_egl.cpp index 4f9b006a62..a7878f290f 100644 --- a/opengl/libs/GLES_trace/src/gltrace_egl.cpp +++ b/opengl/libs/GLES_trace/src/gltrace_egl.cpp @@ -17,7 +17,7 @@ #include <cutils/log.h> #include <utils/Timers.h> -#include "gltrace.pb.h" +#include "frameworks/native/opengl/libs/GLES_trace/proto/gltrace.pb.h" #include "gltrace_context.h" #include "gltrace_fixup.h" #include "gltrace_transport.h" diff --git a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp index be729c705f..a4a187a746 100644 --- a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp +++ b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp @@ -21,7 +21,7 @@ #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> -#include "gltrace.pb.h" +#include "frameworks/native/opengl/libs/GLES_trace/proto/gltrace.pb.h" #include "gltrace_api.h" #include "gltrace_context.h" #include "gltrace_fixup.h" diff --git a/opengl/libs/GLES_trace/src/gltrace_fixup.h b/opengl/libs/GLES_trace/src/gltrace_fixup.h index fe301254d6..c90dbeb02a 100644 --- a/opengl/libs/GLES_trace/src/gltrace_fixup.h +++ b/opengl/libs/GLES_trace/src/gltrace_fixup.h @@ -19,7 +19,7 @@ #include <utils/Timers.h> -#include "gltrace.pb.h" +#include "frameworks/native/opengl/libs/GLES_trace/proto/gltrace.pb.h" #include "gltrace_context.h" namespace android { diff --git a/opengl/libs/GLES_trace/src/gltrace_transport.h b/opengl/libs/GLES_trace/src/gltrace_transport.h index 9cf5b45281..fd6cb8c254 100644 --- a/opengl/libs/GLES_trace/src/gltrace_transport.h +++ b/opengl/libs/GLES_trace/src/gltrace_transport.h @@ -19,7 +19,7 @@ #include <pthread.h> -#include "gltrace.pb.h" +#include "frameworks/native/opengl/libs/GLES_trace/proto/gltrace.pb.h" namespace android { namespace gltrace { diff --git a/opengl/libs/egl_impl.h b/opengl/libs/egl_impl.h index cb0e908d31..c0990ece39 100644 --- a/opengl/libs/egl_impl.h +++ b/opengl/libs/egl_impl.h @@ -30,6 +30,9 @@ namespace android { // ---------------------------------------------------------------------------- EGLAPI const GLubyte * egl_get_string_for_current_context(GLenum name); +EGLAPI const GLubyte * egl_get_string_for_current_context(GLenum name, + GLuint index); +EGLAPI GLint egl_get_num_extensions_for_current_context(); // ---------------------------------------------------------------------------- }; // namespace android diff --git a/opengl/tests/EGLTest/Android.mk b/opengl/tests/EGLTest/Android.mk index f37efec713..80e4867b2e 100644 --- a/opengl/tests/EGLTest/Android.mk +++ b/opengl/tests/EGLTest/Android.mk @@ -1,6 +1,7 @@ # Build the unit tests. LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE := EGL_test @@ -14,27 +15,18 @@ LOCAL_SHARED_LIBRARIES := \ libEGL \ libcutils \ libbinder \ - libstlport \ libutils \ libgui \ -LOCAL_STATIC_LIBRARIES := \ - libgtest \ - libgtest_main \ - LOCAL_C_INCLUDES := \ - bionic \ bionic/libc/private \ - bionic/libstdc++/include \ - external/gtest/include \ - external/stlport/stlport \ frameworks/native/opengl/libs \ frameworks/native/opengl/libs/EGL \ # gold in binutils 2.22 will warn about the usage of mktemp LOCAL_LDFLAGS += -Wl,--no-fatal-warnings -include $(BUILD_EXECUTABLE) +include $(BUILD_NATIVE_TEST) # Include subdirectory makefiles # ============================================================ diff --git a/opengl/tests/EGLTest/egl_cache_test.cpp b/opengl/tests/EGLTest/egl_cache_test.cpp index c7d9e3e201..c5bf296e49 100644 --- a/opengl/tests/EGLTest/egl_cache_test.cpp +++ b/opengl/tests/EGLTest/egl_cache_test.cpp @@ -41,7 +41,7 @@ protected: }; TEST_F(EGLCacheTest, UninitializedCacheAlwaysMisses) { - char buf[4] = { 0xee, 0xee, 0xee, 0xee }; + uint8_t buf[4] = { 0xee, 0xee, 0xee, 0xee }; mCache->setBlob("abcd", 4, "efgh", 4); ASSERT_EQ(0, mCache->getBlob("abcd", 4, buf, 4)); ASSERT_EQ(0xee, buf[0]); @@ -51,7 +51,7 @@ TEST_F(EGLCacheTest, UninitializedCacheAlwaysMisses) { } TEST_F(EGLCacheTest, InitializedCacheAlwaysHits) { - char buf[4] = { 0xee, 0xee, 0xee, 0xee }; + uint8_t buf[4] = { 0xee, 0xee, 0xee, 0xee }; mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY)); mCache->setBlob("abcd", 4, "efgh", 4); ASSERT_EQ(4, mCache->getBlob("abcd", 4, buf, 4)); @@ -62,7 +62,7 @@ TEST_F(EGLCacheTest, InitializedCacheAlwaysHits) { } TEST_F(EGLCacheTest, TerminatedCacheAlwaysMisses) { - char buf[4] = { 0xee, 0xee, 0xee, 0xee }; + uint8_t buf[4] = { 0xee, 0xee, 0xee, 0xee }; mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY)); mCache->setBlob("abcd", 4, "efgh", 4); mCache->terminate(); @@ -94,7 +94,7 @@ protected: }; TEST_F(EGLCacheSerializationTest, ReinitializedCacheContainsValues) { - char buf[4] = { 0xee, 0xee, 0xee, 0xee }; + uint8_t buf[4] = { 0xee, 0xee, 0xee, 0xee }; mCache->setCacheFilename(mFilename); mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY)); mCache->setBlob("abcd", 4, "efgh", 4); diff --git a/opengl/tests/angeles/app-linux.cpp b/opengl/tests/angeles/app-linux.cpp index e490351d58..ced878651e 100644 --- a/opengl/tests/angeles/app-linux.cpp +++ b/opengl/tests/angeles/app-linux.cpp @@ -118,7 +118,7 @@ static void checkEGLErrors() fprintf(stderr, "EGL Error: 0x%04x\n", (int)error); } -static int initGraphics(unsigned samples, const WindowSurface& windowSurface) +static int initGraphics(EGLint samples, const WindowSurface& windowSurface) { EGLint configAttribs[] = { EGL_DEPTH_SIZE, 16, diff --git a/opengl/tests/fillrate/fillrate.cpp b/opengl/tests/fillrate/fillrate.cpp index 1d9b026121..2db63d7835 100644 --- a/opengl/tests/fillrate/fillrate.cpp +++ b/opengl/tests/fillrate/fillrate.cpp @@ -91,11 +91,13 @@ int main(int argc, char** argv) } } + const GLfloat fh = h; + const GLfloat fw = w; const GLfloat vertices[4][2] = { - { 0, 0 }, - { 0, h }, - { w, h }, - { w, 0 } + { 0, 0 }, + { 0, fh }, + { fw, fh }, + { fw, 0 } }; const GLfloat texCoords[4][2] = { diff --git a/opengl/tests/filter/filter.cpp b/opengl/tests/filter/filter.cpp index 289e6cc585..287ee93565 100644 --- a/opengl/tests/filter/filter.cpp +++ b/opengl/tests/filter/filter.cpp @@ -140,11 +140,12 @@ int main(int argc, char** argv) //glDrawTexiOES(0, 0, 0, dim, dim); + const GLfloat fdim = dim; const GLfloat vertices[4][2] = { - { 0, 0 }, - { 0, dim }, - { dim, dim }, - { dim, 0 } + { 0, 0 }, + { 0, fdim }, + { fdim, fdim }, + { fdim, 0 } }; const GLfloat texCoords[4][2] = { diff --git a/opengl/tests/hwc/Android.mk b/opengl/tests/hwc/Android.mk index 86e1d46bb1..f83846b691 100644 --- a/opengl/tests/hwc/Android.mk +++ b/opengl/tests/hwc/Android.mk @@ -15,24 +15,25 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk + LOCAL_MODULE_TAGS := tests LOCAL_MODULE:= libhwcTest +LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES +LOCAL_CXX_STL := libc++ LOCAL_SRC_FILES:= hwcTestLib.cpp LOCAL_C_INCLUDES += system/extras/tests/include \ - bionic \ - bionic/libstdc++/include \ - external/stlport/stlport \ - $(call include-path-for, opengl-tests-includes) - -LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES - -LOCAL_SHARED_LIBRARIES += libcutils libutils libstlport -LOCAL_STATIC_LIBRARIES += libglTest - + $(call include-path-for, opengl-tests-includes) \ include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk + +LOCAL_MODULE:= hwcStress +LOCAL_MODULE_TAGS := tests +LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES +LOCAL_CXX_STL := libc++ LOCAL_SRC_FILES:= hwcStress.cpp LOCAL_SHARED_LIBRARIES := \ @@ -52,19 +53,17 @@ LOCAL_STATIC_LIBRARIES := \ LOCAL_C_INCLUDES += \ system/extras/tests/include \ hardware/libhardware/include \ - $(call include-path-for, opengl-tests-includes) + $(call include-path-for, opengl-tests-includes) \ -LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES +include $(BUILD_NATIVE_TEST) -LOCAL_MODULE:= hwcStress +include $(CLEAR_VARS) +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk +LOCAL_MODULE:= hwcRects LOCAL_MODULE_TAGS := tests - LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES - -include $(BUILD_NATIVE_TEST) - -include $(CLEAR_VARS) +LOCAL_CXX_STL := libc++ LOCAL_SRC_FILES:= hwcRects.cpp LOCAL_SHARED_LIBRARIES := \ @@ -84,17 +83,17 @@ LOCAL_STATIC_LIBRARIES := \ LOCAL_C_INCLUDES += \ system/extras/tests/include \ hardware/libhardware/include \ - $(call include-path-for, opengl-tests-includes) - -LOCAL_MODULE:= hwcRects - -LOCAL_MODULE_TAGS := tests - -LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES + $(call include-path-for, opengl-tests-includes) \ include $(BUILD_NATIVE_TEST) include $(CLEAR_VARS) +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk + +LOCAL_MODULE:= hwcColorEquiv +LOCAL_MODULE_TAGS := tests +LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES +LOCAL_CXX_STL := libc++ LOCAL_SRC_FILES:= hwcColorEquiv.cpp LOCAL_SHARED_LIBRARIES := \ @@ -114,17 +113,17 @@ LOCAL_STATIC_LIBRARIES := \ LOCAL_C_INCLUDES += \ system/extras/tests/include \ hardware/libhardware/include \ - $(call include-path-for, opengl-tests-includes) - -LOCAL_MODULE:= hwcColorEquiv - -LOCAL_MODULE_TAGS := tests - -LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES + $(call include-path-for, opengl-tests-includes) \ include $(BUILD_NATIVE_TEST) include $(CLEAR_VARS) +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk + +LOCAL_MODULE:= hwcCommit +LOCAL_MODULE_TAGS := tests +LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES +LOCAL_CXX_STL := libc++ LOCAL_SRC_FILES:= hwcCommit.cpp LOCAL_SHARED_LIBRARIES := \ @@ -144,12 +143,6 @@ LOCAL_STATIC_LIBRARIES := \ LOCAL_C_INCLUDES += \ system/extras/tests/include \ hardware/libhardware/include \ - $(call include-path-for, opengl-tests-includes) - -LOCAL_MODULE:= hwcCommit - -LOCAL_MODULE_TAGS := tests - -LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES + $(call include-path-for, opengl-tests-includes) \ include $(BUILD_NATIVE_TEST) diff --git a/opengl/tests/hwc/hwcColorEquiv.cpp b/opengl/tests/hwc/hwcColorEquiv.cpp index c4624d2d3a..06a0191f60 100644 --- a/opengl/tests/hwc/hwcColorEquiv.cpp +++ b/opengl/tests/hwc/hwcColorEquiv.cpp @@ -166,7 +166,6 @@ main(int argc, char *argv[]) int rv, opt; bool error; char *chptr; - unsigned int pass; char cmd[MAXCMD]; string str; @@ -293,14 +292,12 @@ main(int argc, char *argv[]) // Use the upper third of the display for the reference frame and // the middle third for the equivalence frame. unsigned int refHeight = height / 3; - unsigned int refPosY = 0; // Reference frame Y position unsigned int refPosX = 0; // Reference frame X position unsigned int refWidth = width - refPosX; if ((refWidth & refFormat->wMod) != 0) { refWidth += refFormat->wMod - (refWidth % refFormat->wMod); } unsigned int equivHeight = height / 3; - unsigned int equivPosY = refHeight; // Equivalence frame Y position unsigned int equivPosX = 0; // Equivalence frame X position unsigned int equivWidth = width - equivPosX; if ((equivWidth & equivFormat->wMod) != 0) { diff --git a/opengl/tests/hwc/hwcCommit.cpp b/opengl/tests/hwc/hwcCommit.cpp index 1bd5fdf3a2..1bcb8604fe 100644 --- a/opengl/tests/hwc/hwcCommit.cpp +++ b/opengl/tests/hwc/hwcCommit.cpp @@ -338,7 +338,6 @@ int main(int argc, char *argv[]) { int rv, opt; - char *chptr; bool error; string str; char cmd[MAXCMD]; diff --git a/opengl/tests/hwc/hwcRects.cpp b/opengl/tests/hwc/hwcRects.cpp index 9b57623925..56c1a2ad39 100644 --- a/opengl/tests/hwc/hwcRects.cpp +++ b/opengl/tests/hwc/hwcRects.cpp @@ -204,7 +204,6 @@ main(int argc, char *argv[]) { int rv, opt; char *chptr; - bool error; string str; char cmd[MAXCMD]; @@ -367,7 +366,6 @@ static Rectangle parseRect(string rectStr) istringstream in(rectStr); const struct hwcTestGraphicFormat *format; Rectangle rect; - struct hwc_rect hwcRect; // Graphic Format in >> str; diff --git a/opengl/tests/hwc/hwcTestLib.cpp b/opengl/tests/hwc/hwcTestLib.cpp index 7fae5e598d..3b0ca744bd 100644 --- a/opengl/tests/hwc/hwcTestLib.cpp +++ b/opengl/tests/hwc/hwcTestLib.cpp @@ -20,22 +20,22 @@ * Utility library functions for use by the Hardware Composer test cases */ +#include <arpa/inet.h> // For ntohl() and htonl() + +#include <cmath> #include <sstream> #include <string> -#include <arpa/inet.h> // For ntohl() and htonl() - #include "hwcTestLib.h" #include "EGLUtils.h" // Defines -#define NUMA(a) (sizeof(a) / sizeof(a [0])) +#define NUMA(a) (sizeof(a) / sizeof((a)[0])) // Function Prototypes static void printGLString(const char *name, GLenum s); static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE); -static void checkGlError(const char* op); static void printEGLConfiguration(EGLDisplay dpy, EGLConfig config); using namespace std; @@ -51,8 +51,6 @@ void hwcTestInitDisplay(bool verbose, EGLDisplay *dpy, EGLSurface *surface, { static EGLContext context; - int rv; - EGLBoolean returnValue; EGLConfig myConfig = {0}; EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; @@ -668,7 +666,6 @@ void hwcTestFillColor(GraphicBuffer *gBuf, ColorFract color, float alpha) for (unsigned int x = 0; x < gBuf->getStride(); x++) { for (unsigned int y = 0; y < gBuf->getHeight(); y++) { - uint32_t val = pixel; hwcTestSetPixel(gBuf, buf, x, y, (x < gBuf->getWidth()) ? pixel : testRand()); } @@ -965,14 +962,6 @@ static void checkEglError(const char* op, EGLBoolean returnVal) } } -static void checkGlError(const char* op) -{ - for (GLint error = glGetError(); error; error - = glGetError()) { - testPrintE("after %s() glError (0x%x)", op, error); - } -} - static void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) { diff --git a/opengl/tests/lib/Android.mk b/opengl/tests/lib/Android.mk index a2752cd9fa..e5124adb30 100644 --- a/opengl/tests/lib/Android.mk +++ b/opengl/tests/lib/Android.mk @@ -15,18 +15,13 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE_TAGS := tests LOCAL_MODULE:= libglTest LOCAL_SRC_FILES:= glTestLib.cpp WindowSurface.cpp LOCAL_C_INCLUDES += system/extras/tests/include \ - bionic \ - bionic/libstdc++/include \ - external/stlport/stlport \ $(call include-path-for, opengl-tests-includes) LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -LOCAL_SHARED_LIBRARIES += libcutils libutils libstlport - - include $(BUILD_STATIC_LIBRARY) diff --git a/opengl/tests/linetex/linetex.cpp b/opengl/tests/linetex/linetex.cpp index 7921f8096e..5ad695bc84 100644 --- a/opengl/tests/linetex/linetex.cpp +++ b/opengl/tests/linetex/linetex.cpp @@ -80,9 +80,11 @@ int main(int argc, char** argv) // default pack-alignment is 4 const uint16_t t16[64] = { 0xFFFF, 0, 0xF800, 0, 0x07E0, 0, 0x001F, 0 }; + const GLfloat fh = h; + const GLfloat fw2 = w/2; const GLfloat vertices[4][2] = { - { w/2, 0 }, - { w/2, h } + { fw2, 0 }, + { fw2, fh } }; const GLfloat texCoords[4][2] = { diff --git a/opengl/tools/glgen/src/JType.java b/opengl/tools/glgen/src/JType.java index c6e227e5f3..5803a44a2e 100644 --- a/opengl/tools/glgen/src/JType.java +++ b/opengl/tools/glgen/src/JType.java @@ -191,6 +191,84 @@ public class JType { (baseType.indexOf("Buffer") != -1); } + public JType getArrayTypeForTypedBuffer() { + if (!isTypedBuffer()) { + throw new RuntimeException("Not typed buffer type " + this); + } + switch (baseType) { + case "java.nio.ByteBuffer": + return new JType("byte", false, true); + case "java.nio.BooleanBuffer": + return new JType("boolean", false, true); + case "java.nio.ShortBuffer": + return new JType("short", false, true); + case "java.nio.CharBuffer": + return new JType("char", false, true); + case "java.nio.IntBuffer": + return new JType("int", false, true); + case "java.nio.LongBuffer": + return new JType("long", false, true); + case "java.nio.FloatBuffer": + return new JType("float", false, true); + case "java.nio.DoubleBuffer": + return new JType("double", false, true); + default: + throw new RuntimeException("Unknown typed buffer type " + this); + } + } + + public String getArrayGetterForPrimitiveArray() { + if (!isArray() || isClass()) { + throw new RuntimeException("Not array type " + this); + } + switch (baseType) { + case "byte": + return "GetByteArrayElements"; + case "boolean": + return "GetBooleanArrayElements"; + case "short": + return "GetShortArrayElements"; + case "char": + return "GetCharArrayElements"; + case "int": + return "GetIntArrayElements"; + case "long": + return "GetLongArrayElements"; + case "float": + return "GetFloatArrayElements"; + case "double": + return "GetDoubleArrayElements"; + default: + throw new RuntimeException("Unknown array type " + this); + } + } + + public String getArrayReleaserForPrimitiveArray() { + if (!isArray() || isClass()) { + throw new RuntimeException("Not array type " + this); + } + switch (baseType) { + case "byte": + return "ReleaseByteArrayElements"; + case "boolean": + return "ReleaseBooleanArrayElements"; + case "short": + return "ReleaseShortArrayElements"; + case "char": + return "ReleaseCharArrayElements"; + case "int": + return "ReleaseIntArrayElements"; + case "long": + return "ReleaseLongArrayElements"; + case "float": + return "ReleaseFloatArrayElements"; + case "double": + return "ReleaseDoubleArrayElements"; + default: + throw new RuntimeException("Unknown array type " + this); + } + } + public boolean isEGLHandle() { return !isPrimitive() && (baseType.startsWith("EGL")); diff --git a/opengl/tools/glgen/src/JniCodeEmitter.java b/opengl/tools/glgen/src/JniCodeEmitter.java index e51b7a2841..1bed05bb63 100644 --- a/opengl/tools/glgen/src/JniCodeEmitter.java +++ b/opengl/tools/glgen/src/JniCodeEmitter.java @@ -812,6 +812,7 @@ public class JniCodeEmitter { List<Integer> stringArgs = new ArrayList<Integer>(); int numBufferArgs = 0; List<String> bufferArgNames = new ArrayList<String>(); + List<JType> bufferArgTypes = new ArrayList<JType>(); // Emit JNI signature (arguments) // @@ -835,6 +836,7 @@ public class JniCodeEmitter { int cIndex = jfunc.getArgCIndex(i); String cname = cfunc.getArgName(cIndex); bufferArgNames.add(cname); + bufferArgTypes.add(jfunc.getArgType(i)); numBufferArgs++; } } @@ -948,12 +950,25 @@ public class JniCodeEmitter { // Emit a single _array or multiple _XXXArray variables if (numBufferArgs == 1) { + JType bufferType = bufferArgTypes.get(0); + if (bufferType.isTypedBuffer()) { + String typedArrayType = getJniType(bufferType.getArrayTypeForTypedBuffer()); + out.println(indent + typedArrayType + " _array = (" + typedArrayType + ") 0;"); + } else { out.println(indent + "jarray _array = (jarray) 0;"); - out.println(indent + "jint _bufferOffset = (jint) 0;"); + } + out.println(indent + "jint _bufferOffset = (jint) 0;"); } else { for (int i = 0; i < numBufferArgs; i++) { - out.println(indent + "jarray _" + bufferArgNames.get(i) + - "Array = (jarray) 0;"); + JType bufferType = bufferArgTypes.get(0); + if (bufferType.isTypedBuffer()) { + String typedArrayType = getJniType(bufferType.getArrayTypeForTypedBuffer()); + out.println(indent + typedArrayType + " _" + bufferArgNames.get(i) + + "Array = (" + typedArrayType + ") 0;"); + } else { + out.println(indent + "jarray _" + bufferArgNames.get(i) + + "Array = (jarray) 0;"); + } out.println(indent + "jint _" + bufferArgNames.get(i) + "BufferOffset = (jint) 0;"); } @@ -1135,9 +1150,10 @@ public class JniCodeEmitter { "_base = (" + cfunc.getArgType(cIndex).getDeclaration() + ")"); + String arrayGetter = jfunc.getArgType(idx).getArrayGetterForPrimitiveArray(); out.println(indent + " " + (mUseCPlusPlus ? "_env" : "(*_env)") + - "->GetPrimitiveArrayCritical(" + + "->" + arrayGetter + "(" + (mUseCPlusPlus ? "" : "_env, ") + jfunc.getArgName(idx) + "_ref, (jboolean *)0);"); @@ -1209,7 +1225,7 @@ public class JniCodeEmitter { cfunc.getArgType(cIndex).getDeclaration() + ")getPointer(_env, " + cname + - "_buf, &" + array + ", &" + remaining + ", &" + bufferOffset + + "_buf, (jarray*)&" + array + ", &" + remaining + ", &" + bufferOffset + ");"); } @@ -1244,9 +1260,17 @@ public class JniCodeEmitter { } else { out.println(indent + "if (" + cname +" == NULL) {"); } - out.println(indent + indent + "char * _" + cname + "Base = (char *)_env->GetPrimitiveArrayCritical(" + array + ", (jboolean *) 0);"); - out.println(indent + indent + cname + " = (" +cfunc.getArgType(cIndex).getDeclaration() +") (_" + cname + "Base + " + bufferOffset + ");"); - out.println(indent + "}"); + JType argType = jfunc.getArgType(idx); + if (argType.isTypedBuffer()) { + String arrayGetter = argType.getArrayTypeForTypedBuffer().getArrayGetterForPrimitiveArray(); + out.println(indent + indent + "char * _" + cname + "Base = (char *)_env->" + arrayGetter + "(" + array + ", (jboolean *) 0);"); + out.println(indent + indent + cname + " = (" +cfunc.getArgType(cIndex).getDeclaration() +") (_" + cname + "Base + " + bufferOffset + ");"); + out.println(indent + "}"); + } else { + out.println(indent + indent + "char * _" + cname + "Base = (char *)_env->GetPrimitiveArrayCritical(" + array + ", (jboolean *) 0);"); + out.println(indent + indent + cname + " = (" +cfunc.getArgType(cIndex).getDeclaration() +") (_" + cname + "Base + " + bufferOffset + ");"); + out.println(indent + "}"); + } } } @@ -1336,12 +1360,13 @@ public class JniCodeEmitter { // the need to write back to the Java array out.println(indent + "if (" + jfunc.getArgName(idx) + "_base) {"); + String arrayReleaser = jfunc.getArgType(idx).getArrayReleaserForPrimitiveArray(); out.println(indent + indent + (mUseCPlusPlus ? "_env" : "(*_env)") + - "->ReleasePrimitiveArrayCritical(" + + "->" + arrayReleaser + "(" + (mUseCPlusPlus ? "" : "_env, ") + jfunc.getArgName(idx) + "_ref, " + - cfunc.getArgName(cIndex) + + "(j" + jfunc.getArgType(idx).getBaseType() + "*)" + cfunc.getArgName(cIndex) + "_base,"); out.println(indent + indent + indent + (cfunc.getArgType(cIndex).isConst() ? @@ -1350,17 +1375,32 @@ public class JniCodeEmitter { out.println(indent + "}"); } else if (jfunc.getArgType(idx).isBuffer()) { if (! isPointerFunc) { + JType argType = jfunc.getArgType(idx); String array = numBufferArgs <= 1 ? "_array" : "_" + cfunc.getArgName(cIndex) + "Array"; out.println(indent + "if (" + array + ") {"); - out.println(indent + indent + - "releasePointer(_env, " + array + ", " + - cfunc.getArgName(cIndex) + - ", " + - (cfunc.getArgType(cIndex).isConst() ? - "JNI_FALSE" : (emitExceptionCheck ? - "_exception ? JNI_FALSE : JNI_TRUE" : "JNI_TRUE")) + - ");"); + if (argType.isTypedBuffer()) { + String arrayReleaser = + argType.getArrayTypeForTypedBuffer().getArrayReleaserForPrimitiveArray(); + out.println(indent + indent + + "_env->" + arrayReleaser + "(" + array + ", " + + "(j" + argType.getArrayTypeForTypedBuffer().getBaseType() + "*)" + + cfunc.getArgName(cIndex) + + ", " + + (cfunc.getArgType(cIndex).isConst() ? + "JNI_ABORT" : (emitExceptionCheck ? + "_exception ? JNI_ABORT : 0" : "0")) + + ");"); + } else { + out.println(indent + indent + + "releasePointer(_env, " + array + ", " + + cfunc.getArgName(cIndex) + + ", " + + (cfunc.getArgType(cIndex).isConst() ? + "JNI_FALSE" : (emitExceptionCheck ? + "_exception ? JNI_FALSE : JNI_TRUE" : "JNI_TRUE")) + + ");"); + } out.println(indent + "}"); } } diff --git a/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp b/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp index a372362f61..f6813fdc03 100644 --- a/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp +++ b/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp @@ -16,6 +16,10 @@ // This source file is automatically generated +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-function" + #include "jni.h" #include "JNIHelp.h" #include <android_runtime/AndroidRuntime.h> diff --git a/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp b/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp index b5c19df782..4df61d3126 100644 --- a/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp +++ b/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp @@ -16,6 +16,10 @@ // This source file is automatically generated +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-function" + #include "jni.h" #include "JNIHelp.h" #include <android_runtime/AndroidRuntime.h> @@ -81,23 +85,19 @@ nativeClassInit(JNIEnv *_env, jclass glImplClass) eglsurfaceConstructor = _env->GetMethodID(eglsurfaceClass, "<init>", "(J)V"); eglconfigConstructor = _env->GetMethodID(eglconfigClass, "<init>", "(J)V"); - jobject localeglNoContextObject = _env->NewObject(eglcontextClass, eglcontextConstructor, reinterpret_cast<jlong>(EGL_NO_CONTEXT)); - eglNoContextObject = _env->NewGlobalRef(localeglNoContextObject); - jobject localeglNoDisplayObject = _env->NewObject(egldisplayClass, egldisplayConstructor, reinterpret_cast<jlong>(EGL_NO_DISPLAY)); - eglNoDisplayObject = _env->NewGlobalRef(localeglNoDisplayObject); - jobject localeglNoSurfaceObject = _env->NewObject(eglsurfaceClass, eglsurfaceConstructor, reinterpret_cast<jlong>(EGL_NO_SURFACE)); - eglNoSurfaceObject = _env->NewGlobalRef(localeglNoSurfaceObject); - jclass eglClass = _env->FindClass("android/opengl/EGL14"); jfieldID noContextFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_CONTEXT", "Landroid/opengl/EGLContext;"); - _env->SetStaticObjectField(eglClass, noContextFieldID, eglNoContextObject); + jobject localeglNoContextObject = _env->GetStaticObjectField(eglClass, noContextFieldID); + eglNoContextObject = _env->NewGlobalRef(localeglNoContextObject); jfieldID noDisplayFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_DISPLAY", "Landroid/opengl/EGLDisplay;"); - _env->SetStaticObjectField(eglClass, noDisplayFieldID, eglNoDisplayObject); + jobject localeglNoDisplayObject = _env->GetStaticObjectField(eglClass, noDisplayFieldID); + eglNoDisplayObject = _env->NewGlobalRef(localeglNoDisplayObject); jfieldID noSurfaceFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_SURFACE", "Landroid/opengl/EGLSurface;"); - _env->SetStaticObjectField(eglClass, noSurfaceFieldID, eglNoSurfaceObject); + jobject localeglNoSurfaceObject = _env->GetStaticObjectField(eglClass, noSurfaceFieldID); + eglNoSurfaceObject = _env->NewGlobalRef(localeglNoSurfaceObject); } static void * diff --git a/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.cpp b/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.cpp index f09c17161c..6199637d60 100755 --- a/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.cpp +++ b/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.cpp @@ -27,7 +27,7 @@ android_eglCreatePbufferFromClientBuffer } _remaining = _env->GetArrayLength(attrib_list_ref) - offset; attrib_list_base = (EGLint *) - _env->GetPrimitiveArrayCritical(attrib_list_ref, (jboolean *)0); + _env->GetIntArrayElements(attrib_list_ref, (jboolean *)0); attrib_list = attrib_list_base + offset; attrib_list_sentinel = false; for (int i = _remaining - 1; i >= 0; i--) { @@ -53,7 +53,7 @@ android_eglCreatePbufferFromClientBuffer exit: if (attrib_list_base) { - _env->ReleasePrimitiveArrayCritical(attrib_list_ref, attrib_list_base, + _env->ReleaseIntArrayElements(attrib_list_ref, attrib_list_base, JNI_ABORT); } if (_exception) { @@ -71,4 +71,3 @@ android_eglCreatePbufferFromClientBufferInt } return android_eglCreatePbufferFromClientBuffer(_env, _this, dpy, buftype, buffer, config, attrib_list_ref, offset); } - diff --git a/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp b/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp index 0b6bf581e1..cc7b85d1de 100644 --- a/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp +++ b/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp @@ -41,7 +41,7 @@ not_valid_surface: _remaining = _env->GetArrayLength(attrib_list_ref) - offset; attrib_list_base = (EGLint *) - _env->GetPrimitiveArrayCritical(attrib_list_ref, (jboolean *)0); + _env->GetIntArrayElements(attrib_list_ref, (jboolean *)0); attrib_list = attrib_list_base + offset; attrib_list_sentinel = 0; for (int i = _remaining - 1; i >= 0; i--) { @@ -66,7 +66,7 @@ not_valid_surface: exit: if (attrib_list_base) { - _env->ReleasePrimitiveArrayCritical(attrib_list_ref, attrib_list_base, + _env->ReleaseIntArrayElements(attrib_list_ref, attrib_list_base, JNI_ABORT); } if (_exception) { @@ -123,7 +123,7 @@ not_valid_surface: _remaining = _env->GetArrayLength(attrib_list_ref) - offset; attrib_list_base = (EGLint *) - _env->GetPrimitiveArrayCritical(attrib_list_ref, (jboolean *)0); + _env->GetIntArrayElements(attrib_list_ref, (jboolean *)0); attrib_list = attrib_list_base + offset; attrib_list_sentinel = 0; for (int i = _remaining - 1; i >= 0; i--) { @@ -148,7 +148,7 @@ not_valid_surface: exit: if (attrib_list_base) { - _env->ReleasePrimitiveArrayCritical(attrib_list_ref, attrib_list_base, + _env->ReleaseIntArrayElements(attrib_list_ref, attrib_list_base, JNI_ABORT); } if (_exception) { diff --git a/opengl/tools/glgen/stubs/egl/eglGetDisplay.cpp b/opengl/tools/glgen/stubs/egl/eglGetDisplay.cpp index 003efd3e16..2abc9167d6 100755 --- a/opengl/tools/glgen/stubs/egl/eglGetDisplay.cpp +++ b/opengl/tools/glgen/stubs/egl/eglGetDisplay.cpp @@ -14,7 +14,8 @@ static jobject android_eglGetDisplayInt (JNIEnv *_env, jobject _this, jint display_id) { - if ((EGLNativeDisplayType)display_id != EGL_DEFAULT_DISPLAY) { + if (static_cast<uintptr_t>(display_id) != + reinterpret_cast<uintptr_t>(EGL_DEFAULT_DISPLAY)) { jniThrowException(_env, "java/lang/UnsupportedOperationException", "eglGetDisplay"); return 0; } diff --git a/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp index 8a1d5edb0f..1fa92758ad 100644 --- a/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp +++ b/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp @@ -17,6 +17,10 @@ // This source file is automatically generated +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-function" + #include <GLES/gl.h> #include <GLES/glext.h> diff --git a/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp index 8a1d5edb0f..1fa92758ad 100644 --- a/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp +++ b/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp @@ -17,6 +17,10 @@ // This source file is automatically generated +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-function" + #include <GLES/gl.h> #include <GLES/glext.h> diff --git a/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp index 8a1d5edb0f..1fa92758ad 100644 --- a/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp +++ b/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp @@ -17,6 +17,10 @@ // This source file is automatically generated +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-function" + #include <GLES/gl.h> #include <GLES/glext.h> diff --git a/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp index 8a1d5edb0f..1fa92758ad 100644 --- a/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp +++ b/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp @@ -17,6 +17,10 @@ // This source file is automatically generated +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-function" + #include <GLES/gl.h> #include <GLES/glext.h> diff --git a/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp index 2389563f90..4004a7dfcf 100644 --- a/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp +++ b/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp @@ -17,6 +17,10 @@ // This source file is automatically generated +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-function" + #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> diff --git a/opengl/tools/glgen/stubs/gles11/GLES30cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES30cHeader.cpp index f5ec455a9d..c5bdf323fc 100644 --- a/opengl/tools/glgen/stubs/gles11/GLES30cHeader.cpp +++ b/opengl/tools/glgen/stubs/gles11/GLES30cHeader.cpp @@ -17,6 +17,10 @@ // This source file is automatically generated +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-function" + #include <GLES3/gl3.h> #include <GLES3/gl3ext.h> diff --git a/opengl/tools/glgen/stubs/gles11/GLES31ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES31ExtcHeader.cpp index e7e356116a..2260a80bb4 100644 --- a/opengl/tools/glgen/stubs/gles11/GLES31ExtcHeader.cpp +++ b/opengl/tools/glgen/stubs/gles11/GLES31ExtcHeader.cpp @@ -16,6 +16,10 @@ // This source file is automatically generated +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-function" + #include <GLES3/gl31.h> #include <GLES2/gl2ext.h> diff --git a/opengl/tools/glgen/stubs/gles11/GLES31cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES31cHeader.cpp index c48ec7c4d4..130612d7cc 100644 --- a/opengl/tools/glgen/stubs/gles11/GLES31cHeader.cpp +++ b/opengl/tools/glgen/stubs/gles11/GLES31cHeader.cpp @@ -16,5 +16,9 @@ // This source file is automatically generated +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-function" + #include <stdint.h> #include <GLES3/gl31.h> diff --git a/opengl/tools/glgen/stubs/gles11/common.cpp b/opengl/tools/glgen/stubs/gles11/common.cpp index f7bcb9d8e1..18ec5e3e7e 100644 --- a/opengl/tools/glgen/stubs/gles11/common.cpp +++ b/opengl/tools/glgen/stubs/gles11/common.cpp @@ -100,6 +100,116 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *o return NULL; } +class ByteArrayGetter { +public: + static void* Get(JNIEnv* _env, jbyteArray array, jboolean* is_copy) { + return _env->GetByteArrayElements(array, is_copy); + } +}; +class BooleanArrayGetter { +public: + static void* Get(JNIEnv* _env, jbooleanArray array, jboolean* is_copy) { + return _env->GetBooleanArrayElements(array, is_copy); + } +}; +class CharArrayGetter { +public: + static void* Get(JNIEnv* _env, jcharArray array, jboolean* is_copy) { + return _env->GetCharArrayElements(array, is_copy); + } +}; +class ShortArrayGetter { +public: + static void* Get(JNIEnv* _env, jshortArray array, jboolean* is_copy) { + return _env->GetShortArrayElements(array, is_copy); + } +}; +class IntArrayGetter { +public: + static void* Get(JNIEnv* _env, jintArray array, jboolean* is_copy) { + return _env->GetIntArrayElements(array, is_copy); + } +}; +class LongArrayGetter { +public: + static void* Get(JNIEnv* _env, jlongArray array, jboolean* is_copy) { + return _env->GetLongArrayElements(array, is_copy); + } +}; +class FloatArrayGetter { +public: + static void* Get(JNIEnv* _env, jfloatArray array, jboolean* is_copy) { + return _env->GetFloatArrayElements(array, is_copy); + } +}; +class DoubleArrayGetter { +public: + static void* Get(JNIEnv* _env, jdoubleArray array, jboolean* is_copy) { + return _env->GetDoubleArrayElements(array, is_copy); + } +}; + +template<typename JTYPEARRAY, typename ARRAYGETTER> +static void* +getArrayPointer(JNIEnv *_env, JTYPEARRAY array, jboolean* is_copy) { + return ARRAYGETTER::Get(_env, array, is_copy); +} + +class ByteArrayReleaser { +public: + static void Release(JNIEnv* _env, jbyteArray array, jbyte* data, jboolean commit) { + _env->ReleaseByteArrayElements(array, data, commit ? 0 : JNI_ABORT); + } +}; +class BooleanArrayReleaser { +public: + static void Release(JNIEnv* _env, jbooleanArray array, jboolean* data, jboolean commit) { + _env->ReleaseBooleanArrayElements(array, data, commit ? 0 : JNI_ABORT); + } +}; +class CharArrayReleaser { +public: + static void Release(JNIEnv* _env, jcharArray array, jchar* data, jboolean commit) { + _env->ReleaseCharArrayElements(array, data, commit ? 0 : JNI_ABORT); + } +}; +class ShortArrayReleaser { +public: + static void Release(JNIEnv* _env, jshortArray array, jshort* data, jboolean commit) { + _env->ReleaseShortArrayElements(array, data, commit ? 0 : JNI_ABORT); + } +}; +class IntArrayReleaser { +public: + static void Release(JNIEnv* _env, jintArray array, jint* data, jboolean commit) { + _env->ReleaseIntArrayElements(array, data, commit ? 0 : JNI_ABORT); + } +}; +class LongArrayReleaser { +public: + static void Release(JNIEnv* _env, jlongArray array, jlong* data, jboolean commit) { + _env->ReleaseLongArrayElements(array, data, commit ? 0 : JNI_ABORT); + } +}; +class FloatArrayReleaser { +public: + static void Release(JNIEnv* _env, jfloatArray array, jfloat* data, jboolean commit) { + _env->ReleaseFloatArrayElements(array, data, commit ? 0 : JNI_ABORT); + } +}; +class DoubleArrayReleaser { +public: + static void Release(JNIEnv* _env, jdoubleArray array, jdouble* data, jboolean commit) { + _env->ReleaseDoubleArrayElements(array, data, commit ? 0 : JNI_ABORT); + } +}; + +template<typename JTYPEARRAY, typename NTYPEARRAY, typename ARRAYRELEASER> +static void +releaseArrayPointer(JNIEnv *_env, JTYPEARRAY array, NTYPEARRAY data, jboolean commit) { + ARRAYRELEASER::Release(_env, array, data, commit); +} + static void releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) { @@ -203,7 +313,8 @@ static int getNeededCount(GLint pname) { return needed; } -template <typename JTYPEARRAY, typename CTYPE, void GET(GLenum, CTYPE*)> +template <typename JTYPEARRAY, typename ARRAYGETTER, typename NTYPEARRAY, + typename ARRAYRELEASER, typename CTYPE, void GET(GLenum, CTYPE*)> static void get (JNIEnv *_env, jobject _this, jint pname, JTYPEARRAY params_ref, jint offset) { @@ -238,8 +349,8 @@ get _exceptionMessage = "length - offset < needed"; goto exit; } - params_base = (CTYPE *) - _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0); + params_base = (CTYPE *) getArrayPointer<JTYPEARRAY, ARRAYGETTER>( + _env, params_ref, (jboolean *)0); params = params_base + offset; GET( @@ -249,8 +360,8 @@ get exit: if (params_base) { - _env->ReleasePrimitiveArrayCritical(params_ref, params_base, - _exception ? JNI_ABORT: 0); + releaseArrayPointer<JTYPEARRAY, NTYPEARRAY, ARRAYRELEASER>( + _env, params_ref, params_base, !_exception); } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); @@ -258,20 +369,21 @@ exit: } -template <typename CTYPE, void GET(GLenum, CTYPE*)> +template <typename CTYPE, typename JTYPEARRAY, typename ARRAYGETTER, typename NTYPEARRAY, + typename ARRAYRELEASER, void GET(GLenum, CTYPE*)> static void getarray (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) { jint _exception = 0; const char * _exceptionType; const char * _exceptionMessage; - jarray _array = (jarray) 0; + JTYPEARRAY _array = (JTYPEARRAY) 0; jint _bufferOffset = (jint) 0; jint _remaining; CTYPE *params = (CTYPE *) 0; int _needed = 0; - params = (CTYPE *)getPointer(_env, params_buf, &_array, &_remaining, &_bufferOffset); + params = (CTYPE *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset); _remaining /= sizeof(CTYPE); // convert from bytes to item count _needed = getNeededCount(pname); // if we didn't find this pname, we just assume the user passed @@ -284,7 +396,8 @@ getarray goto exit; } if (params == NULL) { - char * _paramsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0); + char * _paramsBase = (char *) getArrayPointer<JTYPEARRAY, ARRAYGETTER>( + _env, _array, (jboolean *) 0); params = (CTYPE *) (_paramsBase + _bufferOffset); } GET( @@ -294,7 +407,8 @@ getarray exit: if (_array) { - releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE); + releaseArrayPointer<JTYPEARRAY, NTYPEARRAY, ARRAYRELEASER>( + _env, _array, (NTYPEARRAY)params, _exception ? JNI_FALSE : JNI_TRUE); } if (_exception) { jniThrowException(_env, _exceptionType, _exceptionMessage); diff --git a/opengl/tools/glgen/stubs/gles11/glDrawArraysIndirect.cpp b/opengl/tools/glgen/stubs/gles11/glDrawArraysIndirect.cpp index ce3bc8facb..eda2e46d7c 100644 --- a/opengl/tools/glgen/stubs/gles11/glDrawArraysIndirect.cpp +++ b/opengl/tools/glgen/stubs/gles11/glDrawArraysIndirect.cpp @@ -3,7 +3,7 @@ static void android_glDrawArraysIndirect(JNIEnv *_env, jobject, int mode, jlong // In OpenGL ES, 'indirect' is a byte offset into a buffer, not a raw pointer. // GL checks for too-large values. Here we only need to check for successful signed 64-bit // to unsigned 32-bit conversion. - if (sizeof(void*) != sizeof(jlong) && indirect > UINTPTR_MAX) { + if (sizeof(void*) != sizeof(jlong) && indirect > static_cast<jlong>(UINT32_MAX)) { jniThrowException(_env, "java/lang/IllegalArgumentException", "indirect offset too large"); return; } diff --git a/opengl/tools/glgen/stubs/gles11/glDrawElementsIndirect.cpp b/opengl/tools/glgen/stubs/gles11/glDrawElementsIndirect.cpp index 1833ee9b9e..a091dc9949 100644 --- a/opengl/tools/glgen/stubs/gles11/glDrawElementsIndirect.cpp +++ b/opengl/tools/glgen/stubs/gles11/glDrawElementsIndirect.cpp @@ -3,7 +3,7 @@ static void android_glDrawElementsIndirect(JNIEnv *_env, jobject, jint mode, jin // In OpenGL ES, 'indirect' is a byte offset into a buffer, not a raw pointer. // GL checks for too-large values. Here we only need to check for successful signed 64-bit // to unsigned 32-bit conversion. - if (sizeof(void*) != sizeof(jlong) && indirect > UINTPTR_MAX) { + if (sizeof(void*) != sizeof(jlong) && indirect > static_cast<jlong>(UINT32_MAX)) { jniThrowException(_env, "java/lang/IllegalArgumentException", "indirect offset too large"); return; } diff --git a/opengl/tools/glgen/stubs/gles11/glDrawElementsInstanced.cpp b/opengl/tools/glgen/stubs/gles11/glDrawElementsInstanced.cpp index 41df486f1b..86decfbe31 100644 --- a/opengl/tools/glgen/stubs/gles11/glDrawElementsInstanced.cpp +++ b/opengl/tools/glgen/stubs/gles11/glDrawElementsInstanced.cpp @@ -32,8 +32,7 @@ android_glDrawElementsInstanced__IIIII (GLenum)mode, (GLsizei)count, (GLenum)type, - (GLvoid *)indicesOffset, + (GLvoid *)static_cast<uintptr_t>(indicesOffset), (GLsizei)instanceCount ); } - diff --git a/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.cpp b/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.cpp index 7d414d8f35..a8d63d9d3a 100644 --- a/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.cpp +++ b/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.cpp @@ -32,7 +32,7 @@ android_glGetActiveAttrib__III_3II_3II_3II_3BI } _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset; length_base = (GLsizei *) - _env->GetPrimitiveArrayCritical(length_ref, (jboolean *)0); + _env->GetIntArrayElements(length_ref, (jboolean *)0); length = length_base + lengthOffset; if (!size_ref) { @@ -49,7 +49,7 @@ android_glGetActiveAttrib__III_3II_3II_3II_3BI } _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset; size_base = (GLint *) - _env->GetPrimitiveArrayCritical(size_ref, (jboolean *)0); + _env->GetIntArrayElements(size_ref, (jboolean *)0); size = size_base + sizeOffset; if (!type_ref) { @@ -66,7 +66,7 @@ android_glGetActiveAttrib__III_3II_3II_3II_3BI } _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset; type_base = (GLenum *) - _env->GetPrimitiveArrayCritical(type_ref, (jboolean *)0); + _env->GetIntArrayElements(type_ref, (jboolean *)0); type = type_base + typeOffset; if (!name_ref) { @@ -83,7 +83,7 @@ android_glGetActiveAttrib__III_3II_3II_3II_3BI } _nameRemaining = _env->GetArrayLength(name_ref) - nameOffset; name_base = (char *) - _env->GetPrimitiveArrayCritical(name_ref, (jboolean *)0); + _env->GetByteArrayElements(name_ref, (jboolean *)0); name = name_base + nameOffset; glGetActiveAttrib( @@ -98,19 +98,19 @@ android_glGetActiveAttrib__III_3II_3II_3II_3BI exit: if (name_base) { - _env->ReleasePrimitiveArrayCritical(name_ref, name_base, + _env->ReleaseByteArrayElements(name_ref, (jbyte*)name_base, _exception ? JNI_ABORT: 0); } if (type_base) { - _env->ReleasePrimitiveArrayCritical(type_ref, type_base, + _env->ReleaseIntArrayElements(type_ref, (jint*)type_base, _exception ? JNI_ABORT: 0); } if (size_base) { - _env->ReleasePrimitiveArrayCritical(size_ref, size_base, + _env->ReleaseIntArrayElements(size_ref, (jint*)size_base, _exception ? JNI_ABORT: 0); } if (length_base) { - _env->ReleasePrimitiveArrayCritical(length_ref, length_base, + _env->ReleaseIntArrayElements(length_ref, (jint*)length_base, _exception ? JNI_ABORT: 0); } if (_exception) { @@ -122,11 +122,11 @@ exit: static void android_glGetActiveAttrib__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jobject length_buf, jobject size_buf, jobject type_buf, jbyte name) { - jarray _lengthArray = (jarray) 0; + jintArray _lengthArray = (jintArray) 0; jint _lengthBufferOffset = (jint) 0; - jarray _sizeArray = (jarray) 0; + jintArray _sizeArray = (jintArray) 0; jint _sizeBufferOffset = (jint) 0; - jarray _typeArray = (jarray) 0; + jintArray _typeArray = (jintArray) 0; jint _typeBufferOffset = (jint) 0; jint _lengthRemaining; GLsizei *length = (GLsizei *) 0; @@ -135,19 +135,19 @@ android_glGetActiveAttrib__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_ni jint _typeRemaining; GLenum *type = (GLenum *) 0; - length = (GLsizei *)getPointer(_env, length_buf, &_lengthArray, &_lengthRemaining, &_lengthBufferOffset); - size = (GLint *)getPointer(_env, size_buf, &_sizeArray, &_sizeRemaining, &_sizeBufferOffset); - type = (GLenum *)getPointer(_env, type_buf, &_typeArray, &_typeRemaining, &_typeBufferOffset); + length = (GLsizei *)getPointer(_env, length_buf, (jarray*)&_lengthArray, &_lengthRemaining, &_lengthBufferOffset); + size = (GLint *)getPointer(_env, size_buf, (jarray*)&_sizeArray, &_sizeRemaining, &_sizeBufferOffset); + type = (GLenum *)getPointer(_env, type_buf, (jarray*)&_typeArray, &_typeRemaining, &_typeBufferOffset); if (length == NULL) { - char * _lengthBase = (char *)_env->GetPrimitiveArrayCritical(_lengthArray, (jboolean *) 0); + char * _lengthBase = (char *)_env->GetIntArrayElements(_lengthArray, (jboolean *) 0); length = (GLsizei *) (_lengthBase + _lengthBufferOffset); } if (size == NULL) { - char * _sizeBase = (char *)_env->GetPrimitiveArrayCritical(_sizeArray, (jboolean *) 0); + char * _sizeBase = (char *)_env->GetIntArrayElements(_sizeArray, (jboolean *) 0); size = (GLint *) (_sizeBase + _sizeBufferOffset); } if (type == NULL) { - char * _typeBase = (char *)_env->GetPrimitiveArrayCritical(_typeArray, (jboolean *) 0); + char * _typeBase = (char *)_env->GetIntArrayElements(_typeArray, (jboolean *) 0); type = (GLenum *) (_typeBase + _typeBufferOffset); } glGetActiveAttrib( @@ -160,13 +160,13 @@ android_glGetActiveAttrib__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_ni reinterpret_cast<char *>(name) ); if (_typeArray) { - releasePointer(_env, _typeArray, type, JNI_TRUE); + releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _typeArray, (jint*)type, JNI_TRUE); } if (_sizeArray) { - releasePointer(_env, _sizeArray, size, JNI_TRUE); + releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _sizeArray, (jint*)size, JNI_TRUE); } if (_lengthArray) { - releasePointer(_env, _lengthArray, length, JNI_TRUE); + releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _lengthArray, (jint*)length, JNI_TRUE); } } @@ -211,7 +211,7 @@ android_glGetActiveAttrib1 } _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset; size_base = (GLint *) - _env->GetPrimitiveArrayCritical(size_ref, (jboolean *)0); + _env->GetIntArrayElements(size_ref, (jboolean *)0); size = size_base + sizeOffset; if (!type_ref) { @@ -228,7 +228,7 @@ android_glGetActiveAttrib1 } _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset; type_base = (GLenum *) - _env->GetPrimitiveArrayCritical(type_ref, (jboolean *)0); + _env->GetIntArrayElements(type_ref, (jboolean *)0); type = type_base + typeOffset; glGetActiveAttrib( @@ -242,11 +242,11 @@ android_glGetActiveAttrib1 ); exit: if (type_base) { - _env->ReleasePrimitiveArrayCritical(type_ref, type_base, + _env->ReleaseIntArrayElements(type_ref, (jint*)type_base, _exception ? JNI_ABORT: 0); } if (size_base) { - _env->ReleasePrimitiveArrayCritical(size_ref, size_base, + _env->ReleaseIntArrayElements(size_ref, (jint*)size_base, _exception ? JNI_ABORT: 0); } if (_exception != 1) { @@ -269,9 +269,9 @@ exit: static jstring android_glGetActiveAttrib2 (JNIEnv *_env, jobject _this, jint program, jint index, jobject size_buf, jobject type_buf) { - jarray _sizeArray = (jarray) 0; + jintArray _sizeArray = (jintArray) 0; jint _sizeBufferOffset = (jint) 0; - jarray _typeArray = (jarray) 0; + jintArray _typeArray = (jintArray) 0; jint _typeBufferOffset = (jint) 0; jint _lengthRemaining; GLsizei *length = (GLsizei *) 0; @@ -294,14 +294,14 @@ android_glGetActiveAttrib2 return NULL; } - size = (GLint *)getPointer(_env, size_buf, &_sizeArray, &_sizeRemaining, &_sizeBufferOffset); - type = (GLenum *)getPointer(_env, type_buf, &_typeArray, &_typeRemaining, &_typeBufferOffset); + size = (GLint *)getPointer(_env, size_buf, (jarray*)&_sizeArray, &_sizeRemaining, &_sizeBufferOffset); + type = (GLenum *)getPointer(_env, type_buf, (jarray*)&_typeArray, &_typeRemaining, &_typeBufferOffset); if (size == NULL) { - char * _sizeBase = (char *)_env->GetPrimitiveArrayCritical(_sizeArray, (jboolean *) 0); + char * _sizeBase = (char *)_env->GetIntArrayElements(_sizeArray, (jboolean *) 0); size = (GLint *) (_sizeBase + _sizeBufferOffset); } if (type == NULL) { - char * _typeBase = (char *)_env->GetPrimitiveArrayCritical(_typeArray, (jboolean *) 0); + char * _typeBase = (char *)_env->GetIntArrayElements(_typeArray, (jboolean *) 0); type = (GLenum *) (_typeBase + _typeBufferOffset); } glGetActiveAttrib( @@ -315,10 +315,10 @@ android_glGetActiveAttrib2 ); if (_typeArray) { - releasePointer(_env, _typeArray, type, JNI_TRUE); + releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _typeArray, (jint*)type, JNI_TRUE); } if (_sizeArray) { - releasePointer(_env, _sizeArray, size, JNI_TRUE); + releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _sizeArray, (jint*)size, JNI_TRUE); } result = _env->NewStringUTF(buf); if (buf) { diff --git a/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.cpp b/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.cpp index a7376ba90c..68e83890e1 100644 --- a/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.cpp +++ b/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.cpp @@ -32,7 +32,7 @@ android_glGetActiveUniform__III_3II_3II_3II_3BI } _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset; length_base = (GLsizei *) - _env->GetPrimitiveArrayCritical(length_ref, (jboolean *)0); + _env->GetIntArrayElements(length_ref, (jboolean *)0); length = length_base + lengthOffset; if (!size_ref) { @@ -49,7 +49,7 @@ android_glGetActiveUniform__III_3II_3II_3II_3BI } _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset; size_base = (GLint *) - _env->GetPrimitiveArrayCritical(size_ref, (jboolean *)0); + _env->GetIntArrayElements(size_ref, (jboolean *)0); size = size_base + sizeOffset; if (!type_ref) { @@ -66,7 +66,7 @@ android_glGetActiveUniform__III_3II_3II_3II_3BI } _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset; type_base = (GLenum *) - _env->GetPrimitiveArrayCritical(type_ref, (jboolean *)0); + _env->GetIntArrayElements(type_ref, (jboolean *)0); type = type_base + typeOffset; if (!name_ref) { @@ -83,7 +83,7 @@ android_glGetActiveUniform__III_3II_3II_3II_3BI } _nameRemaining = _env->GetArrayLength(name_ref) - nameOffset; name_base = (char *) - _env->GetPrimitiveArrayCritical(name_ref, (jboolean *)0); + _env->GetByteArrayElements(name_ref, (jboolean *)0); name = name_base + nameOffset; glGetActiveUniform( @@ -98,19 +98,19 @@ android_glGetActiveUniform__III_3II_3II_3II_3BI exit: if (name_base) { - _env->ReleasePrimitiveArrayCritical(name_ref, name_base, + _env->ReleaseByteArrayElements(name_ref, (jbyte*)name_base, _exception ? JNI_ABORT: 0); } if (type_base) { - _env->ReleasePrimitiveArrayCritical(type_ref, type_base, + _env->ReleaseIntArrayElements(type_ref, (jint*)type_base, _exception ? JNI_ABORT: 0); } if (size_base) { - _env->ReleasePrimitiveArrayCritical(size_ref, size_base, + _env->ReleaseIntArrayElements(size_ref, (jint*)size_base, _exception ? JNI_ABORT: 0); } if (length_base) { - _env->ReleasePrimitiveArrayCritical(length_ref, length_base, + _env->ReleaseIntArrayElements(length_ref, (jint*)length_base, _exception ? JNI_ABORT: 0); } if (_exception) { @@ -122,11 +122,11 @@ exit: static void android_glGetActiveUniform__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jobject length_buf, jobject size_buf, jobject type_buf, jbyte name) { - jarray _lengthArray = (jarray) 0; + jintArray _lengthArray = (jintArray) 0; jint _lengthBufferOffset = (jint) 0; - jarray _sizeArray = (jarray) 0; + jintArray _sizeArray = (jintArray) 0; jint _sizeBufferOffset = (jint) 0; - jarray _typeArray = (jarray) 0; + jintArray _typeArray = (jintArray) 0; jint _typeBufferOffset = (jint) 0; jint _lengthRemaining; GLsizei *length = (GLsizei *) 0; @@ -135,19 +135,19 @@ android_glGetActiveUniform__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_n jint _typeRemaining; GLenum *type = (GLenum *) 0; - length = (GLsizei *)getPointer(_env, length_buf, &_lengthArray, &_lengthRemaining, &_lengthBufferOffset); - size = (GLint *)getPointer(_env, size_buf, &_sizeArray, &_sizeRemaining, &_sizeBufferOffset); - type = (GLenum *)getPointer(_env, type_buf, &_typeArray, &_typeRemaining, &_typeBufferOffset); + length = (GLsizei *)getPointer(_env, length_buf, (jarray*)&_lengthArray, &_lengthRemaining, &_lengthBufferOffset); + size = (GLint *)getPointer(_env, size_buf, (jarray*)&_sizeArray, &_sizeRemaining, &_sizeBufferOffset); + type = (GLenum *)getPointer(_env, type_buf, (jarray*)&_typeArray, &_typeRemaining, &_typeBufferOffset); if (length == NULL) { - char * _lengthBase = (char *)_env->GetPrimitiveArrayCritical(_lengthArray, (jboolean *) 0); + char * _lengthBase = (char *)_env->GetIntArrayElements(_lengthArray, (jboolean *) 0); length = (GLsizei *) (_lengthBase + _lengthBufferOffset); } if (size == NULL) { - char * _sizeBase = (char *)_env->GetPrimitiveArrayCritical(_sizeArray, (jboolean *) 0); + char * _sizeBase = (char *)_env->GetIntArrayElements(_sizeArray, (jboolean *) 0); size = (GLint *) (_sizeBase + _sizeBufferOffset); } if (type == NULL) { - char * _typeBase = (char *)_env->GetPrimitiveArrayCritical(_typeArray, (jboolean *) 0); + char * _typeBase = (char *)_env->GetIntArrayElements(_typeArray, (jboolean *) 0); type = (GLenum *) (_typeBase + _typeBufferOffset); } glGetActiveUniform( @@ -160,13 +160,13 @@ android_glGetActiveUniform__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_n reinterpret_cast<char *>(name) ); if (_typeArray) { - releasePointer(_env, _typeArray, type, JNI_TRUE); + releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _typeArray, (jint*)type, JNI_TRUE); } if (_sizeArray) { - releasePointer(_env, _sizeArray, size, JNI_TRUE); + releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _sizeArray, (jint*)size, JNI_TRUE); } if (_lengthArray) { - releasePointer(_env, _lengthArray, length, JNI_TRUE); + releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _lengthArray, (jint*)length, JNI_TRUE); } } @@ -214,7 +214,7 @@ android_glGetActiveUniform1 } _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset; size_base = (GLint *) - _env->GetPrimitiveArrayCritical(size_ref, (jboolean *)0); + _env->GetIntArrayElements(size_ref, (jboolean *)0); size = size_base + sizeOffset; if (!type_ref) { @@ -231,7 +231,7 @@ android_glGetActiveUniform1 } _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset; type_base = (GLenum *) - _env->GetPrimitiveArrayCritical(type_ref, (jboolean *)0); + _env->GetIntArrayElements(type_ref, (jboolean *)0); type = type_base + typeOffset; glGetActiveUniform( @@ -246,11 +246,11 @@ android_glGetActiveUniform1 exit: if (type_base) { - _env->ReleasePrimitiveArrayCritical(type_ref, type_base, + _env->ReleaseIntArrayElements(type_ref, (jint*)type_base, _exception ? JNI_ABORT: 0); } if (size_base) { - _env->ReleasePrimitiveArrayCritical(size_ref, size_base, + _env->ReleaseIntArrayElements(size_ref, (jint*)size_base, _exception ? JNI_ABORT: 0); } if (_exception != 1) { @@ -272,9 +272,9 @@ exit: static jstring android_glGetActiveUniform2 (JNIEnv *_env, jobject _this, jint program, jint index, jobject size_buf, jobject type_buf) { - jarray _sizeArray = (jarray) 0; + jintArray _sizeArray = (jintArray) 0; jint _sizeBufferOffset = (jint) 0; - jarray _typeArray = (jarray) 0; + jintArray _typeArray = (jintArray) 0; jint _typeBufferOffset = (jint) 0; jint _sizeRemaining; GLint *size = (GLint *) 0; @@ -294,15 +294,15 @@ android_glGetActiveUniform2 return NULL; } - size = (GLint *)getPointer(_env, size_buf, &_sizeArray, &_sizeRemaining, &_sizeBufferOffset); - type = (GLenum *)getPointer(_env, type_buf, &_typeArray, &_typeRemaining, &_typeBufferOffset); + size = (GLint *)getPointer(_env, size_buf, (jarray*)&_sizeArray, &_sizeRemaining, &_sizeBufferOffset); + type = (GLenum *)getPointer(_env, type_buf, (jarray*)&_typeArray, &_typeRemaining, &_typeBufferOffset); if (size == NULL) { - char * _sizeBase = (char *)_env->GetPrimitiveArrayCritical(_sizeArray, (jboolean *) 0); + char * _sizeBase = (char *)_env->GetIntArrayElements(_sizeArray, (jboolean *) 0); size = (GLint *) (_sizeBase + _sizeBufferOffset); } if (type == NULL) { - char * _typeBase = (char *)_env->GetPrimitiveArrayCritical(_typeArray, (jboolean *) 0); + char * _typeBase = (char *)_env->GetIntArrayElements(_typeArray, (jboolean *) 0); type = (GLenum *) (_typeBase + _typeBufferOffset); } glGetActiveUniform( @@ -316,10 +316,10 @@ android_glGetActiveUniform2 ); if (_typeArray) { - releasePointer(_env, _typeArray, type, JNI_TRUE); + releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _typeArray, (jint*)type, JNI_TRUE); } if (_sizeArray) { - releasePointer(_env, _sizeArray, size, JNI_TRUE); + releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _sizeArray, (jint*)size, JNI_TRUE); } result = _env->NewStringUTF(buf); if (buf) { diff --git a/opengl/tools/glgen/stubs/gles11/glGetActiveUniformBlockName.cpp b/opengl/tools/glgen/stubs/gles11/glGetActiveUniformBlockName.cpp index bb6ae7ceae..6104c84e7d 100644 --- a/opengl/tools/glgen/stubs/gles11/glGetActiveUniformBlockName.cpp +++ b/opengl/tools/glgen/stubs/gles11/glGetActiveUniformBlockName.cpp @@ -25,7 +25,7 @@ android_glGetActiveUniformBlockName_III_3II_3BI goto exit; } _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset; - _length_base = (GLsizei*)_env->GetPrimitiveArrayCritical( + _length_base = (GLsizei*)_env->GetIntArrayElements( length_ref, (jboolean*)0); _length = _length_base + lengthOffset; @@ -42,7 +42,7 @@ android_glGetActiveUniformBlockName_III_3II_3BI goto exit; } _nameRemaining = _env->GetArrayLength(name_ref) - nameOffset; - _name_base = (GLchar*)_env->GetPrimitiveArrayCritical( + _name_base = (GLchar*)_env->GetByteArrayElements( name_ref, (jboolean*)0); _name = _name_base + nameOffset; @@ -56,11 +56,11 @@ android_glGetActiveUniformBlockName_III_3II_3BI exit: if (_name_base) { - _env->ReleasePrimitiveArrayCritical(name_ref, _name_base, + _env->ReleaseByteArrayElements(name_ref, (jbyte*)_name_base, _exception ? JNI_ABORT: 0); } if (_length_base) { - _env->ReleasePrimitiveArrayCritical(length_ref, _length_base, + _env->ReleaseIntArrayElements(length_ref, (jint*)_length_base, _exception ? JNI_ABORT: 0); } if (_exception) { @@ -124,4 +124,3 @@ android_glGetActiveUniformBlockName_II free(name); return result; } - diff --git a/opengl/tools/glgen/stubs/gles11/glGetBooleanv.cpp b/opengl/tools/glgen/stubs/gles11/glGetBooleanv.cpp index 00c52af150..7874bd8758 100644 --- a/opengl/tools/glgen/stubs/gles11/glGetBooleanv.cpp +++ b/opengl/tools/glgen/stubs/gles11/glGetBooleanv.cpp @@ -2,12 +2,14 @@ static void android_glGetBooleanv__I_3ZI (JNIEnv *_env, jobject _this, jint pname, jbooleanArray params_ref, jint offset) { - get<jbooleanArray, GLboolean, glGetBooleanv>(_env, _this, pname, params_ref, offset); + get<jbooleanArray, BooleanArrayGetter, jboolean*, BooleanArrayReleaser, GLboolean, glGetBooleanv>( + _env, _this, pname, params_ref, offset); } /* void glGetBooleanv ( GLenum pname, GLboolean *params ) */ static void android_glGetBooleanv__ILjava_nio_IntBuffer_2 (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) { - getarray<GLboolean, glGetBooleanv>(_env, _this, pname, params_buf); + getarray<GLboolean, jintArray, IntArrayGetter, jint*, IntArrayReleaser, glGetBooleanv>( + _env, _this, pname, params_buf); } diff --git a/opengl/tools/glgen/stubs/gles11/glGetFloatv.cpp b/opengl/tools/glgen/stubs/gles11/glGetFloatv.cpp index 71c399de20..2f41fd1cf8 100644 --- a/opengl/tools/glgen/stubs/gles11/glGetFloatv.cpp +++ b/opengl/tools/glgen/stubs/gles11/glGetFloatv.cpp @@ -2,12 +2,14 @@ static void android_glGetFloatv__I_3FI (JNIEnv *_env, jobject _this, jint pname, jfloatArray params_ref, jint offset) { - get<jfloatArray, GLfloat, glGetFloatv>(_env, _this, pname, params_ref, offset); + get<jfloatArray, FloatArrayGetter, jfloat*, FloatArrayReleaser, GLfloat, glGetFloatv>( + _env, _this, pname, params_ref, offset); } /* void glGetFloatv ( GLenum pname, GLfloat *params ) */ static void android_glGetFloatv__ILjava_nio_FloatBuffer_2 (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) { - getarray<GLfloat, glGetFloatv>(_env, _this, pname, params_buf); + getarray<GLfloat, jfloatArray, FloatArrayGetter, jfloat*, FloatArrayReleaser, glGetFloatv>( + _env, _this, pname, params_buf); } diff --git a/opengl/tools/glgen/stubs/gles11/glGetIntegerv.cpp b/opengl/tools/glgen/stubs/gles11/glGetIntegerv.cpp index 9000ece832..c960f31af3 100644 --- a/opengl/tools/glgen/stubs/gles11/glGetIntegerv.cpp +++ b/opengl/tools/glgen/stubs/gles11/glGetIntegerv.cpp @@ -2,13 +2,14 @@ static void android_glGetIntegerv__I_3II (JNIEnv *_env, jobject _this, jint pname, jintArray params_ref, jint offset) { - get<jintArray, GLint, glGetIntegerv>(_env, _this, pname, params_ref, offset); + get<jintArray, IntArrayGetter, jint*, IntArrayReleaser, GLint, glGetIntegerv>( + _env, _this, pname, params_ref, offset); } /* void glGetIntegerv ( GLenum pname, GLint *params ) */ static void android_glGetIntegerv__ILjava_nio_IntBuffer_2 (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) { - getarray<GLint, glGetIntegerv>(_env, _this, pname, params_buf); + getarray<GLint, jintArray, IntArrayGetter, jint*, IntArrayReleaser, glGetIntegerv>( + _env, _this, pname, params_buf); } - diff --git a/opengl/tools/glgen/stubs/gles11/glGetShaderSource.cpp b/opengl/tools/glgen/stubs/gles11/glGetShaderSource.cpp index c995d9cef3..d9808ef07a 100644 --- a/opengl/tools/glgen/stubs/gles11/glGetShaderSource.cpp +++ b/opengl/tools/glgen/stubs/gles11/glGetShaderSource.cpp @@ -26,7 +26,7 @@ android_glGetShaderSource__II_3II_3BI } _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset; length_base = (GLsizei *) - _env->GetPrimitiveArrayCritical(length_ref, (jboolean *)0); + _env->GetIntArrayElements(length_ref, (jboolean *)0); length = length_base + lengthOffset; if (!source_ref) { @@ -43,7 +43,7 @@ android_glGetShaderSource__II_3II_3BI } _sourceRemaining = _env->GetArrayLength(source_ref) - sourceOffset; source_base = (char *) - _env->GetPrimitiveArrayCritical(source_ref, (jboolean *)0); + _env->GetByteArrayElements(source_ref, (jboolean *)0); source = source_base + sourceOffset; glGetShaderSource( @@ -55,11 +55,11 @@ android_glGetShaderSource__II_3II_3BI exit: if (source_base) { - _env->ReleasePrimitiveArrayCritical(source_ref, source_base, + _env->ReleaseByteArrayElements(source_ref, (jbyte*)source_base, _exception ? JNI_ABORT: 0); } if (length_base) { - _env->ReleasePrimitiveArrayCritical(length_ref, length_base, + _env->ReleaseIntArrayElements(length_ref, (jint*)length_base, _exception ? JNI_ABORT: 0); } if (_exception) { @@ -71,14 +71,14 @@ exit: static void android_glGetShaderSource__IILjava_nio_IntBuffer_2B (JNIEnv *_env, jobject _this, jint shader, jint bufsize, jobject length_buf, jbyte source) { - jarray _array = (jarray) 0; + jintArray _array = (jintArray) 0; jint _bufferOffset = (jint) 0; jint _remaining; GLsizei *length = (GLsizei *) 0; - length = (GLsizei *)getPointer(_env, length_buf, &_array, &_remaining, &_bufferOffset); + length = (GLsizei *)getPointer(_env, length_buf, (jarray*)&_array, &_remaining, &_bufferOffset); if (length == NULL) { - char * _lengthBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0); + char * _lengthBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0); length = (GLsizei *) (_lengthBase + _bufferOffset); } glGetShaderSource( @@ -88,7 +88,7 @@ android_glGetShaderSource__IILjava_nio_IntBuffer_2B reinterpret_cast<char *>(source) ); if (_array) { - releasePointer(_env, _array, length, JNI_TRUE); + releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _array, (jint*)length, JNI_TRUE); } } diff --git a/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.cpp b/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.cpp index 0514fe9802..cb656c8068 100644 --- a/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.cpp +++ b/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.cpp @@ -32,7 +32,7 @@ android_glGetTransformFeedbackVarying__III_3II_3II_3II_3BI } _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset; length_base = (GLsizei *) - _env->GetPrimitiveArrayCritical(length_ref, (jboolean *)0); + _env->GetIntArrayElements(length_ref, (jboolean *)0); length = length_base + lengthOffset; if (!size_ref) { @@ -49,7 +49,7 @@ android_glGetTransformFeedbackVarying__III_3II_3II_3II_3BI } _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset; size_base = (GLint *) - _env->GetPrimitiveArrayCritical(size_ref, (jboolean *)0); + _env->GetIntArrayElements(size_ref, (jboolean *)0); size = size_base + sizeOffset; if (!type_ref) { @@ -66,7 +66,7 @@ android_glGetTransformFeedbackVarying__III_3II_3II_3II_3BI } _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset; type_base = (GLenum *) - _env->GetPrimitiveArrayCritical(type_ref, (jboolean *)0); + _env->GetIntArrayElements(type_ref, (jboolean *)0); type = type_base + typeOffset; if (!name_ref) { @@ -83,7 +83,7 @@ android_glGetTransformFeedbackVarying__III_3II_3II_3II_3BI } _nameRemaining = _env->GetArrayLength(name_ref) - nameOffset; name_base = (char *) - _env->GetPrimitiveArrayCritical(name_ref, (jboolean *)0); + _env->GetByteArrayElements(name_ref, (jboolean *)0); name = name_base + nameOffset; glGetTransformFeedbackVarying( @@ -98,19 +98,19 @@ android_glGetTransformFeedbackVarying__III_3II_3II_3II_3BI exit: if (name_base) { - _env->ReleasePrimitiveArrayCritical(name_ref, name_base, + _env->ReleaseByteArrayElements(name_ref, (jbyte*)name_base, _exception ? JNI_ABORT: 0); } if (type_base) { - _env->ReleasePrimitiveArrayCritical(type_ref, type_base, + _env->ReleaseIntArrayElements(type_ref, (jint*)type_base, _exception ? JNI_ABORT: 0); } if (size_base) { - _env->ReleasePrimitiveArrayCritical(size_ref, size_base, + _env->ReleaseIntArrayElements(size_ref, (jint*)size_base, _exception ? JNI_ABORT: 0); } if (length_base) { - _env->ReleasePrimitiveArrayCritical(length_ref, length_base, + _env->ReleaseIntArrayElements(length_ref, (jint*)length_base, _exception ? JNI_ABORT: 0); } if (_exception) { @@ -122,11 +122,11 @@ exit: static void android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jobject length_buf, jobject size_buf, jobject type_buf, jbyte name) { - jarray _lengthArray = (jarray) 0; + jintArray _lengthArray = (jintArray) 0; jint _lengthBufferOffset = (jint) 0; - jarray _sizeArray = (jarray) 0; + jintArray _sizeArray = (jintArray) 0; jint _sizeBufferOffset = (jint) 0; - jarray _typeArray = (jarray) 0; + jintArray _typeArray = (jintArray) 0; jint _typeBufferOffset = (jint) 0; jint _lengthRemaining; GLsizei *length = (GLsizei *) 0; @@ -135,19 +135,19 @@ android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuff jint _typeRemaining; GLenum *type = (GLenum *) 0; - length = (GLsizei *)getPointer(_env, length_buf, &_lengthArray, &_lengthRemaining, &_lengthBufferOffset); - size = (GLint *)getPointer(_env, size_buf, &_sizeArray, &_sizeRemaining, &_sizeBufferOffset); - type = (GLenum *)getPointer(_env, type_buf, &_typeArray, &_typeRemaining, &_typeBufferOffset); + length = (GLsizei *)getPointer(_env, length_buf, (jarray*)&_lengthArray, &_lengthRemaining, &_lengthBufferOffset); + size = (GLint *)getPointer(_env, size_buf, (jarray*)&_sizeArray, &_sizeRemaining, &_sizeBufferOffset); + type = (GLenum *)getPointer(_env, type_buf, (jarray*)&_typeArray, &_typeRemaining, &_typeBufferOffset); if (length == NULL) { - char * _lengthBase = (char *)_env->GetPrimitiveArrayCritical(_lengthArray, (jboolean *) 0); + char * _lengthBase = (char *)_env->GetIntArrayElements(_lengthArray, (jboolean *) 0); length = (GLsizei *) (_lengthBase + _lengthBufferOffset); } if (size == NULL) { - char * _sizeBase = (char *)_env->GetPrimitiveArrayCritical(_sizeArray, (jboolean *) 0); + char * _sizeBase = (char *)_env->GetIntArrayElements(_sizeArray, (jboolean *) 0); size = (GLint *) (_sizeBase + _sizeBufferOffset); } if (type == NULL) { - char * _typeBase = (char *)_env->GetPrimitiveArrayCritical(_typeArray, (jboolean *) 0); + char * _typeBase = (char *)_env->GetIntArrayElements(_typeArray, (jboolean *) 0); type = (GLenum *) (_typeBase + _typeBufferOffset); } glGetTransformFeedbackVarying( @@ -157,16 +157,20 @@ android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuff (GLsizei *)length, (GLint *)size, (GLenum *)type, - (char *)name + // The cast below is incorrect. The driver will end up writing to the + // address specified by name, which will always crash the process since + // it is guaranteed to be in low memory. The additional static_cast + // suppresses the warning for now. http://b/19478262 + (char *)static_cast<uintptr_t>(name) ); if (_typeArray) { - releasePointer(_env, _typeArray, type, JNI_TRUE); + releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _typeArray, (jint*)type, JNI_TRUE); } if (_sizeArray) { - releasePointer(_env, _sizeArray, size, JNI_TRUE); + releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _sizeArray, (jint*)size, JNI_TRUE); } if (_lengthArray) { - releasePointer(_env, _lengthArray, length, JNI_TRUE); + releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _lengthArray, (jint*)length, JNI_TRUE); } } @@ -211,7 +215,7 @@ android_glGetTransformFeedbackVarying1 } _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset; size_base = (GLint *) - _env->GetPrimitiveArrayCritical(size_ref, (jboolean *)0); + _env->GetIntArrayElements(size_ref, (jboolean *)0); size = size_base + sizeOffset; if (!type_ref) { @@ -228,7 +232,7 @@ android_glGetTransformFeedbackVarying1 } _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset; type_base = (GLenum *) - _env->GetPrimitiveArrayCritical(type_ref, (jboolean *)0); + _env->GetIntArrayElements(type_ref, (jboolean *)0); type = type_base + typeOffset; glGetTransformFeedbackVarying( @@ -242,11 +246,11 @@ android_glGetTransformFeedbackVarying1 ); exit: if (type_base) { - _env->ReleasePrimitiveArrayCritical(type_ref, type_base, + _env->ReleaseIntArrayElements(type_ref, (jint*)type_base, _exception ? JNI_ABORT: 0); } if (size_base) { - _env->ReleasePrimitiveArrayCritical(size_ref, size_base, + _env->ReleaseIntArrayElements(size_ref, (jint*)size_base, _exception ? JNI_ABORT: 0); } if (_exception != 1) { @@ -269,9 +273,9 @@ exit: static jstring android_glGetTransformFeedbackVarying2 (JNIEnv *_env, jobject _this, jint program, jint index, jobject size_buf, jobject type_buf) { - jarray _sizeArray = (jarray) 0; + jintArray _sizeArray = (jintArray) 0; jint _sizeBufferOffset = (jint) 0; - jarray _typeArray = (jarray) 0; + jintArray _typeArray = (jintArray) 0; jint _typeBufferOffset = (jint) 0; jint _lengthRemaining; GLsizei *length = (GLsizei *) 0; @@ -294,14 +298,14 @@ android_glGetTransformFeedbackVarying2 return NULL; } - size = (GLint *)getPointer(_env, size_buf, &_sizeArray, &_sizeRemaining, &_sizeBufferOffset); - type = (GLenum *)getPointer(_env, type_buf, &_typeArray, &_typeRemaining, &_typeBufferOffset); + size = (GLint *)getPointer(_env, size_buf, (jarray*)&_sizeArray, &_sizeRemaining, &_sizeBufferOffset); + type = (GLenum *)getPointer(_env, type_buf, (jarray*)&_typeArray, &_typeRemaining, &_typeBufferOffset); if (size == NULL) { - char * _sizeBase = (char *)_env->GetPrimitiveArrayCritical(_sizeArray, (jboolean *) 0); + char * _sizeBase = (char *)_env->GetIntArrayElements(_sizeArray, (jboolean *) 0); size = (GLint *) (_sizeBase + _sizeBufferOffset); } if (type == NULL) { - char * _typeBase = (char *)_env->GetPrimitiveArrayCritical(_typeArray, (jboolean *) 0); + char * _typeBase = (char *)_env->GetIntArrayElements(_typeArray, (jboolean *) 0); type = (GLenum *) (_typeBase + _typeBufferOffset); } glGetTransformFeedbackVarying( @@ -315,10 +319,10 @@ android_glGetTransformFeedbackVarying2 ); if (_typeArray) { - releasePointer(_env, _typeArray, type, JNI_TRUE); + releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _typeArray, (jint*)type, JNI_TRUE); } if (_sizeArray) { - releasePointer(_env, _sizeArray, size, JNI_TRUE); + releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _sizeArray, (jint*)size, JNI_TRUE); } result = _env->NewStringUTF(buf); if (buf) { diff --git a/opengl/tools/glgen/stubs/gles11/glGetUniformIndices.cpp b/opengl/tools/glgen/stubs/gles11/glGetUniformIndices.cpp index fb137ab4f7..13ef01e290 100644 --- a/opengl/tools/glgen/stubs/gles11/glGetUniformIndices.cpp +++ b/opengl/tools/glgen/stubs/gles11/glGetUniformIndices.cpp @@ -49,7 +49,7 @@ android_glGetUniformIndices_array _exceptionMessage = "not enough space in uniformIndices"; goto exit; } - _indices_base = (GLuint*)_env->GetPrimitiveArrayCritical( + _indices_base = (GLuint*)_env->GetIntArrayElements( uniformIndices_ref, 0); _indices = _indices_base + uniformIndicesOffset; @@ -57,8 +57,8 @@ android_glGetUniformIndices_array exit: if (_indices_base) { - _env->ReleasePrimitiveArrayCritical(uniformIndices_ref, _indices_base, - _exception ? JNI_ABORT : 0); + _env->ReleaseIntArrayElements(uniformIndices_ref, (jint*)_indices_base, + _exception ? JNI_ABORT : 0); } for (_i = _count - 1; _i >= 0; _i--) { if (_names[_i]) { @@ -85,7 +85,7 @@ android_glGetUniformIndices_buffer jint _count = 0; jint _i; const char** _names = NULL; - jarray _uniformIndicesArray = (jarray)0; + jintArray _uniformIndicesArray = (jintArray)0; jint _uniformIndicesRemaining; jint _uniformIndicesOffset = 0; GLuint* _indices = NULL; @@ -118,11 +118,11 @@ android_glGetUniformIndices_buffer } _indices = (GLuint*)getPointer(_env, uniformIndices_buf, - &_uniformIndicesArray, &_uniformIndicesRemaining, + (jarray*)&_uniformIndicesArray, &_uniformIndicesRemaining, &_uniformIndicesOffset); if (!_indices) { - _indicesBase = (char*)_env->GetPrimitiveArrayCritical( - _uniformIndicesArray, 0); + _indicesBase = (char*)_env->GetIntArrayElements( + _uniformIndicesArray, 0); _indices = (GLuint*)(_indicesBase + _uniformIndicesOffset); } if (_uniformIndicesRemaining < _count) { @@ -136,7 +136,8 @@ android_glGetUniformIndices_buffer exit: if (_uniformIndicesArray) { - releasePointer(_env, _uniformIndicesArray, _indicesBase, JNI_TRUE); + releaseArrayPointer<jintArray, jint*, IntArrayReleaser>( + _env, _uniformIndicesArray, (jint*)_indicesBase, JNI_TRUE); } for (_i = _count - 1; _i >= 0; _i--) { if (_names[_i]) { @@ -151,4 +152,3 @@ exit: jniThrowException(_env, _exceptionType, _exceptionMessage); } } - diff --git a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp index df11c53423..f5506baf95 100644 --- a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp +++ b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp @@ -16,6 +16,10 @@ // This source file is automatically generated +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-function" + #include "jni.h" #include "JNIHelp.h" #include <android_runtime/AndroidRuntime.h> diff --git a/opengl/tools/glgen2/glgen.py b/opengl/tools/glgen2/glgen.py index ed6b451f7b..9b30fd1307 100755 --- a/opengl/tools/glgen2/glgen.py +++ b/opengl/tools/glgen2/glgen.py @@ -86,11 +86,25 @@ def fmtTypeNameList(params): return ', '.join(['"%s", %s' % (p[0], p[1]) for p in params]) -def overrideSymbolName(sym): - # The wrapper intercepts glGetString and (sometimes) calls the generated - # __glGetString thunk which dispatches to the driver's glGetString - if sym == 'glGetString': - return '__glGetString' +def overrideSymbolName(sym, apiname): + # The wrapper intercepts various glGet and glGetString functions and + # (sometimes) calls the generated thunk which dispatches to the + # driver's implementation + wrapped_get_syms = { + 'gles1' : [ + 'glGetString' + ], + 'gles2' : [ + 'glGetString', + 'glGetStringi', + 'glGetBooleanv', + 'glGetFloatv', + 'glGetIntegerv', + 'glGetInteger64v', + ], + } + if sym in wrapped_get_syms.get(apiname): + return '__' + sym else: return sym @@ -115,8 +129,8 @@ class TrampolineGen(reg.OutputGenerator): print('%s API_ENTRY(%s)(%s) {\n' ' %s(%s%s%s);\n' '}' - % (rtype, overrideSymbolName(fname), fmtParams(params), - call, fname, + % (rtype, overrideSymbolName(fname, self.genOpts.apiname), + fmtParams(params), call, fname, ', ' if len(params) > 0 else '', fmtArgs(params)), file=self.outFile) diff --git a/services/batteryservice/Android.mk b/services/batteryservice/Android.mk index 9354b99ae8..e4097d7104 100644 --- a/services/batteryservice/Android.mk +++ b/services/batteryservice/Android.mk @@ -2,17 +2,19 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ - BatteryProperties.cpp \ - BatteryProperty.cpp \ - IBatteryPropertiesListener.cpp \ - IBatteryPropertiesRegistrar.cpp + BatteryProperties.cpp \ + BatteryProperty.cpp \ + IBatteryPropertiesListener.cpp \ + IBatteryPropertiesRegistrar.cpp LOCAL_STATIC_LIBRARIES := \ - libutils \ - libbinder + libutils \ + libbinder LOCAL_MODULE:= libbatteryservice LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code + include $(BUILD_STATIC_LIBRARY) diff --git a/services/batteryservice/IBatteryPropertiesListener.cpp b/services/batteryservice/IBatteryPropertiesListener.cpp index 19ac7f0ecd..8aff26c4c8 100644 --- a/services/batteryservice/IBatteryPropertiesListener.cpp +++ b/services/batteryservice/IBatteryPropertiesListener.cpp @@ -35,7 +35,7 @@ public: data.writeInterfaceToken(IBatteryPropertiesListener::getInterfaceDescriptor()); data.writeInt32(1); props.writeToParcel(&data); - status_t err = remote()->transact(TRANSACT_BATTERYPROPERTIESCHANGED, data, &reply, IBinder::FLAG_ONEWAY); + remote()->transact(TRANSACT_BATTERYPROPERTIESCHANGED, data, &reply, IBinder::FLAG_ONEWAY); } }; diff --git a/services/batteryservice/IBatteryPropertiesRegistrar.cpp b/services/batteryservice/IBatteryPropertiesRegistrar.cpp index 296bfab08c..46934e04e1 100644 --- a/services/batteryservice/IBatteryPropertiesRegistrar.cpp +++ b/services/batteryservice/IBatteryPropertiesRegistrar.cpp @@ -34,14 +34,14 @@ public: void registerListener(const sp<IBatteryPropertiesListener>& listener) { Parcel data; data.writeInterfaceToken(IBatteryPropertiesRegistrar::getInterfaceDescriptor()); - data.writeStrongBinder(listener->asBinder()); + data.writeStrongBinder(IInterface::asBinder(listener)); remote()->transact(REGISTER_LISTENER, data, NULL); } void unregisterListener(const sp<IBatteryPropertiesListener>& listener) { Parcel data; data.writeInterfaceToken(IBatteryPropertiesRegistrar::getInterfaceDescriptor()); - data.writeStrongBinder(listener->asBinder()); + data.writeStrongBinder(IInterface::asBinder(listener)); remote()->transact(UNREGISTER_LISTENER, data, NULL); } diff --git a/services/inputflinger/Android.mk b/services/inputflinger/Android.mk index 85edbe5db4..ed867d8441 100644 --- a/services/inputflinger/Android.mk +++ b/services/inputflinger/Android.mk @@ -31,16 +31,13 @@ LOCAL_SHARED_LIBRARIES := \ libinput \ liblog \ libutils \ - libui \ - libhardware_legacy + libui \ + libhardware_legacy # TODO: Move inputflinger to its own process and mark it hidden #LOCAL_CFLAGS += -fvisibility=hidden -LOCAL_C_INCLUDES := \ - external/openssl/include \ - LOCAL_CFLAGS += -Wno-unused-parameter LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) @@ -48,3 +45,5 @@ LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) LOCAL_MODULE := libinputflinger include $(BUILD_SHARED_LIBRARY) + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp index dfe5d3de60..6b60c7cf71 100644 --- a/services/inputflinger/EventHub.cpp +++ b/services/inputflinger/EventHub.cpp @@ -131,6 +131,13 @@ uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses) { } } + // External stylus gets the pressure axis + if (deviceClasses & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { + if (axis == ABS_PRESSURE) { + return INPUT_DEVICE_CLASS_EXTERNAL_STYLUS; + } + } + // Joystick devices get the rest. return deviceClasses & INPUT_DEVICE_CLASS_JOYSTICK; } @@ -858,7 +865,6 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz int(iev.time.tv_sec), int(iev.time.tv_usec)); } -#ifdef HAVE_POSIX_CLOCKS // Use the time specified in the event instead of the current time // so that downstream code can get more accurate estimates of // event dispatch latency from the time the event is enqueued onto @@ -909,9 +915,6 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz event->when, time, now); } } -#else - event->when = now; -#endif event->deviceId = deviceId; event->type = iev.type; event->code = iev.code; @@ -1189,6 +1192,16 @@ status_t EventHub::openDeviceLocked(const char *devicePath) { && test_bit(ABS_X, device->absBitmask) && test_bit(ABS_Y, device->absBitmask)) { device->classes |= INPUT_DEVICE_CLASS_TOUCH; + // Is this a BT stylus? + } else if ((test_bit(ABS_PRESSURE, device->absBitmask) || + test_bit(BTN_TOUCH, device->keyBitmask)) + && !test_bit(ABS_X, device->absBitmask) + && !test_bit(ABS_Y, device->absBitmask)) { + device->classes |= INPUT_DEVICE_CLASS_EXTERNAL_STYLUS; + // Keyboard will try to claim some of the buttons but we really want to reserve those so we + // can fuse it with the touch screen data, so just take them back. Note this means an + // external stylus cannot also be a keyboard device. + device->classes &= ~INPUT_DEVICE_CLASS_KEYBOARD; } // See if this device is a joystick. @@ -1283,6 +1296,11 @@ status_t EventHub::openDeviceLocked(const char *devicePath) { return -1; } + // Determine whether the device has a mic. + if (deviceHasMicLocked(device)) { + device->classes |= INPUT_DEVICE_CLASS_MIC; + } + // Determine whether the device is external or internal. if (isExternalDeviceLocked(device)) { device->classes |= INPUT_DEVICE_CLASS_EXTERNAL; @@ -1297,7 +1315,10 @@ status_t EventHub::openDeviceLocked(const char *devicePath) { // Register with epoll. struct epoll_event eventItem; memset(&eventItem, 0, sizeof(eventItem)); - eventItem.events = mUsingEpollWakeup ? EPOLLIN : EPOLLIN | EPOLLWAKEUP; + eventItem.events = EPOLLIN; + if (mUsingEpollWakeup) { + eventItem.events |= EPOLLWAKEUP; + } eventItem.data.u32 = deviceId; if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) { ALOGE("Could not add device fd to epoll instance. errno=%d", errno); @@ -1416,6 +1437,16 @@ bool EventHub::isExternalDeviceLocked(Device* device) { return device->identifier.bus == BUS_USB || device->identifier.bus == BUS_BLUETOOTH; } +bool EventHub::deviceHasMicLocked(Device* device) { + if (device->configuration) { + bool value; + if (device->configuration->tryGetProperty(String8("audio.mic"), value)) { + return value; + } + } + return false; +} + int32_t EventHub::getNextControllerNumberLocked(Device* device) { if (mControllerNumbers.isFull()) { ALOGI("Maximum number of controllers reached, assigning controller number 0 to device %s", @@ -1443,7 +1474,7 @@ void EventHub::setLedForController(Device* device) { } bool EventHub::hasKeycodeLocked(Device* device, int keycode) const { - if (!device->keyMap.haveKeyLayout() || !device->keyBitmask) { + if (!device->keyMap.haveKeyLayout()) { return false; } @@ -1461,7 +1492,7 @@ bool EventHub::hasKeycodeLocked(Device* device, int keycode) const { } status_t EventHub::mapLed(Device* device, int32_t led, int32_t* outScanCode) const { - if (!device->keyMap.haveKeyLayout() || !device->ledBitmask) { + if (!device->keyMap.haveKeyLayout()) { return NAME_NOT_FOUND; } diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h index 20179aef22..3ec49105c0 100644 --- a/services/inputflinger/EventHub.h +++ b/services/inputflinger/EventHub.h @@ -131,6 +131,12 @@ enum { /* The input device has a vibrator (supports FF_RUMBLE). */ INPUT_DEVICE_CLASS_VIBRATOR = 0x00000200, + /* The input device has a microphone. */ + INPUT_DEVICE_CLASS_MIC = 0x00000400, + + /* The input device is an external stylus (has data we want to fuse with touch data). */ + INPUT_DEVICE_CLASS_EXTERNAL_STYLUS = 0x00000800, + /* The input device is virtual (not a real device, not part of UI configuration). */ INPUT_DEVICE_CLASS_VIRTUAL = 0x40000000, @@ -394,6 +400,7 @@ private: status_t loadKeyMapLocked(Device* device); bool isExternalDeviceLocked(Device* device); + bool deviceHasMicLocked(Device* device); int32_t getNextControllerNumberLocked(Device* device); void releaseControllerNumberLocked(Device* device); diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp index 603836a5ab..c9e876fd29 100644 --- a/services/inputflinger/InputDispatcher.cpp +++ b/services/inputflinger/InputDispatcher.cpp @@ -119,7 +119,7 @@ static bool validateKeyEvent(int32_t action) { return true; } -static bool isValidMotionAction(int32_t action, size_t pointerCount) { +static bool isValidMotionAction(int32_t action, int32_t actionButton, int32_t pointerCount) { switch (action & AMOTION_EVENT_ACTION_MASK) { case AMOTION_EVENT_ACTION_DOWN: case AMOTION_EVENT_ACTION_UP: @@ -136,14 +136,17 @@ static bool isValidMotionAction(int32_t action, size_t pointerCount) { int32_t index = getMotionEventActionPointerIndex(action); return index >= 0 && size_t(index) < pointerCount; } + case AMOTION_EVENT_ACTION_BUTTON_PRESS: + case AMOTION_EVENT_ACTION_BUTTON_RELEASE: + return actionButton != 0; default: return false; } } -static bool validateMotionEvent(int32_t action, size_t pointerCount, +static bool validateMotionEvent(int32_t action, int32_t actionButton, size_t pointerCount, const PointerProperties* pointerProperties) { - if (! isValidMotionAction(action, pointerCount)) { + if (! isValidMotionAction(action, actionButton, pointerCount)) { ALOGE("Motion event has invalid action code 0x%x", action); return false; } @@ -198,7 +201,8 @@ static void dumpRegion(String8& dump, const Region& region) { InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) : mPolicy(policy), - mPendingEvent(NULL), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX), + mPendingEvent(NULL), mLastDropReason(DROP_REASON_NOT_DROPPED), + mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX), mNextUnblockedEvent(NULL), mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false), mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) { @@ -394,6 +398,7 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { if (dropReason != DROP_REASON_NOT_DROPPED) { dropInboundEventLocked(mPendingEvent, dropReason); } + mLastDropReason = dropReason; releasePendingEventLocked(); *nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately @@ -503,7 +508,9 @@ void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropR reason = "inbound event was dropped because the policy consumed it"; break; case DROP_REASON_DISABLED: - ALOGI("Dropped event because input dispatch is disabled."); + if (mLastDropReason != DROP_REASON_DISABLED) { + ALOGI("Dropped event because input dispatch is disabled."); + } reason = "inbound event was dropped because input dispatch is disabled"; break; case DROP_REASON_APP_SWITCH: @@ -852,6 +859,13 @@ bool InputDispatcher::dispatchMotionLocked( setInjectionResultLocked(entry, injectionResult); if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) { + if (injectionResult != INPUT_EVENT_INJECTION_PERMISSION_DENIED) { + CancelationOptions::Mode mode(isPointerEvent ? + CancelationOptions::CANCEL_POINTER_EVENTS : + CancelationOptions::CANCEL_NON_POINTER_EVENTS); + CancelationOptions options(mode, "input event injection failed"); + synthesizeCancelationEventsForMonitorsLocked(options); + } return true; } @@ -874,12 +888,12 @@ bool InputDispatcher::dispatchMotionLocked( void InputDispatcher::logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " - "action=0x%x, flags=0x%x, " - "metaState=0x%x, buttonState=0x%x, " + "action=0x%x, actionButton=0x%x, flags=0x%x, " + "metaState=0x%x, buttonState=0x%x," "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld", prefix, entry->eventTime, entry->deviceId, entry->source, entry->policyFlags, - entry->action, entry->flags, + entry->action, entry->actionButton, entry->flags, entry->metaState, entry->buttonState, entry->edgeFlags, entry->xPrecision, entry->yPrecision, entry->downTime); @@ -1211,6 +1225,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, 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( @@ -1248,6 +1264,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, } if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) { targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; + } else if (isWindowObscuredLocked(newTouchedWindowHandle)) { + targetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED; } // Update hover state. @@ -1423,6 +1441,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, == InputWindowInfo::TYPE_WALLPAPER) { mTempTouchState.addOrUpdateWindow(windowHandle, InputTarget::FLAG_WINDOW_IS_OBSCURED + | InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0)); } @@ -1617,6 +1636,27 @@ bool InputDispatcher::isWindowObscuredAtPointLocked( return false; } + +bool InputDispatcher::isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const { + int32_t displayId = windowHandle->getInfo()->displayId; + const InputWindowInfo* windowInfo = windowHandle->getInfo(); + size_t numWindows = mWindowHandles.size(); + for (size_t i = 0; i < numWindows; i++) { + sp<InputWindowHandle> otherHandle = mWindowHandles.itemAt(i); + if (otherHandle == windowHandle) { + break; + } + + const InputWindowInfo* otherInfo = otherHandle->getInfo(); + if (otherInfo->displayId == displayId + && otherInfo->visible && !otherInfo->isTrustedOverlay() + && otherInfo->overlaps(windowInfo)) { + return true; + } + } + return false; +} + String8 InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentTime, const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry, const char* targetType) { @@ -1891,6 +1931,9 @@ void InputDispatcher::enqueueDispatchEntryLocked( if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) { dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED; } + if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED) { + dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; + } if (!connection->inputState.trackMotion(motionEntry, dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) { @@ -1981,10 +2024,10 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, // Publish the motion event. status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq, motionEntry->deviceId, motionEntry->source, - dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags, - motionEntry->edgeFlags, motionEntry->metaState, motionEntry->buttonState, - xOffset, yOffset, - motionEntry->xPrecision, motionEntry->yPrecision, + dispatchEntry->resolvedAction, motionEntry->actionButton, + dispatchEntry->resolvedFlags, motionEntry->edgeFlags, + motionEntry->metaState, motionEntry->buttonState, + xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision, motionEntry->downTime, motionEntry->eventTime, motionEntry->pointerCount, motionEntry->pointerProperties, usingCoords); @@ -2160,6 +2203,13 @@ void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked( } } +void InputDispatcher::synthesizeCancelationEventsForMonitorsLocked( + const CancelationOptions& options) { + for (size_t i = 0; i < mMonitoringChannels.size(); i++) { + synthesizeCancelationEventsForInputChannelLocked(mMonitoringChannels[i], options); + } +} + void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked( const sp<InputChannel>& channel, const CancelationOptions& options) { ssize_t index = getConnectionIndexLocked(channel); @@ -2298,6 +2348,7 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet originalMotionEntry->source, originalMotionEntry->policyFlags, action, + originalMotionEntry->actionButton, originalMotionEntry->flags, originalMotionEntry->metaState, originalMotionEntry->buttonState, @@ -2432,10 +2483,10 @@ bool InputDispatcher::shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS ALOGD("notifyMotion - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " - "action=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, edgeFlags=0x%x, " - "xPrecision=%f, yPrecision=%f, downTime=%lld", + "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x," + "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld", args->eventTime, args->deviceId, args->source, args->policyFlags, - args->action, args->flags, args->metaState, args->buttonState, + args->action, args->actionButton, args->flags, args->metaState, args->buttonState, args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime); for (uint32_t i = 0; i < args->pointerCount; i++) { ALOGD(" Pointer %d: id=%d, toolType=%d, " @@ -2455,7 +2506,8 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); } #endif - if (!validateMotionEvent(args->action, args->pointerCount, args->pointerProperties)) { + if (!validateMotionEvent(args->action, args->actionButton, + args->pointerCount, args->pointerProperties)) { return; } @@ -2471,9 +2523,9 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { mLock.unlock(); MotionEvent event; - event.initialize(args->deviceId, args->source, args->action, args->flags, - args->edgeFlags, args->metaState, args->buttonState, 0, 0, - args->xPrecision, args->yPrecision, + event.initialize(args->deviceId, args->source, args->action, args->actionButton, + args->flags, args->edgeFlags, args->metaState, args->buttonState, + 0, 0, args->xPrecision, args->yPrecision, args->downTime, args->eventTime, args->pointerCount, args->pointerProperties, args->pointerCoords); @@ -2488,7 +2540,8 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { // Just enqueue a new motion event. MotionEntry* newEntry = new MotionEntry(args->eventTime, args->deviceId, args->source, policyFlags, - args->action, args->flags, args->metaState, args->buttonState, + args->action, args->actionButton, args->flags, + args->metaState, args->buttonState, args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime, args->displayId, args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0); @@ -2589,7 +2642,8 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t displ int32_t action = motionEvent->getAction(); size_t pointerCount = motionEvent->getPointerCount(); const PointerProperties* pointerProperties = motionEvent->getPointerProperties(); - if (! validateMotionEvent(action, pointerCount, pointerProperties)) { + int32_t actionButton = motionEvent->getActionButton(); + if (! validateMotionEvent(action, actionButton, pointerCount, pointerProperties)) { return INPUT_EVENT_INJECTION_FAILED; } @@ -2603,7 +2657,7 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t displ const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords(); firstInjectedEntry = new MotionEntry(*sampleEventTimes, motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags, - action, motionEvent->getFlags(), + action, actionButton, motionEvent->getFlags(), motionEvent->getMetaState(), motionEvent->getButtonState(), motionEvent->getEdgeFlags(), motionEvent->getXPrecision(), motionEvent->getYPrecision(), @@ -2616,7 +2670,7 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t displ samplePointerCoords += pointerCount; MotionEntry* nextInjectedEntry = new MotionEntry(*sampleEventTimes, motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags, - action, motionEvent->getFlags(), + action, actionButton, motionEvent->getFlags(), motionEvent->getMetaState(), motionEvent->getButtonState(), motionEvent->getEdgeFlags(), motionEvent->getXPrecision(), motionEvent->getYPrecision(), @@ -3789,18 +3843,6 @@ void InputDispatcher::monitor() { } -// --- InputDispatcher::Queue --- - -template <typename T> -uint32_t InputDispatcher::Queue<T>::count() const { - uint32_t result = 0; - for (const T* entry = head; entry; entry = entry->next) { - result += 1; - } - return result; -} - - // --- InputDispatcher::InjectionState --- InputDispatcher::InjectionState::InjectionState(int32_t injectorPid, int32_t injectorUid) : @@ -3919,18 +3961,18 @@ void InputDispatcher::KeyEntry::recycle() { // --- InputDispatcher::MotionEntry --- -InputDispatcher::MotionEntry::MotionEntry(nsecs_t eventTime, - int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags, - int32_t metaState, int32_t buttonState, - int32_t edgeFlags, float xPrecision, float yPrecision, - nsecs_t downTime, int32_t displayId, uint32_t pointerCount, +InputDispatcher::MotionEntry::MotionEntry(nsecs_t eventTime, int32_t deviceId, + uint32_t source, uint32_t policyFlags, int32_t action, int32_t actionButton, + int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, + float xPrecision, float yPrecision, nsecs_t downTime, + int32_t displayId, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, float xOffset, float yOffset) : EventEntry(TYPE_MOTION, eventTime, policyFlags), eventTime(eventTime), - deviceId(deviceId), source(source), action(action), flags(flags), - metaState(metaState), buttonState(buttonState), edgeFlags(edgeFlags), - xPrecision(xPrecision), yPrecision(yPrecision), + deviceId(deviceId), source(source), action(action), actionButton(actionButton), + flags(flags), metaState(metaState), buttonState(buttonState), + edgeFlags(edgeFlags), xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime), displayId(displayId), pointerCount(pointerCount) { for (uint32_t i = 0; i < pointerCount; i++) { this->pointerProperties[i].copyFrom(pointerProperties[i]); @@ -3945,10 +3987,10 @@ InputDispatcher::MotionEntry::~MotionEntry() { } void InputDispatcher::MotionEntry::appendDescription(String8& msg) const { - msg.appendFormat("MotionEvent(deviceId=%d, source=0x%08x, action=%d, " - "flags=0x%08x, metaState=0x%08x, buttonState=0x%08x, edgeFlags=0x%08x, " - "xPrecision=%.1f, yPrecision=%.1f, displayId=%d, pointers=[", - deviceId, source, action, flags, metaState, buttonState, edgeFlags, + msg.appendFormat("MotionEvent(deviceId=%d, source=0x%08x, action=%d, actionButton=0x%08x, " + "flags=0x%08x, metaState=0x%08x, buttonState=0x%08x, " + "edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, displayId=%d, pointers=[", + deviceId, source, action, actionButton, flags, metaState, buttonState, edgeFlags, xPrecision, yPrecision, displayId); for (uint32_t i = 0; i < pointerCount; i++) { if (i) { @@ -4249,7 +4291,7 @@ void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTim memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT : AMOTION_EVENT_ACTION_CANCEL, - memento.flags, 0, 0, 0, + memento.flags, 0, 0, 0, 0, memento.xPrecision, memento.yPrecision, memento.downTime, memento.displayId, memento.pointerCount, memento.pointerProperties, memento.pointerCoords, diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h index 70b0a34b0a..1c054f5ce0 100644 --- a/services/inputflinger/InputDispatcher.h +++ b/services/inputflinger/InputDispatcher.h @@ -89,7 +89,7 @@ struct InputTarget { /* This flag indicates that the event is being delivered to a foreground application. */ FLAG_FOREGROUND = 1 << 0, - /* This flag indicates that the target of a MotionEvent is partly or wholly + /* This flag indicates that the MotionEvent falls within the area of the target * obscured by another visible window above it. The motion event should be * delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */ FLAG_WINDOW_IS_OBSCURED = 1 << 1, @@ -139,6 +139,12 @@ struct InputTarget { | FLAG_DISPATCH_AS_HOVER_EXIT | FLAG_DISPATCH_AS_SLIPPERY_EXIT | FLAG_DISPATCH_AS_SLIPPERY_ENTER, + + /* This flag indicates that the target of a MotionEvent is partly or wholly + * obscured by another visible window above it. The motion event should be + * delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED. */ + FLAG_WINDOW_IS_PARTIALLY_OBSCURED = 1 << 14, + }; // The input channel to be targeted. @@ -504,6 +510,7 @@ private: int32_t deviceId; uint32_t source; int32_t action; + int32_t actionButton; int32_t flags; int32_t metaState; int32_t buttonState; @@ -518,10 +525,10 @@ private: MotionEntry(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, - int32_t action, int32_t flags, + int32_t action, int32_t actionButton, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, - float xPrecision, float yPrecision, - nsecs_t downTime, int32_t displayId, uint32_t pointerCount, + float xPrecision, float yPrecision, nsecs_t downTime, + int32_t displayId, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, float xOffset, float yOffset); virtual void appendDescription(String8& msg) const; @@ -606,8 +613,9 @@ private: struct Queue { T* head; T* tail; + uint32_t entryCount; - inline Queue() : head(NULL), tail(NULL) { + inline Queue() : head(NULL), tail(NULL), entryCount(0) { } inline bool isEmpty() const { @@ -615,6 +623,7 @@ private: } inline void enqueueAtTail(T* entry) { + entryCount++; entry->prev = tail; if (tail) { tail->next = entry; @@ -626,6 +635,7 @@ private: } inline void enqueueAtHead(T* entry) { + entryCount++; entry->next = head; if (head) { head->prev = entry; @@ -637,6 +647,7 @@ private: } inline void dequeue(T* entry) { + entryCount--; if (entry->prev) { entry->prev->next = entry->next; } else { @@ -650,6 +661,7 @@ private: } inline T* dequeueAtHead() { + entryCount--; T* entry = head; head = entry->next; if (head) { @@ -660,7 +672,9 @@ private: return entry; } - uint32_t count() const; + uint32_t count() const { + return entryCount; + } }; /* Specifies which events are to be canceled and why. */ @@ -849,6 +863,8 @@ private: Queue<EventEntry> mRecentQueue; Queue<CommandEntry> mCommandQueue; + DropReason mLastDropReason; + void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime); // Enqueues an inbound event. Returns true if mLooper->wake() should be called. @@ -1038,6 +1054,7 @@ private: const InjectionState* injectionState); bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle, int32_t x, int32_t y) const; + bool isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const; String8 getApplicationWindowLabelLocked(const sp<InputApplicationHandle>& applicationHandle, const sp<InputWindowHandle>& windowHandle); @@ -1066,6 +1083,7 @@ private: void synthesizeCancelationEventsForAllConnectionsLocked( const CancelationOptions& options); + void synthesizeCancelationEventsForMonitorsLocked(const CancelationOptions& options); void synthesizeCancelationEventsForInputChannelLocked(const sp<InputChannel>& channel, const CancelationOptions& options); void synthesizeCancelationEventsForConnectionLocked(const sp<Connection>& connection, diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp index 85bb0ed524..dded47dc88 100644 --- a/services/inputflinger/InputListener.cpp +++ b/services/inputflinger/InputListener.cpp @@ -68,12 +68,13 @@ void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const { NotifyMotionArgs::NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, - int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, - int32_t edgeFlags, int32_t displayId, uint32_t pointerCount, + int32_t action, int32_t actionButton, int32_t flags, int32_t metaState, + int32_t buttonState, int32_t edgeFlags, int32_t displayId, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, float xPrecision, float yPrecision, nsecs_t downTime) : eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags), - action(action), flags(flags), metaState(metaState), buttonState(buttonState), + action(action), actionButton(actionButton), + flags(flags), metaState(metaState), buttonState(buttonState), edgeFlags(edgeFlags), displayId(displayId), pointerCount(pointerCount), xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime) { for (uint32_t i = 0; i < pointerCount; i++) { @@ -85,10 +86,9 @@ NotifyMotionArgs::NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other) : eventTime(other.eventTime), deviceId(other.deviceId), source(other.source), policyFlags(other.policyFlags), - action(other.action), flags(other.flags), + action(other.action), actionButton(other.actionButton), flags(other.flags), metaState(other.metaState), buttonState(other.buttonState), - edgeFlags(other.edgeFlags), displayId(other.displayId), - pointerCount(other.pointerCount), + edgeFlags(other.edgeFlags), displayId(other.displayId), pointerCount(other.pointerCount), xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime) { for (uint32_t i = 0; i < pointerCount; i++) { pointerProperties[i].copyFrom(other.pointerProperties[i]); diff --git a/services/inputflinger/InputListener.h b/services/inputflinger/InputListener.h index 78ae10f70d..1ec09ce4b5 100644 --- a/services/inputflinger/InputListener.h +++ b/services/inputflinger/InputListener.h @@ -84,6 +84,7 @@ struct NotifyMotionArgs : public NotifyArgs { uint32_t source; uint32_t policyFlags; int32_t action; + int32_t actionButton; int32_t flags; int32_t metaState; int32_t buttonState; @@ -99,7 +100,8 @@ struct NotifyMotionArgs : public NotifyArgs { inline NotifyMotionArgs() { } NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, - int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, + int32_t action, int32_t actionButton, int32_t flags, + int32_t metaState, int32_t buttonState, int32_t edgeFlags, int32_t displayId, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, float xPrecision, float yPrecision, nsecs_t downTime); diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp index 8634e4272a..bd74b026e0 100644 --- a/services/inputflinger/InputReader.cpp +++ b/services/inputflinger/InputReader.cpp @@ -39,12 +39,16 @@ // Log debug messages about the vibrator. #define DEBUG_VIBRATOR 0 +// Log debug messages about fusing stylus data. +#define DEBUG_STYLUS_FUSION 0 + #include "InputReader.h" #include <cutils/log.h> #include <input/Keyboard.h> #include <input/VirtualKeyMap.h> +#include <inttypes.h> #include <stddef.h> #include <stdlib.h> #include <unistd.h> @@ -65,6 +69,17 @@ namespace android { // Maximum number of slots supported when using the slot-based Multitouch Protocol B. static const size_t MAX_SLOTS = 32; +// Maximum amount of latency to add to touch events while waiting for data from an +// external stylus. +static const nsecs_t EXTERNAL_STYLUS_DATA_TIMEOUT = ms2ns(72); + +// Maximum amount of time to wait on touch data before pushing out new pressure data. +static const nsecs_t TOUCH_DATA_TIMEOUT = ms2ns(20); + +// Artificial latency on synthetic events created from stylus data without corresponding touch +// data. +static const nsecs_t STYLUS_DATA_LATENCY = ms2ns(10); + // --- Static Functions --- template<typename T> @@ -381,6 +396,10 @@ void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) { mDevices.add(deviceId, device); bumpGenerationLocked(); + + if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { + notifyExternalStylusPresenceChanged(); + } } void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) { @@ -403,6 +422,10 @@ void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) { device->getId(), device->getName().string(), device->getSources()); } + if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { + notifyExternalStylusPresenceChanged(); + } + device->reset(when); delete device; } @@ -417,6 +440,11 @@ InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controlle device->setExternal(true); } + // Devices with mics. + if (classes & INPUT_DEVICE_CLASS_MIC) { + device->setMic(true); + } + // Switch-like devices. if (classes & INPUT_DEVICE_CLASS_SWITCH) { device->addMapper(new SwitchInputMapper(device)); @@ -464,6 +492,11 @@ InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controlle device->addMapper(new JoystickInputMapper(device)); } + // External stylus-like devices. + if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { + device->addMapper(new ExternalStylusInputMapper(device)); + } + return device; } @@ -534,6 +567,27 @@ int32_t InputReader::getGlobalMetaStateLocked() { return mGlobalMetaState; } +void InputReader::notifyExternalStylusPresenceChanged() { + refreshConfigurationLocked(InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE); +} + +void InputReader::getExternalStylusDevicesLocked(Vector<InputDeviceInfo>& outDevices) { + for (size_t i = 0; i < mDevices.size(); i++) { + InputDevice* device = mDevices.valueAt(i); + if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS && !device->isIgnored()) { + outDevices.push(); + device->getDeviceInfo(&outDevices.editTop()); + } + } +} + +void InputReader::dispatchExternalStylusState(const StylusState& state) { + for (size_t i = 0; i < mDevices.size(); i++) { + InputDevice* device = mDevices.valueAt(i); + device->updateExternalStylusState(state); + } +} + void InputReader::disableVirtualKeysUntilLocked(nsecs_t time) { mDisableVirtualKeysTimeout = time; } @@ -824,6 +878,15 @@ int32_t InputReader::ContextImpl::bumpGeneration() { return mReader->bumpGenerationLocked(); } +void InputReader::ContextImpl::getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices) { + // lock is already held by whatever called refreshConfigurationLocked + mReader->getExternalStylusDevicesLocked(outDevices); +} + +void InputReader::ContextImpl::dispatchExternalStylusState(const StylusState& state) { + mReader->dispatchExternalStylusState(state); +} + InputReaderPolicyInterface* InputReader::ContextImpl::getPolicy() { return mReader->mPolicy.get(); } @@ -858,7 +921,7 @@ InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t genera int32_t controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes) : mContext(context), mId(id), mGeneration(generation), mControllerNumber(controllerNumber), mIdentifier(identifier), mClasses(classes), - mSources(0), mIsExternal(false), mDropUntilNextSync(false) { + mSources(0), mIsExternal(false), mHasMic(false), mDropUntilNextSync(false) { } InputDevice::~InputDevice() { @@ -877,6 +940,7 @@ void InputDevice::dump(String8& dump) { deviceInfo.getDisplayName().string()); dump.appendFormat(INDENT2 "Generation: %d\n", mGeneration); dump.appendFormat(INDENT2 "IsExternal: %s\n", toString(mIsExternal)); + dump.appendFormat(INDENT2 "HasMic: %s\n", toString(mHasMic)); dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources()); dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType()); @@ -1006,10 +1070,17 @@ void InputDevice::timeoutExpired(nsecs_t when) { } } +void InputDevice::updateExternalStylusState(const StylusState& state) { + size_t numMappers = mMappers.size(); + for (size_t i = 0; i < numMappers; i++) { + InputMapper* mapper = mMappers[i]; + mapper->updateExternalStylusState(state); + } +} + void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) { outDeviceInfo->initialize(mId, mGeneration, mControllerNumber, mIdentifier, mAlias, - mIsExternal); - + mIsExternal, mHasMic); size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; @@ -1078,6 +1149,14 @@ void InputDevice::cancelVibrate(int32_t token) { } } +void InputDevice::cancelTouch(nsecs_t when) { + size_t numMappers = mMappers.size(); + for (size_t i = 0; i < numMappers; i++) { + InputMapper* mapper = mMappers[i]; + mapper->cancelTouch(when); + } +} + int32_t InputDevice::getMetaState() { int32_t result = 0; size_t numMappers = mMappers.size(); @@ -1277,7 +1356,9 @@ void TouchButtonAccumulator::configure(InputDevice* device) { void TouchButtonAccumulator::reset(InputDevice* device) { mBtnTouch = device->isKeyPressed(BTN_TOUCH); mBtnStylus = device->isKeyPressed(BTN_STYLUS); - mBtnStylus2 = device->isKeyPressed(BTN_STYLUS); + // BTN_0 is what gets mapped for the HID usage Digitizers.SecondaryBarrelSwitch + mBtnStylus2 = + device->isKeyPressed(BTN_STYLUS2) || device->isKeyPressed(BTN_0); mBtnToolFinger = device->isKeyPressed(BTN_TOOL_FINGER); mBtnToolPen = device->isKeyPressed(BTN_TOOL_PEN); mBtnToolRubber = device->isKeyPressed(BTN_TOOL_RUBBER); @@ -1318,6 +1399,7 @@ void TouchButtonAccumulator::process(const RawEvent* rawEvent) { mBtnStylus = rawEvent->value; break; case BTN_STYLUS2: + case BTN_0:// BTN_0 is what gets mapped for the HID usage Digitizers.SecondaryBarrelSwitch mBtnStylus2 = rawEvent->value; break; case BTN_TOOL_FINGER: @@ -1360,10 +1442,10 @@ void TouchButtonAccumulator::process(const RawEvent* rawEvent) { uint32_t TouchButtonAccumulator::getButtonState() const { uint32_t result = 0; if (mBtnStylus) { - result |= AMOTION_EVENT_BUTTON_SECONDARY; + result |= AMOTION_EVENT_BUTTON_STYLUS_PRIMARY; } if (mBtnStylus2) { - result |= AMOTION_EVENT_BUTTON_TERTIARY; + result |= AMOTION_EVENT_BUTTON_STYLUS_SECONDARY; } return result; } @@ -1786,10 +1868,17 @@ void InputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t re void InputMapper::cancelVibrate(int32_t token) { } +void InputMapper::cancelTouch(nsecs_t when) { +} + int32_t InputMapper::getMetaState() { return 0; } +void InputMapper::updateExternalStylusState(const StylusState& state) { + +} + void InputMapper::fadePointer() { } @@ -1811,6 +1900,12 @@ void InputMapper::dumpRawAbsoluteAxisInfo(String8& dump, } } +void InputMapper::dumpStylusState(String8& dump, const StylusState& state) { + dump.appendFormat(INDENT4 "When: %" PRId64 "\n", state.when); + dump.appendFormat(INDENT4 "Pressure: %f\n", state.pressure); + dump.appendFormat(INDENT4 "Button State: 0x%08x\n", state.buttons); + dump.appendFormat(INDENT4 "Tool Type: %" PRId32 "\n", state.toolType); +} // --- SwitchInputMapper --- @@ -2134,6 +2229,9 @@ void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode, getDevice(), keyCode, scanCode)) { return; } + if (policyFlags & POLICY_FLAG_GESTURE) { + mDevice->cancelTouch(when); + } mKeyDowns.push(); KeyDown& keyDown = mKeyDowns.editTop(); @@ -2449,7 +2547,8 @@ void CursorInputMapper::sync(nsecs_t when) { } nsecs_t downTime = mDownTime; bool buttonsChanged = currentButtonState != lastButtonState; - bool buttonsPressed = currentButtonState & ~lastButtonState; + int32_t buttonsPressed = currentButtonState & ~lastButtonState; + int32_t buttonsReleased = lastButtonState & ~currentButtonState; float deltaX = mCursorMotionAccumulator.getRelativeX() * mXScale; float deltaY = mCursorMotionAccumulator.getRelativeY() * mYScale; @@ -2525,6 +2624,7 @@ void CursorInputMapper::sync(nsecs_t when) { // Send motion event. if (downChanged || moved || scrolled || buttonsChanged) { int32_t metaState = mContext->getGlobalMetaState(); + int32_t buttonState = lastButtonState; int32_t motionEventAction; if (downChanged) { motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; @@ -2534,17 +2634,48 @@ void CursorInputMapper::sync(nsecs_t when) { motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE; } + if (buttonsReleased) { + BitSet32 released(buttonsReleased); + while (!released.isEmpty()) { + int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit()); + buttonState &= ~actionButton; + NotifyMotionArgs releaseArgs(when, getDeviceId(), mSource, policyFlags, + AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0, + metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, + displayId, 1, &pointerProperties, &pointerCoords, + mXPrecision, mYPrecision, downTime); + getListener()->notifyMotion(&releaseArgs); + } + } + NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - motionEventAction, 0, metaState, currentButtonState, 0, + motionEventAction, 0, 0, metaState, currentButtonState, + AMOTION_EVENT_EDGE_FLAG_NONE, displayId, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, downTime); getListener()->notifyMotion(&args); + if (buttonsPressed) { + BitSet32 pressed(buttonsPressed); + while (!pressed.isEmpty()) { + int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit()); + buttonState |= actionButton; + NotifyMotionArgs pressArgs(when, getDeviceId(), mSource, policyFlags, + AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0, + metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, + displayId, 1, &pointerProperties, &pointerCoords, + mXPrecision, mYPrecision, downTime); + getListener()->notifyMotion(&pressArgs); + } + } + + ALOG_ASSERT(buttonState == currentButtonState); + // Send hover move after UP to tell the application that the mouse is hovering now. if (motionEventAction == AMOTION_EVENT_ACTION_UP && mPointerController != NULL) { NotifyMotionArgs hoverArgs(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, + AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE, displayId, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, downTime); @@ -2557,7 +2688,7 @@ void CursorInputMapper::sync(nsecs_t when) { pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); NotifyMotionArgs scrollArgs(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_SCROLL, 0, metaState, currentButtonState, + AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE, displayId, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, downTime); @@ -2689,12 +2820,11 @@ void TouchInputMapper::dump(String8& dump) { dump.appendFormat(INDENT4 "TiltYCenter: %0.3f\n", mTiltYCenter); dump.appendFormat(INDENT4 "TiltYScale: %0.3f\n", mTiltYScale); - dump.appendFormat(INDENT3 "Last Button State: 0x%08x\n", mLastButtonState); - + dump.appendFormat(INDENT3 "Last Raw Button State: 0x%08x\n", mLastRawState.buttonState); dump.appendFormat(INDENT3 "Last Raw Touch: pointerCount=%d\n", - mLastRawPointerData.pointerCount); - for (uint32_t i = 0; i < mLastRawPointerData.pointerCount; i++) { - const RawPointerData::Pointer& pointer = mLastRawPointerData.pointers[i]; + mLastRawState.rawPointerData.pointerCount); + for (uint32_t i = 0; i < mLastRawState.rawPointerData.pointerCount; i++) { + const RawPointerData::Pointer& pointer = mLastRawState.rawPointerData.pointers[i]; dump.appendFormat(INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, " "touchMajor=%d, touchMinor=%d, toolMajor=%d, toolMinor=%d, " "orientation=%d, tiltX=%d, tiltY=%d, distance=%d, " @@ -2706,11 +2836,13 @@ void TouchInputMapper::dump(String8& dump) { pointer.toolType, toString(pointer.isHovering)); } + dump.appendFormat(INDENT3 "Last Cooked Button State: 0x%08x\n", mLastCookedState.buttonState); dump.appendFormat(INDENT3 "Last Cooked Touch: pointerCount=%d\n", - mLastCookedPointerData.pointerCount); - for (uint32_t i = 0; i < mLastCookedPointerData.pointerCount; i++) { - const PointerProperties& pointerProperties = mLastCookedPointerData.pointerProperties[i]; - const PointerCoords& pointerCoords = mLastCookedPointerData.pointerCoords[i]; + mLastCookedState.cookedPointerData.pointerCount); + for (uint32_t i = 0; i < mLastCookedState.cookedPointerData.pointerCount; i++) { + const PointerProperties& pointerProperties = + mLastCookedState.cookedPointerData.pointerProperties[i]; + const PointerCoords& pointerCoords = mLastCookedState.cookedPointerData.pointerCoords[i]; dump.appendFormat(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, pressure=%0.3f, " "touchMajor=%0.3f, touchMinor=%0.3f, toolMajor=%0.3f, toolMinor=%0.3f, " "orientation=%0.3f, tilt=%0.3f, distance=%0.3f, " @@ -2727,9 +2859,18 @@ void TouchInputMapper::dump(String8& dump) { pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TILT), pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE), pointerProperties.toolType, - toString(mLastCookedPointerData.isHovering(i))); + toString(mLastCookedState.cookedPointerData.isHovering(i))); } + dump.append(INDENT3 "Stylus Fusion:\n"); + dump.appendFormat(INDENT4 "ExternalStylusConnected: %s\n", + toString(mExternalStylusConnected)); + dump.appendFormat(INDENT4 "External Stylus ID: %" PRId64 "\n", mExternalStylusId); + dump.appendFormat(INDENT4 "External Stylus Data Timeout: %" PRId64 "\n", + mExternalStylusFusionTimeout); + dump.append(INDENT3 "External Stylus State:\n"); + dumpStylusState(dump, mExternalStylusState); + if (mDeviceMode == DEVICE_MODE_POINTER) { dump.appendFormat(INDENT3 "Pointer Gesture Detector:\n"); dump.appendFormat(INDENT4 "XMovementScale: %0.3f\n", @@ -2767,7 +2908,7 @@ void TouchInputMapper::configure(nsecs_t when, resolveCalibration(); } - if (!changes || (changes & InputReaderConfiguration::TOUCH_AFFINE_TRANSFORMATION)) { + if (!changes || (changes & InputReaderConfiguration::CHANGE_TOUCH_AFFINE_TRANSFORMATION)) { // Update location calibration to reflect current settings updateAffineTransformation(); } @@ -2782,7 +2923,8 @@ void TouchInputMapper::configure(nsecs_t when, bool resetNeeded = false; if (!changes || (changes & (InputReaderConfiguration::CHANGE_DISPLAY_INFO | InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT - | InputReaderConfiguration::CHANGE_SHOW_TOUCHES))) { + | InputReaderConfiguration::CHANGE_SHOW_TOUCHES + | InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE))) { // Configure device sources, surface dimensions, orientation and // scaling factors. configureSurface(when, &resetNeeded); @@ -2795,6 +2937,16 @@ void TouchInputMapper::configure(nsecs_t when, } } +void TouchInputMapper::resolveExternalStylusPresence() { + Vector<InputDeviceInfo> devices; + mContext->getExternalStylusDevices(devices); + mExternalStylusConnected = !devices.isEmpty(); + + if (!mExternalStylusConnected) { + resetExternalStylus(); + } +} + void TouchInputMapper::configureParameters() { // Use the pointer presentation mode for devices that do not support distinct // multitouch. The spot-based presentation relies on being able to accurately @@ -2931,9 +3083,15 @@ void TouchInputMapper::dumpRawPointerAxes(String8& dump) { dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.slot, "Slot"); } +bool TouchInputMapper::hasExternalStylus() const { + return mExternalStylusConnected; +} + void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { int32_t oldDeviceMode = mDeviceMode; + resolveExternalStylusPresence(); + // Determine device mode. if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER && mConfig.pointerGesturesEnabled) { @@ -2949,6 +3107,9 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { if (hasStylus()) { mSource |= AINPUT_SOURCE_STYLUS; } + if (hasExternalStylus()) { + mSource |= AINPUT_SOURCE_BLUETOOTH_STYLUS; + } } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_NAVIGATION) { mSource = AINPUT_SOURCE_TOUCH_NAVIGATION; mDeviceMode = DEVICE_MODE_NAVIGATION; @@ -3691,28 +3852,22 @@ void TouchInputMapper::reset(nsecs_t when) { mWheelXVelocityControl.reset(); mWheelYVelocityControl.reset(); - mCurrentRawPointerData.clear(); - mLastRawPointerData.clear(); - mCurrentCookedPointerData.clear(); - mLastCookedPointerData.clear(); - mCurrentButtonState = 0; - mLastButtonState = 0; - mCurrentRawVScroll = 0; - mCurrentRawHScroll = 0; - mCurrentFingerIdBits.clear(); - mLastFingerIdBits.clear(); - mCurrentStylusIdBits.clear(); - mLastStylusIdBits.clear(); - mCurrentMouseIdBits.clear(); - mLastMouseIdBits.clear(); + mRawStatesPending.clear(); + mCurrentRawState.clear(); + mCurrentCookedState.clear(); + mLastRawState.clear(); + mLastCookedState.clear(); mPointerUsage = POINTER_USAGE_NONE; mSentHoverEnter = false; + mHavePointerIds = false; + mCurrentMotionAborted = false; mDownTime = 0; mCurrentVirtualKey.down = false; mPointerGesture.reset(); mPointerSimple.reset(); + resetExternalStylus(); if (mPointerController != NULL) { mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); @@ -3722,6 +3877,18 @@ void TouchInputMapper::reset(nsecs_t when) { InputMapper::reset(when); } +void TouchInputMapper::resetExternalStylus() { + mExternalStylusState.clear(); + mExternalStylusId = -1; + mExternalStylusFusionTimeout = LLONG_MAX; + mExternalStylusDataPending = false; +} + +void TouchInputMapper::clearStylusDataPendingFlags() { + mExternalStylusDataPending = false; + mExternalStylusFusionTimeout = LLONG_MAX; +} + void TouchInputMapper::process(const RawEvent* rawEvent) { mCursorButtonAccumulator.process(rawEvent); mCursorScrollAccumulator.process(rawEvent); @@ -3733,155 +3900,288 @@ void TouchInputMapper::process(const RawEvent* rawEvent) { } void TouchInputMapper::sync(nsecs_t when) { + const RawState* last = mRawStatesPending.isEmpty() ? + &mCurrentRawState : &mRawStatesPending.top(); + + // Push a new state. + mRawStatesPending.push(); + RawState* next = &mRawStatesPending.editTop(); + next->clear(); + next->when = when; + // Sync button state. - mCurrentButtonState = mTouchButtonAccumulator.getButtonState() + next->buttonState = mTouchButtonAccumulator.getButtonState() | mCursorButtonAccumulator.getButtonState(); - // Sync scroll state. - mCurrentRawVScroll = mCursorScrollAccumulator.getRelativeVWheel(); - mCurrentRawHScroll = mCursorScrollAccumulator.getRelativeHWheel(); + // Sync scroll + next->rawVScroll = mCursorScrollAccumulator.getRelativeVWheel(); + next->rawHScroll = mCursorScrollAccumulator.getRelativeHWheel(); mCursorScrollAccumulator.finishSync(); - // Sync touch state. - bool havePointerIds = true; - mCurrentRawPointerData.clear(); - syncTouch(when, &havePointerIds); + // Sync touch + syncTouch(when, next); -#if DEBUG_RAW_EVENTS - if (!havePointerIds) { - ALOGD("syncTouch: pointerCount %d -> %d, no pointer ids", - mLastRawPointerData.pointerCount, - mCurrentRawPointerData.pointerCount); - } else { - ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, " - "hovering ids 0x%08x -> 0x%08x", - mLastRawPointerData.pointerCount, - mCurrentRawPointerData.pointerCount, - mLastRawPointerData.touchingIdBits.value, - mCurrentRawPointerData.touchingIdBits.value, - mLastRawPointerData.hoveringIdBits.value, - mCurrentRawPointerData.hoveringIdBits.value); + // Assign pointer ids. + if (!mHavePointerIds) { + assignPointerIds(last, next); } + +#if DEBUG_RAW_EVENTS + ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, " + "hovering ids 0x%08x -> 0x%08x", + last->rawPointerData.pointerCount, + next->rawPointerData.pointerCount, + last->rawPointerData.touchingIdBits.value, + next->rawPointerData.touchingIdBits.value, + last->rawPointerData.hoveringIdBits.value, + next->rawPointerData.hoveringIdBits.value); #endif - // Reset state that we will compute below. - mCurrentFingerIdBits.clear(); - mCurrentStylusIdBits.clear(); - mCurrentMouseIdBits.clear(); - mCurrentCookedPointerData.clear(); + processRawTouches(false /*timeout*/); +} +void TouchInputMapper::processRawTouches(bool timeout) { if (mDeviceMode == DEVICE_MODE_DISABLED) { // Drop all input if the device is disabled. - mCurrentRawPointerData.clear(); - mCurrentButtonState = 0; - } else { - // Preprocess pointer data. - if (!havePointerIds) { - assignPointerIds(); - } - - // Handle policy on initial down or hover events. - uint32_t policyFlags = 0; - bool initialDown = mLastRawPointerData.pointerCount == 0 - && mCurrentRawPointerData.pointerCount != 0; - bool buttonsPressed = mCurrentButtonState & ~mLastButtonState; - if (initialDown || buttonsPressed) { - // If this is a touch screen, hide the pointer on an initial down. - if (mDeviceMode == DEVICE_MODE_DIRECT) { - getContext()->fadePointer(); - } + mCurrentRawState.clear(); + mRawStatesPending.clear(); + return; + } - if (mParameters.wake) { - policyFlags |= POLICY_FLAG_WAKE; - } + // Drain any pending touch states. The invariant here is that the mCurrentRawState is always + // valid and must go through the full cook and dispatch cycle. This ensures that anything + // touching the current state will only observe the events that have been dispatched to the + // rest of the pipeline. + const size_t N = mRawStatesPending.size(); + size_t count; + for(count = 0; count < N; count++) { + const RawState& next = mRawStatesPending[count]; + + // A failure to assign the stylus id means that we're waiting on stylus data + // and so should defer the rest of the pipeline. + if (assignExternalStylusId(next, timeout)) { + break; } - // Synthesize key down from raw buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource, - policyFlags, mLastButtonState, mCurrentButtonState); + // All ready to go. + clearStylusDataPendingFlags(); + mCurrentRawState.copyFrom(next); + if (mCurrentRawState.when < mLastRawState.when) { + mCurrentRawState.when = mLastRawState.when; + } + cookAndDispatch(mCurrentRawState.when); + } + if (count != 0) { + mRawStatesPending.removeItemsAt(0, count); + } - // Consume raw off-screen touches before cooking pointer data. - // If touches are consumed, subsequent code will not receive any pointer data. - if (consumeRawTouches(when, policyFlags)) { - mCurrentRawPointerData.clear(); + if (mExternalStylusDataPending) { + if (timeout) { + nsecs_t when = mExternalStylusFusionTimeout - STYLUS_DATA_LATENCY; + clearStylusDataPendingFlags(); + mCurrentRawState.copyFrom(mLastRawState); +#if DEBUG_STYLUS_FUSION + ALOGD("Timeout expired, synthesizing event with new stylus data"); +#endif + cookAndDispatch(when); + } else if (mExternalStylusFusionTimeout == LLONG_MAX) { + mExternalStylusFusionTimeout = mExternalStylusState.when + TOUCH_DATA_TIMEOUT; + getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout); } + } +} - // Cook pointer data. This call populates the mCurrentCookedPointerData structure - // with cooked pointer data that has the same ids and indices as the raw data. - // The following code can use either the raw or cooked data, as needed. - cookPointerData(); +void TouchInputMapper::cookAndDispatch(nsecs_t when) { + // Always start with a clean state. + mCurrentCookedState.clear(); - // Dispatch the touches either directly or by translation through a pointer on screen. - if (mDeviceMode == DEVICE_MODE_POINTER) { - for (BitSet32 idBits(mCurrentRawPointerData.touchingIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); - if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS - || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { - mCurrentStylusIdBits.markBit(id); - } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER - || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { - mCurrentFingerIdBits.markBit(id); - } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) { - mCurrentMouseIdBits.markBit(id); - } + // Apply stylus buttons to current raw state. + applyExternalStylusButtonState(when); + + // Handle policy on initial down or hover events. + bool initialDown = mLastRawState.rawPointerData.pointerCount == 0 + && mCurrentRawState.rawPointerData.pointerCount != 0; + + uint32_t policyFlags = 0; + bool buttonsPressed = mCurrentRawState.buttonState & ~mLastRawState.buttonState; + if (initialDown || buttonsPressed) { + // If this is a touch screen, hide the pointer on an initial down. + if (mDeviceMode == DEVICE_MODE_DIRECT) { + getContext()->fadePointer(); + } + + if (mParameters.wake) { + policyFlags |= POLICY_FLAG_WAKE; + } + } + + // Consume raw off-screen touches before cooking pointer data. + // If touches are consumed, subsequent code will not receive any pointer data. + if (consumeRawTouches(when, policyFlags)) { + mCurrentRawState.rawPointerData.clear(); + } + + // Cook pointer data. This call populates the mCurrentCookedState.cookedPointerData structure + // with cooked pointer data that has the same ids and indices as the raw data. + // The following code can use either the raw or cooked data, as needed. + cookPointerData(); + + // Apply stylus pressure to current cooked state. + applyExternalStylusTouchState(when); + + // Synthesize key down from raw buttons if needed. + synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource, + policyFlags, mLastCookedState.buttonState, mCurrentCookedState.buttonState); + + // Dispatch the touches either directly or by translation through a pointer on screen. + if (mDeviceMode == DEVICE_MODE_POINTER) { + for (BitSet32 idBits(mCurrentRawState.rawPointerData.touchingIdBits); + !idBits.isEmpty(); ) { + uint32_t id = idBits.clearFirstMarkedBit(); + const RawPointerData::Pointer& pointer = + mCurrentRawState.rawPointerData.pointerForId(id); + if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS + || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { + mCurrentCookedState.stylusIdBits.markBit(id); + } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER + || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { + mCurrentCookedState.fingerIdBits.markBit(id); + } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) { + mCurrentCookedState.mouseIdBits.markBit(id); } - for (BitSet32 idBits(mCurrentRawPointerData.hoveringIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); - if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS - || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { - mCurrentStylusIdBits.markBit(id); - } + } + for (BitSet32 idBits(mCurrentRawState.rawPointerData.hoveringIdBits); + !idBits.isEmpty(); ) { + uint32_t id = idBits.clearFirstMarkedBit(); + const RawPointerData::Pointer& pointer = + mCurrentRawState.rawPointerData.pointerForId(id); + if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS + || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { + mCurrentCookedState.stylusIdBits.markBit(id); } + } - // Stylus takes precedence over all tools, then mouse, then finger. - PointerUsage pointerUsage = mPointerUsage; - if (!mCurrentStylusIdBits.isEmpty()) { - mCurrentMouseIdBits.clear(); - mCurrentFingerIdBits.clear(); - pointerUsage = POINTER_USAGE_STYLUS; - } else if (!mCurrentMouseIdBits.isEmpty()) { - mCurrentFingerIdBits.clear(); - pointerUsage = POINTER_USAGE_MOUSE; - } else if (!mCurrentFingerIdBits.isEmpty() || isPointerDown(mCurrentButtonState)) { - pointerUsage = POINTER_USAGE_GESTURES; - } + // Stylus takes precedence over all tools, then mouse, then finger. + PointerUsage pointerUsage = mPointerUsage; + if (!mCurrentCookedState.stylusIdBits.isEmpty()) { + mCurrentCookedState.mouseIdBits.clear(); + mCurrentCookedState.fingerIdBits.clear(); + pointerUsage = POINTER_USAGE_STYLUS; + } else if (!mCurrentCookedState.mouseIdBits.isEmpty()) { + mCurrentCookedState.fingerIdBits.clear(); + pointerUsage = POINTER_USAGE_MOUSE; + } else if (!mCurrentCookedState.fingerIdBits.isEmpty() || + isPointerDown(mCurrentRawState.buttonState)) { + pointerUsage = POINTER_USAGE_GESTURES; + } - dispatchPointerUsage(when, policyFlags, pointerUsage); - } else { - if (mDeviceMode == DEVICE_MODE_DIRECT - && mConfig.showTouches && mPointerController != NULL) { - mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT); - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - - mPointerController->setButtonState(mCurrentButtonState); - mPointerController->setSpots(mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - mCurrentCookedPointerData.touchingIdBits); - } + dispatchPointerUsage(when, policyFlags, pointerUsage); + } else { + if (mDeviceMode == DEVICE_MODE_DIRECT + && mConfig.showTouches && mPointerController != NULL) { + mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT); + mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); + mPointerController->setButtonState(mCurrentRawState.buttonState); + mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.touchingIdBits); + } + + if (!mCurrentMotionAborted) { + dispatchButtonRelease(when, policyFlags); dispatchHoverExit(when, policyFlags); dispatchTouches(when, policyFlags); dispatchHoverEnterAndMove(when, policyFlags); + dispatchButtonPress(when, policyFlags); } - // Synthesize key up from raw buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, - policyFlags, mLastButtonState, mCurrentButtonState); + if (mCurrentCookedState.cookedPointerData.pointerCount == 0) { + mCurrentMotionAborted = false; + } } - // Copy current touch to last touch in preparation for the next cycle. - mLastRawPointerData.copyFrom(mCurrentRawPointerData); - mLastCookedPointerData.copyFrom(mCurrentCookedPointerData); - mLastButtonState = mCurrentButtonState; - mLastFingerIdBits = mCurrentFingerIdBits; - mLastStylusIdBits = mCurrentStylusIdBits; - mLastMouseIdBits = mCurrentMouseIdBits; + // Synthesize key up from raw buttons if needed. + synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, + policyFlags, mLastCookedState.buttonState, mCurrentCookedState.buttonState); // Clear some transient state. - mCurrentRawVScroll = 0; - mCurrentRawHScroll = 0; + mCurrentRawState.rawVScroll = 0; + mCurrentRawState.rawHScroll = 0; + + // Copy current touch to last touch in preparation for the next cycle. + mLastRawState.copyFrom(mCurrentRawState); + mLastCookedState.copyFrom(mCurrentCookedState); +} + +void TouchInputMapper::applyExternalStylusButtonState(nsecs_t when) { + if (mDeviceMode == DEVICE_MODE_DIRECT && hasExternalStylus() && mExternalStylusId != -1) { + mCurrentRawState.buttonState |= mExternalStylusState.buttons; + } +} + +void TouchInputMapper::applyExternalStylusTouchState(nsecs_t when) { + CookedPointerData& currentPointerData = mCurrentCookedState.cookedPointerData; + const CookedPointerData& lastPointerData = mLastCookedState.cookedPointerData; + + if (mExternalStylusId != -1 && currentPointerData.isTouching(mExternalStylusId)) { + float pressure = mExternalStylusState.pressure; + if (pressure == 0.0f && lastPointerData.isTouching(mExternalStylusId)) { + const PointerCoords& coords = lastPointerData.pointerCoordsForId(mExternalStylusId); + pressure = coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE); + } + PointerCoords& coords = currentPointerData.editPointerCoordsWithId(mExternalStylusId); + coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure); + + PointerProperties& properties = + currentPointerData.editPointerPropertiesWithId(mExternalStylusId); + if (mExternalStylusState.toolType != AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { + properties.toolType = mExternalStylusState.toolType; + } + } +} + +bool TouchInputMapper::assignExternalStylusId(const RawState& state, bool timeout) { + if (mDeviceMode != DEVICE_MODE_DIRECT || !hasExternalStylus()) { + return false; + } + + const bool initialDown = mLastRawState.rawPointerData.pointerCount == 0 + && state.rawPointerData.pointerCount != 0; + if (initialDown) { + if (mExternalStylusState.pressure != 0.0f) { +#if DEBUG_STYLUS_FUSION + ALOGD("Have both stylus and touch data, beginning fusion"); +#endif + mExternalStylusId = state.rawPointerData.touchingIdBits.firstMarkedBit(); + } else if (timeout) { +#if DEBUG_STYLUS_FUSION + ALOGD("Timeout expired, assuming touch is not a stylus."); +#endif + resetExternalStylus(); + } else { + if (mExternalStylusFusionTimeout == LLONG_MAX) { + mExternalStylusFusionTimeout = state.when + EXTERNAL_STYLUS_DATA_TIMEOUT; + } +#if DEBUG_STYLUS_FUSION + ALOGD("No stylus data but stylus is connected, requesting timeout " + "(%" PRId64 "ms)", mExternalStylusFusionTimeout); +#endif + getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout); + return true; + } + } + + // Check if the stylus pointer has gone up. + if (mExternalStylusId != -1 && + !state.rawPointerData.touchingIdBits.hasBit(mExternalStylusId)) { +#if DEBUG_STYLUS_FUSION + ALOGD("Stylus pointer is going up"); +#endif + mExternalStylusId = -1; + } + + return false; } void TouchInputMapper::timeoutExpired(nsecs_t when) { @@ -3889,13 +4189,30 @@ void TouchInputMapper::timeoutExpired(nsecs_t when) { if (mPointerUsage == POINTER_USAGE_GESTURES) { dispatchPointerGestures(when, 0 /*policyFlags*/, true /*isTimeout*/); } + } else if (mDeviceMode == DEVICE_MODE_DIRECT) { + if (mExternalStylusFusionTimeout < when) { + processRawTouches(true /*timeout*/); + } else if (mExternalStylusFusionTimeout != LLONG_MAX) { + getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout); + } + } +} + +void TouchInputMapper::updateExternalStylusState(const StylusState& state) { + mExternalStylusState.copyFrom(state); + if (mExternalStylusId != -1 || mExternalStylusFusionTimeout != LLONG_MAX) { + // We're either in the middle of a fused stream of data or we're waiting on data before + // dispatching the initial down, so go ahead and dispatch now that we have fresh stylus + // data. + mExternalStylusDataPending = true; + processRawTouches(false /*timeout*/); } } bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) { // Check for release of a virtual key. if (mCurrentVirtualKey.down) { - if (mCurrentRawPointerData.touchingIdBits.isEmpty()) { + if (mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) { // Pointer went up while virtual key was down. mCurrentVirtualKey.down = false; if (!mCurrentVirtualKey.ignored) { @@ -3910,9 +4227,10 @@ bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) { return true; } - if (mCurrentRawPointerData.touchingIdBits.count() == 1) { - uint32_t id = mCurrentRawPointerData.touchingIdBits.firstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); + if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) { + uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit(); + const RawPointerData::Pointer& pointer = + mCurrentRawState.rawPointerData.pointerForId(id); const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y); if (virtualKey && virtualKey->keyCode == mCurrentVirtualKey.keyCode) { // Pointer is still within the space of the virtual key. @@ -3937,15 +4255,15 @@ bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) { } } - if (mLastRawPointerData.touchingIdBits.isEmpty() - && !mCurrentRawPointerData.touchingIdBits.isEmpty()) { + if (mLastRawState.rawPointerData.touchingIdBits.isEmpty() + && !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) { // Pointer just went down. Check for virtual key press or off-screen touches. - uint32_t id = mCurrentRawPointerData.touchingIdBits.firstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); + uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit(); + const RawPointerData::Pointer& pointer = mCurrentRawState.rawPointerData.pointerForId(id); if (!isPointInsideSurface(pointer.x, pointer.y)) { // If exactly one pointer went down, check for virtual key hit. // Otherwise we will drop the entire stroke. - if (mCurrentRawPointerData.touchingIdBits.count() == 1) { + if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) { const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y); if (virtualKey) { mCurrentVirtualKey.down = true; @@ -3985,7 +4303,8 @@ bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) { // area and accidentally triggers a virtual key. This often happens when virtual keys // are layed out below the screen near to where the on screen keyboard's space bar // is displayed. - if (mConfig.virtualKeyQuietTime > 0 && !mCurrentRawPointerData.touchingIdBits.isEmpty()) { + if (mConfig.virtualKeyQuietTime > 0 && + !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) { mContext->disableVirtualKeysUntil(when + mConfig.virtualKeyQuietTime); } return false; @@ -4004,22 +4323,38 @@ void TouchInputMapper::dispatchVirtualKey(nsecs_t when, uint32_t policyFlags, getListener()->notifyKey(&args); } +void TouchInputMapper::abortTouches(nsecs_t when, uint32_t policyFlags) { + BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits; + if (!currentIdBits.isEmpty()) { + int32_t metaState = getContext()->getGlobalMetaState(); + int32_t buttonState = mCurrentCookedState.buttonState; + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0, + metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + currentIdBits, -1, + mOrientedXPrecision, mOrientedYPrecision, mDownTime); + mCurrentMotionAborted = true; + } +} + void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { - BitSet32 currentIdBits = mCurrentCookedPointerData.touchingIdBits; - BitSet32 lastIdBits = mLastCookedPointerData.touchingIdBits; + BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits; + BitSet32 lastIdBits = mLastCookedState.cookedPointerData.touchingIdBits; int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mCurrentButtonState; + int32_t buttonState = mCurrentCookedState.buttonState; if (currentIdBits == lastIdBits) { if (!currentIdBits.isEmpty()) { // No pointer id changes so this is a move event. // The listener takes care of batching moves so we don't have to deal with that here. dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, + AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, currentIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } @@ -4034,14 +4369,14 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { // Update last coordinates of pointers that have moved so that we observe the new // pointer positions at the same time as other pointers that have just gone up. bool moveNeeded = updateMovedPointers( - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - mLastCookedPointerData.pointerProperties, - mLastCookedPointerData.pointerCoords, - mLastCookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mLastCookedState.cookedPointerData.pointerProperties, + mLastCookedState.cookedPointerData.pointerCoords, + mLastCookedState.cookedPointerData.idToIndex, moveIdBits); - if (buttonState != mLastButtonState) { + if (buttonState != mLastCookedState.buttonState) { moveNeeded = true; } @@ -4050,27 +4385,25 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { uint32_t upId = upIdBits.clearFirstMarkedBit(); dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_POINTER_UP, 0, metaState, buttonState, 0, - mLastCookedPointerData.pointerProperties, - mLastCookedPointerData.pointerCoords, - mLastCookedPointerData.idToIndex, - dispatchedIdBits, upId, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); + AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, metaState, buttonState, 0, + mLastCookedState.cookedPointerData.pointerProperties, + mLastCookedState.cookedPointerData.pointerCoords, + mLastCookedState.cookedPointerData.idToIndex, + dispatchedIdBits, upId, mOrientedXPrecision, mOrientedYPrecision, mDownTime); dispatchedIdBits.clearBit(upId); } // Dispatch move events if any of the remaining pointers moved from their old locations. // Although applications receive new locations as part of individual pointer up // events, they do not generally handle them except when presented in a move event. - if (moveNeeded) { + if (moveNeeded && !moveIdBits.isEmpty()) { ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value); dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, 0, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - dispatchedIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); + AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, 0, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + dispatchedIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } // Dispatch pointer down events using the new pointer locations. @@ -4084,69 +4417,119 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { } dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - dispatchedIdBits, downId, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); + AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + dispatchedIdBits, downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } } } void TouchInputMapper::dispatchHoverExit(nsecs_t when, uint32_t policyFlags) { if (mSentHoverEnter && - (mCurrentCookedPointerData.hoveringIdBits.isEmpty() - || !mCurrentCookedPointerData.touchingIdBits.isEmpty())) { + (mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty() + || !mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty())) { int32_t metaState = getContext()->getGlobalMetaState(); dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastButtonState, 0, - mLastCookedPointerData.pointerProperties, - mLastCookedPointerData.pointerCoords, - mLastCookedPointerData.idToIndex, - mLastCookedPointerData.hoveringIdBits, -1, + AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastCookedState.buttonState, 0, + mLastCookedState.cookedPointerData.pointerProperties, + mLastCookedState.cookedPointerData.pointerCoords, + mLastCookedState.cookedPointerData.idToIndex, + mLastCookedState.cookedPointerData.hoveringIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); mSentHoverEnter = false; } } void TouchInputMapper::dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags) { - if (mCurrentCookedPointerData.touchingIdBits.isEmpty() - && !mCurrentCookedPointerData.hoveringIdBits.isEmpty()) { + if (mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty() + && !mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty()) { int32_t metaState = getContext()->getGlobalMetaState(); if (!mSentHoverEnter) { - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, mCurrentButtonState, 0, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - mCurrentCookedPointerData.hoveringIdBits, -1, + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_ENTER, + 0, 0, metaState, mCurrentRawState.buttonState, 0, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.hoveringIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); mSentHoverEnter = true; } dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, mCurrentButtonState, 0, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - mCurrentCookedPointerData.hoveringIdBits, -1, + AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, + mCurrentRawState.buttonState, 0, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.hoveringIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } } +void TouchInputMapper::dispatchButtonRelease(nsecs_t when, uint32_t policyFlags) { + BitSet32 releasedButtons(mLastCookedState.buttonState & ~mCurrentCookedState.buttonState); + const BitSet32& idBits = findActiveIdBits(mLastCookedState.cookedPointerData); + const int32_t metaState = getContext()->getGlobalMetaState(); + int32_t buttonState = mLastCookedState.buttonState; + while (!releasedButtons.isEmpty()) { + int32_t actionButton = BitSet32::valueForBit(releasedButtons.clearFirstMarkedBit()); + buttonState &= ~actionButton; + dispatchMotion(when, policyFlags, mSource, + AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, + 0, metaState, buttonState, 0, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1, + mOrientedXPrecision, mOrientedYPrecision, mDownTime); + } +} + +void TouchInputMapper::dispatchButtonPress(nsecs_t when, uint32_t policyFlags) { + BitSet32 pressedButtons(mCurrentCookedState.buttonState & ~mLastCookedState.buttonState); + const BitSet32& idBits = findActiveIdBits(mCurrentCookedState.cookedPointerData); + const int32_t metaState = getContext()->getGlobalMetaState(); + int32_t buttonState = mLastCookedState.buttonState; + while (!pressedButtons.isEmpty()) { + int32_t actionButton = BitSet32::valueForBit(pressedButtons.clearFirstMarkedBit()); + buttonState |= actionButton; + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, + 0, metaState, buttonState, 0, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1, + mOrientedXPrecision, mOrientedYPrecision, mDownTime); + } +} + +const BitSet32& TouchInputMapper::findActiveIdBits(const CookedPointerData& cookedPointerData) { + if (!cookedPointerData.touchingIdBits.isEmpty()) { + return cookedPointerData.touchingIdBits; + } + return cookedPointerData.hoveringIdBits; +} + void TouchInputMapper::cookPointerData() { - uint32_t currentPointerCount = mCurrentRawPointerData.pointerCount; + uint32_t currentPointerCount = mCurrentRawState.rawPointerData.pointerCount; + + mCurrentCookedState.cookedPointerData.clear(); + mCurrentCookedState.cookedPointerData.pointerCount = currentPointerCount; + mCurrentCookedState.cookedPointerData.hoveringIdBits = + mCurrentRawState.rawPointerData.hoveringIdBits; + mCurrentCookedState.cookedPointerData.touchingIdBits = + mCurrentRawState.rawPointerData.touchingIdBits; - mCurrentCookedPointerData.clear(); - mCurrentCookedPointerData.pointerCount = currentPointerCount; - mCurrentCookedPointerData.hoveringIdBits = mCurrentRawPointerData.hoveringIdBits; - mCurrentCookedPointerData.touchingIdBits = mCurrentRawPointerData.touchingIdBits; + if (mCurrentCookedState.cookedPointerData.pointerCount == 0) { + mCurrentCookedState.buttonState = 0; + } else { + mCurrentCookedState.buttonState = mCurrentRawState.buttonState; + } // Walk through the the active pointers and map device coordinates onto // surface coordinates and adjust for display orientation. for (uint32_t i = 0; i < currentPointerCount; i++) { - const RawPointerData::Pointer& in = mCurrentRawPointerData.pointers[i]; + const RawPointerData::Pointer& in = mCurrentRawState.rawPointerData.pointers[i]; // Size float touchMajor, touchMinor, toolMajor, toolMinor, size; @@ -4185,7 +4568,8 @@ void TouchInputMapper::cookPointerData() { } if (mCalibration.haveSizeIsSummed && mCalibration.sizeIsSummed) { - uint32_t touchingCount = mCurrentRawPointerData.touchingIdBits.count(); + uint32_t touchingCount = + mCurrentRawState.rawPointerData.touchingIdBits.count(); if (touchingCount > 1) { touchMajor /= touchingCount; touchMinor /= touchingCount; @@ -4354,7 +4738,7 @@ void TouchInputMapper::cookPointerData() { } // Write output coords. - PointerCoords& out = mCurrentCookedPointerData.pointerCoords[i]; + PointerCoords& out = mCurrentCookedState.cookedPointerData.pointerCoords[i]; out.clear(); out.setAxisValue(AMOTION_EVENT_AXIS_X, x); out.setAxisValue(AMOTION_EVENT_AXIS_Y, y); @@ -4376,14 +4760,15 @@ void TouchInputMapper::cookPointerData() { } // Write output properties. - PointerProperties& properties = mCurrentCookedPointerData.pointerProperties[i]; + PointerProperties& properties = + mCurrentCookedState.cookedPointerData.pointerProperties[i]; uint32_t id = in.id; properties.clear(); properties.id = id; properties.toolType = in.toolType; // Write id index. - mCurrentCookedPointerData.idToIndex[id] = i; + mCurrentCookedState.cookedPointerData.idToIndex[id] = i; } } @@ -4487,7 +4872,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag // Send events! int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mCurrentButtonState; + int32_t buttonState = mCurrentCookedState.buttonState; // Update last coordinates of pointers that have moved so that we observe the new // pointer positions at the same time as other pointers that have just gone up. @@ -4508,7 +4893,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, movedGestureIdBits); - if (buttonState != mLastButtonState) { + if (buttonState != mLastCookedState.buttonState) { moveNeeded = true; } } @@ -4518,12 +4903,12 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag if (!dispatchedGestureIdBits.isEmpty()) { if (cancelPreviousGesture) { dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_CANCEL, 0, metaState, buttonState, + AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, - dispatchedGestureIdBits, -1, - 0, 0, mPointerGesture.downTime); + dispatchedGestureIdBits, -1, 0, + 0, mPointerGesture.downTime); dispatchedGestureIdBits.clear(); } else { @@ -4538,7 +4923,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag uint32_t id = upGestureIdBits.clearFirstMarkedBit(); dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_POINTER_UP, 0, + AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, @@ -4553,7 +4938,8 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag // Send motion events for all pointers that moved. if (moveNeeded) { dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, + AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, + AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, dispatchedGestureIdBits, -1, @@ -4573,7 +4959,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag } dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0, + AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0, mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, dispatchedGestureIdBits, id, @@ -4584,7 +4970,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag // Send motion events for hover. if (mPointerGesture.currentGestureMode == PointerGesture::HOVER) { dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, + AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, @@ -4610,7 +4996,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, + AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mViewport.displayId, 1, &pointerProperties, &pointerCoords, 0, 0, mPointerGesture.downTime); @@ -4639,9 +5025,9 @@ void TouchInputMapper::abortPointerGestures(nsecs_t when, uint32_t policyFlags) // Cancel previously dispatches pointers. if (!mPointerGesture.lastGestureIdBits.isEmpty()) { int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mCurrentButtonState; + int32_t buttonState = mCurrentRawState.buttonState; dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_CANCEL, 0, metaState, buttonState, + AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, @@ -4696,21 +5082,22 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, return false; } - const uint32_t currentFingerCount = mCurrentFingerIdBits.count(); - const uint32_t lastFingerCount = mLastFingerIdBits.count(); + const uint32_t currentFingerCount = mCurrentCookedState.fingerIdBits.count(); + const uint32_t lastFingerCount = mLastCookedState.fingerIdBits.count(); // Update the velocity tracker. { VelocityTracker::Position positions[MAX_POINTERS]; uint32_t count = 0; - for (BitSet32 idBits(mCurrentFingerIdBits); !idBits.isEmpty(); count++) { + for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty(); count++) { uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); + const RawPointerData::Pointer& pointer = + mCurrentRawState.rawPointerData.pointerForId(id); positions[count].x = pointer.x * mPointerXMovementScale; positions[count].y = pointer.y * mPointerYMovementScale; } mPointerGesture.velocityTracker.addMovement(when, - mCurrentFingerIdBits, positions); + mCurrentCookedState.fingerIdBits, positions); } // If the gesture ever enters a mode other than TAP, HOVER or TAP_DRAG, without first returning @@ -4730,17 +5117,17 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, int32_t lastActiveTouchId = mPointerGesture.activeTouchId; int32_t activeTouchId = lastActiveTouchId; if (activeTouchId < 0) { - if (!mCurrentFingerIdBits.isEmpty()) { + if (!mCurrentCookedState.fingerIdBits.isEmpty()) { activeTouchChanged = true; activeTouchId = mPointerGesture.activeTouchId = - mCurrentFingerIdBits.firstMarkedBit(); + mCurrentCookedState.fingerIdBits.firstMarkedBit(); mPointerGesture.firstTouchTime = when; } - } else if (!mCurrentFingerIdBits.hasBit(activeTouchId)) { + } else if (!mCurrentCookedState.fingerIdBits.hasBit(activeTouchId)) { activeTouchChanged = true; - if (!mCurrentFingerIdBits.isEmpty()) { + if (!mCurrentCookedState.fingerIdBits.isEmpty()) { activeTouchId = mPointerGesture.activeTouchId = - mCurrentFingerIdBits.firstMarkedBit(); + mCurrentCookedState.fingerIdBits.firstMarkedBit(); } else { activeTouchId = mPointerGesture.activeTouchId = -1; } @@ -4763,7 +5150,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, isQuietTime = true; } else if (mPointerGesture.lastGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG && currentFingerCount >= 2 - && !isPointerDown(mCurrentButtonState)) { + && !isPointerDown(mCurrentRawState.buttonState)) { // Enter quiet time when releasing the button and there are still two or more // fingers down. This may indicate that one finger was used to press the button // but it has not gone up yet. @@ -4791,7 +5178,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureIdBits.clear(); mPointerVelocityControl.reset(); - } else if (isPointerDown(mCurrentButtonState)) { + } else if (isPointerDown(mCurrentRawState.buttonState)) { // Case 2: Button is pressed. (BUTTON_CLICK_OR_DRAG) // The pointer follows the active touch point. // Emit DOWN, MOVE, UP events at the pointer location. @@ -4820,7 +5207,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, if (activeTouchId >= 0 && currentFingerCount > 1) { int32_t bestId = -1; float bestSpeed = mConfig.pointerGestureDragMinSwitchSpeed; - for (BitSet32 idBits(mCurrentFingerIdBits); !idBits.isEmpty(); ) { + for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty(); ) { uint32_t id = idBits.clearFirstMarkedBit(); float vx, vy; if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) { @@ -4841,11 +5228,11 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } } - if (activeTouchId >= 0 && mLastFingerIdBits.hasBit(activeTouchId)) { + if (activeTouchId >= 0 && mLastCookedState.fingerIdBits.hasBit(activeTouchId)) { const RawPointerData::Pointer& currentPointer = - mCurrentRawPointerData.pointerForId(activeTouchId); + mCurrentRawState.rawPointerData.pointerForId(activeTouchId); const RawPointerData::Pointer& lastPointer = - mLastRawPointerData.pointerForId(activeTouchId); + mLastRawState.rawPointerData.pointerForId(activeTouchId); float deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale; float deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale; @@ -4981,11 +5368,11 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG; } - if (mLastFingerIdBits.hasBit(activeTouchId)) { + if (mLastCookedState.fingerIdBits.hasBit(activeTouchId)) { const RawPointerData::Pointer& currentPointer = - mCurrentRawPointerData.pointerForId(activeTouchId); + mCurrentRawState.rawPointerData.pointerForId(activeTouchId); const RawPointerData::Pointer& lastPointer = - mLastRawPointerData.pointerForId(activeTouchId); + mLastRawState.rawPointerData.pointerForId(activeTouchId); float deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale; float deltaY = (currentPointer.y - lastPointer.y) @@ -5090,7 +5477,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, + mConfig.pointerGestureMultitouchSettleInterval - when) * 0.000001f); #endif - mCurrentRawPointerData.getCentroidOfTouchingPointers( + mCurrentRawState.rawPointerData.getCentroidOfTouchingPointers( &mPointerGesture.referenceTouchX, &mPointerGesture.referenceTouchY); mPointerController->getPosition(&mPointerGesture.referenceGestureX, @@ -5098,23 +5485,23 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } // Clear the reference deltas for fingers not yet included in the reference calculation. - for (BitSet32 idBits(mCurrentFingerIdBits.value + for (BitSet32 idBits(mCurrentCookedState.fingerIdBits.value & ~mPointerGesture.referenceIdBits.value); !idBits.isEmpty(); ) { uint32_t id = idBits.clearFirstMarkedBit(); mPointerGesture.referenceDeltas[id].dx = 0; mPointerGesture.referenceDeltas[id].dy = 0; } - mPointerGesture.referenceIdBits = mCurrentFingerIdBits; + mPointerGesture.referenceIdBits = mCurrentCookedState.fingerIdBits; // Add delta for all fingers and calculate a common movement delta. float commonDeltaX = 0, commonDeltaY = 0; - BitSet32 commonIdBits(mLastFingerIdBits.value - & mCurrentFingerIdBits.value); + BitSet32 commonIdBits(mLastCookedState.fingerIdBits.value + & mCurrentCookedState.fingerIdBits.value); for (BitSet32 idBits(commonIdBits); !idBits.isEmpty(); ) { bool first = (idBits == commonIdBits); uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& cpd = mCurrentRawPointerData.pointerForId(id); - const RawPointerData::Pointer& lpd = mLastRawPointerData.pointerForId(id); + const RawPointerData::Pointer& cpd = mCurrentRawState.rawPointerData.pointerForId(id); + const RawPointerData::Pointer& lpd = mLastRawState.rawPointerData.pointerForId(id); PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; delta.dx += cpd.x - lpd.x; delta.dy += cpd.y - lpd.y; @@ -5155,11 +5542,13 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; } else { // There are exactly two pointers. - BitSet32 idBits(mCurrentFingerIdBits); + BitSet32 idBits(mCurrentCookedState.fingerIdBits); uint32_t id1 = idBits.clearFirstMarkedBit(); uint32_t id2 = idBits.firstMarkedBit(); - const RawPointerData::Pointer& p1 = mCurrentRawPointerData.pointerForId(id1); - const RawPointerData::Pointer& p2 = mCurrentRawPointerData.pointerForId(id2); + const RawPointerData::Pointer& p1 = + mCurrentRawState.rawPointerData.pointerForId(id1); + const RawPointerData::Pointer& p2 = + mCurrentRawState.rawPointerData.pointerForId(id2); float mutualDistance = distance(p1.x, p1.y, p2.x, p2.y); if (mutualDistance > mPointerGestureMaxSwipeWidth) { // There are two pointers but they are too far apart for a SWIPE, @@ -5305,14 +5694,14 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } else { // Otherwise, assume we mapped all touches from the previous frame. // Reuse all mappings that are still applicable. - mappedTouchIdBits.value = mLastFingerIdBits.value - & mCurrentFingerIdBits.value; + mappedTouchIdBits.value = mLastCookedState.fingerIdBits.value + & mCurrentCookedState.fingerIdBits.value; usedGestureIdBits = mPointerGesture.lastGestureIdBits; // Check whether we need to choose a new active gesture id because the // current went went up. - for (BitSet32 upTouchIdBits(mLastFingerIdBits.value - & ~mCurrentFingerIdBits.value); + for (BitSet32 upTouchIdBits(mLastCookedState.fingerIdBits.value + & ~mCurrentCookedState.fingerIdBits.value); !upTouchIdBits.isEmpty(); ) { uint32_t upTouchId = upTouchIdBits.clearFirstMarkedBit(); uint32_t upGestureId = mPointerGesture.freeformTouchToGestureIdMap[upTouchId]; @@ -5331,7 +5720,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.activeGestureId); #endif - BitSet32 idBits(mCurrentFingerIdBits); + BitSet32 idBits(mCurrentCookedState.fingerIdBits); for (uint32_t i = 0; i < currentFingerCount; i++) { uint32_t touchId = idBits.clearFirstMarkedBit(); uint32_t gestureId; @@ -5355,7 +5744,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureIdToIndex[gestureId] = i; const RawPointerData::Pointer& pointer = - mCurrentRawPointerData.pointerForId(touchId); + mCurrentRawState.rawPointerData.pointerForId(touchId); float deltaX = (pointer.x - mPointerGesture.referenceTouchX) * mPointerXZoomScale; float deltaY = (pointer.y - mPointerGesture.referenceTouchY) @@ -5386,7 +5775,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } } - mPointerController->setButtonState(mCurrentButtonState); + mPointerController->setButtonState(mCurrentRawState.buttonState); #if DEBUG_GESTURES ALOGD("Gestures: finishPreviousGesture=%s, cancelPreviousGesture=%s, " @@ -5428,23 +5817,24 @@ void TouchInputMapper::dispatchPointerStylus(nsecs_t when, uint32_t policyFlags) mPointerSimple.currentProperties.clear(); bool down, hovering; - if (!mCurrentStylusIdBits.isEmpty()) { - uint32_t id = mCurrentStylusIdBits.firstMarkedBit(); - uint32_t index = mCurrentCookedPointerData.idToIndex[id]; - float x = mCurrentCookedPointerData.pointerCoords[index].getX(); - float y = mCurrentCookedPointerData.pointerCoords[index].getY(); + if (!mCurrentCookedState.stylusIdBits.isEmpty()) { + uint32_t id = mCurrentCookedState.stylusIdBits.firstMarkedBit(); + uint32_t index = mCurrentCookedState.cookedPointerData.idToIndex[id]; + float x = mCurrentCookedState.cookedPointerData.pointerCoords[index].getX(); + float y = mCurrentCookedState.cookedPointerData.pointerCoords[index].getY(); mPointerController->setPosition(x, y); - hovering = mCurrentCookedPointerData.hoveringIdBits.hasBit(id); + hovering = mCurrentCookedState.cookedPointerData.hoveringIdBits.hasBit(id); down = !hovering; mPointerController->getPosition(&x, &y); - mPointerSimple.currentCoords.copyFrom(mCurrentCookedPointerData.pointerCoords[index]); + mPointerSimple.currentCoords.copyFrom( + mCurrentCookedState.cookedPointerData.pointerCoords[index]); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); mPointerSimple.currentProperties.id = 0; mPointerSimple.currentProperties.toolType = - mCurrentCookedPointerData.pointerProperties[index].toolType; + mCurrentCookedState.cookedPointerData.pointerProperties[index].toolType; } else { down = false; hovering = false; @@ -5462,16 +5852,16 @@ void TouchInputMapper::dispatchPointerMouse(nsecs_t when, uint32_t policyFlags) mPointerSimple.currentProperties.clear(); bool down, hovering; - if (!mCurrentMouseIdBits.isEmpty()) { - uint32_t id = mCurrentMouseIdBits.firstMarkedBit(); - uint32_t currentIndex = mCurrentRawPointerData.idToIndex[id]; - if (mLastMouseIdBits.hasBit(id)) { - uint32_t lastIndex = mCurrentRawPointerData.idToIndex[id]; - float deltaX = (mCurrentRawPointerData.pointers[currentIndex].x - - mLastRawPointerData.pointers[lastIndex].x) + if (!mCurrentCookedState.mouseIdBits.isEmpty()) { + uint32_t id = mCurrentCookedState.mouseIdBits.firstMarkedBit(); + uint32_t currentIndex = mCurrentRawState.rawPointerData.idToIndex[id]; + if (mLastCookedState.mouseIdBits.hasBit(id)) { + uint32_t lastIndex = mCurrentRawState.rawPointerData.idToIndex[id]; + float deltaX = (mCurrentRawState.rawPointerData.pointers[currentIndex].x + - mLastRawState.rawPointerData.pointers[lastIndex].x) * mPointerXMovementScale; - float deltaY = (mCurrentRawPointerData.pointers[currentIndex].y - - mLastRawPointerData.pointers[lastIndex].y) + float deltaY = (mCurrentRawState.rawPointerData.pointers[currentIndex].y + - mLastRawState.rawPointerData.pointers[lastIndex].y) * mPointerYMovementScale; rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); @@ -5482,20 +5872,20 @@ void TouchInputMapper::dispatchPointerMouse(nsecs_t when, uint32_t policyFlags) mPointerVelocityControl.reset(); } - down = isPointerDown(mCurrentButtonState); + down = isPointerDown(mCurrentRawState.buttonState); hovering = !down; float x, y; mPointerController->getPosition(&x, &y); mPointerSimple.currentCoords.copyFrom( - mCurrentCookedPointerData.pointerCoords[currentIndex]); + mCurrentCookedState.cookedPointerData.pointerCoords[currentIndex]); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, hovering ? 0.0f : 1.0f); mPointerSimple.currentProperties.id = 0; mPointerSimple.currentProperties.toolType = - mCurrentCookedPointerData.pointerProperties[currentIndex].toolType; + mCurrentCookedState.cookedPointerData.pointerProperties[currentIndex].toolType; } else { mPointerVelocityControl.reset(); @@ -5520,7 +5910,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, if (down || hovering) { mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); mPointerController->clearSpots(); - mPointerController->setButtonState(mCurrentButtonState); + mPointerController->setButtonState(mCurrentRawState.buttonState); mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) { mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); @@ -5532,7 +5922,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, // Send up. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_UP, 0, metaState, mLastButtonState, 0, + AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -5545,7 +5935,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, // Send hover exit. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastButtonState, 0, + AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -5560,7 +5950,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, // Send down. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_DOWN, 0, metaState, mCurrentButtonState, 0, + AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -5570,7 +5960,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, // Send move. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, mCurrentButtonState, 0, + AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -5584,7 +5974,8 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, // Send hover enter. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, mCurrentButtonState, 0, + AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState, + mCurrentRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -5594,7 +5985,8 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, // Send hover move. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, mCurrentButtonState, 0, + AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, + mCurrentRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -5602,9 +5994,9 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, getListener()->notifyMotion(&args); } - if (mCurrentRawVScroll || mCurrentRawHScroll) { - float vscroll = mCurrentRawVScroll; - float hscroll = mCurrentRawHScroll; + if (mCurrentRawState.rawVScroll || mCurrentRawState.rawHScroll) { + float vscroll = mCurrentRawState.rawVScroll; + float hscroll = mCurrentRawState.rawHScroll; mWheelYVelocityControl.move(when, NULL, &vscroll); mWheelXVelocityControl.move(when, &hscroll, NULL); @@ -5615,7 +6007,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_SCROLL, 0, metaState, mCurrentButtonState, 0, + AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.currentProperties, &pointerCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -5640,10 +6032,11 @@ void TouchInputMapper::abortPointerSimple(nsecs_t when, uint32_t policyFlags) { } void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, - int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, + int32_t action, int32_t actionButton, int32_t flags, + int32_t metaState, int32_t buttonState, int32_t edgeFlags, const PointerProperties* properties, const PointerCoords* coords, - const uint32_t* idToIndex, BitSet32 idBits, - int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) { + const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId, + float xPrecision, float yPrecision, nsecs_t downTime) { PointerCoords pointerCoords[MAX_POINTERS]; PointerProperties pointerProperties[MAX_POINTERS]; uint32_t pointerCount = 0; @@ -5677,7 +6070,7 @@ void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32 } NotifyMotionArgs args(when, getDeviceId(), source, policyFlags, - action, flags, metaState, buttonState, edgeFlags, + action, actionButton, flags, metaState, buttonState, edgeFlags, mViewport.displayId, pointerCount, pointerProperties, pointerCoords, xPrecision, yPrecision, downTime); getListener()->notifyMotion(&args); @@ -5717,6 +6110,11 @@ void TouchInputMapper::fadePointer() { } } +void TouchInputMapper::cancelTouch(nsecs_t when) { + abortPointerUsage(when, 0 /*policyFlags*/); + abortTouches(when, 0 /* policyFlags*/); +} + bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) { return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue && y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue; @@ -5745,11 +6143,11 @@ const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit( return NULL; } -void TouchInputMapper::assignPointerIds() { - uint32_t currentPointerCount = mCurrentRawPointerData.pointerCount; - uint32_t lastPointerCount = mLastRawPointerData.pointerCount; +void TouchInputMapper::assignPointerIds(const RawState* last, RawState* current) { + uint32_t currentPointerCount = current->rawPointerData.pointerCount; + uint32_t lastPointerCount = last->rawPointerData.pointerCount; - mCurrentRawPointerData.clearIdBits(); + current->rawPointerData.clearIdBits(); if (currentPointerCount == 0) { // No pointers to assign. @@ -5760,21 +6158,21 @@ void TouchInputMapper::assignPointerIds() { // All pointers are new. for (uint32_t i = 0; i < currentPointerCount; i++) { uint32_t id = i; - mCurrentRawPointerData.pointers[i].id = id; - mCurrentRawPointerData.idToIndex[id] = i; - mCurrentRawPointerData.markIdBit(id, mCurrentRawPointerData.isHovering(i)); + current->rawPointerData.pointers[i].id = id; + current->rawPointerData.idToIndex[id] = i; + current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(i)); } return; } if (currentPointerCount == 1 && lastPointerCount == 1 - && mCurrentRawPointerData.pointers[0].toolType - == mLastRawPointerData.pointers[0].toolType) { + && current->rawPointerData.pointers[0].toolType + == last->rawPointerData.pointers[0].toolType) { // Only one pointer and no change in count so it must have the same id as before. - uint32_t id = mLastRawPointerData.pointers[0].id; - mCurrentRawPointerData.pointers[0].id = id; - mCurrentRawPointerData.idToIndex[id] = 0; - mCurrentRawPointerData.markIdBit(id, mCurrentRawPointerData.isHovering(0)); + uint32_t id = last->rawPointerData.pointers[0].id; + current->rawPointerData.pointers[0].id = id; + current->rawPointerData.idToIndex[id] = 0; + current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(0)); return; } @@ -5792,9 +6190,9 @@ void TouchInputMapper::assignPointerIds() { for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount; lastPointerIndex++) { const RawPointerData::Pointer& currentPointer = - mCurrentRawPointerData.pointers[currentPointerIndex]; + current->rawPointerData.pointers[currentPointerIndex]; const RawPointerData::Pointer& lastPointer = - mLastRawPointerData.pointers[lastPointerIndex]; + last->rawPointerData.pointers[lastPointerIndex]; if (currentPointer.toolType == lastPointer.toolType) { int64_t deltaX = currentPointer.x - lastPointer.x; int64_t deltaY = currentPointer.y - lastPointer.y; @@ -5900,11 +6298,11 @@ void TouchInputMapper::assignPointerIds() { matchedCurrentBits.markBit(currentPointerIndex); matchedLastBits.markBit(lastPointerIndex); - uint32_t id = mLastRawPointerData.pointers[lastPointerIndex].id; - mCurrentRawPointerData.pointers[currentPointerIndex].id = id; - mCurrentRawPointerData.idToIndex[id] = currentPointerIndex; - mCurrentRawPointerData.markIdBit(id, - mCurrentRawPointerData.isHovering(currentPointerIndex)); + uint32_t id = last->rawPointerData.pointers[lastPointerIndex].id; + current->rawPointerData.pointers[currentPointerIndex].id = id; + current->rawPointerData.idToIndex[id] = currentPointerIndex; + current->rawPointerData.markIdBit(id, + current->rawPointerData.isHovering(currentPointerIndex)); usedIdBits.markBit(id); #if DEBUG_POINTER_ASSIGNMENT @@ -5920,10 +6318,10 @@ void TouchInputMapper::assignPointerIds() { uint32_t currentPointerIndex = matchedCurrentBits.markFirstUnmarkedBit(); uint32_t id = usedIdBits.markFirstUnmarkedBit(); - mCurrentRawPointerData.pointers[currentPointerIndex].id = id; - mCurrentRawPointerData.idToIndex[id] = currentPointerIndex; - mCurrentRawPointerData.markIdBit(id, - mCurrentRawPointerData.isHovering(currentPointerIndex)); + current->rawPointerData.pointers[currentPointerIndex].id = id; + current->rawPointerData.idToIndex[id] = currentPointerIndex; + current->rawPointerData.markIdBit(id, + current->rawPointerData.isHovering(currentPointerIndex)); #if DEBUG_POINTER_ASSIGNMENT ALOGD("assignPointerIds - assigned: cur=%d, id=%d", @@ -6002,18 +6400,18 @@ void SingleTouchInputMapper::process(const RawEvent* rawEvent) { mSingleTouchMotionAccumulator.process(rawEvent); } -void SingleTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) { +void SingleTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { if (mTouchButtonAccumulator.isToolActive()) { - mCurrentRawPointerData.pointerCount = 1; - mCurrentRawPointerData.idToIndex[0] = 0; + outState->rawPointerData.pointerCount = 1; + outState->rawPointerData.idToIndex[0] = 0; bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE && (mTouchButtonAccumulator.isHovering() || (mRawPointerAxes.pressure.valid && mSingleTouchMotionAccumulator.getAbsolutePressure() <= 0)); - mCurrentRawPointerData.markIdBit(0, isHovering); + outState->rawPointerData.markIdBit(0, isHovering); - RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[0]; + RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[0]; outPointer.id = 0; outPointer.x = mSingleTouchMotionAccumulator.getAbsoluteX(); outPointer.y = mSingleTouchMotionAccumulator.getAbsoluteY(); @@ -6074,7 +6472,7 @@ void MultiTouchInputMapper::process(const RawEvent* rawEvent) { mMultiTouchMotionAccumulator.process(rawEvent); } -void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) { +void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { size_t inCount = mMultiTouchMotionAccumulator.getSlotCount(); size_t outCount = 0; BitSet32 newPointerIdBits; @@ -6095,7 +6493,7 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) { break; // too many fingers! } - RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[outCount]; + RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[outCount]; outPointer.x = inSlot->getX(); outPointer.y = inSlot->getY(); outPointer.pressure = inSlot->getPressure(); @@ -6122,38 +6520,37 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) { outPointer.isHovering = isHovering; // Assign pointer id using tracking id if available. - if (*outHavePointerIds) { - int32_t trackingId = inSlot->getTrackingId(); - int32_t id = -1; - if (trackingId >= 0) { - for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) { - uint32_t n = idBits.clearFirstMarkedBit(); - if (mPointerTrackingIdMap[n] == trackingId) { - id = n; - } - } - - if (id < 0 && !mPointerIdBits.isFull()) { - id = mPointerIdBits.markFirstUnmarkedBit(); - mPointerTrackingIdMap[id] = trackingId; + mHavePointerIds = true; + int32_t trackingId = inSlot->getTrackingId(); + int32_t id = -1; + if (trackingId >= 0) { + for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) { + uint32_t n = idBits.clearFirstMarkedBit(); + if (mPointerTrackingIdMap[n] == trackingId) { + id = n; } } - if (id < 0) { - *outHavePointerIds = false; - mCurrentRawPointerData.clearIdBits(); - newPointerIdBits.clear(); - } else { - outPointer.id = id; - mCurrentRawPointerData.idToIndex[id] = outCount; - mCurrentRawPointerData.markIdBit(id, isHovering); - newPointerIdBits.markBit(id); + + if (id < 0 && !mPointerIdBits.isFull()) { + id = mPointerIdBits.markFirstUnmarkedBit(); + mPointerTrackingIdMap[id] = trackingId; } } + if (id < 0) { + mHavePointerIds = false; + outState->rawPointerData.clearIdBits(); + newPointerIdBits.clear(); + } else { + outPointer.id = id; + outState->rawPointerData.idToIndex[id] = outCount; + outState->rawPointerData.markIdBit(id, isHovering); + newPointerIdBits.markBit(id); + } outCount += 1; } - mCurrentRawPointerData.pointerCount = outCount; + outState->rawPointerData.pointerCount = outCount; mPointerIdBits = newPointerIdBits; mMultiTouchMotionAccumulator.finishSync(); @@ -6197,6 +6594,77 @@ bool MultiTouchInputMapper::hasStylus() const { || mTouchButtonAccumulator.hasStylus(); } +// --- ExternalStylusInputMapper + +ExternalStylusInputMapper::ExternalStylusInputMapper(InputDevice* device) : + InputMapper(device) { + +} + +uint32_t ExternalStylusInputMapper::getSources() { + return AINPUT_SOURCE_STYLUS; +} + +void ExternalStylusInputMapper::populateDeviceInfo(InputDeviceInfo* info) { + InputMapper::populateDeviceInfo(info); + info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, AINPUT_SOURCE_STYLUS, + 0.0f, 1.0f, 0.0f, 0.0f, 0.0f); +} + +void ExternalStylusInputMapper::dump(String8& dump) { + dump.append(INDENT2 "External Stylus Input Mapper:\n"); + dump.append(INDENT3 "Raw Stylus Axes:\n"); + dumpRawAbsoluteAxisInfo(dump, mRawPressureAxis, "Pressure"); + dump.append(INDENT3 "Stylus State:\n"); + dumpStylusState(dump, mStylusState); +} + +void ExternalStylusInputMapper::configure(nsecs_t when, + const InputReaderConfiguration* config, uint32_t changes) { + getAbsoluteAxisInfo(ABS_PRESSURE, &mRawPressureAxis); + mTouchButtonAccumulator.configure(getDevice()); +} + +void ExternalStylusInputMapper::reset(nsecs_t when) { + InputDevice* device = getDevice(); + mSingleTouchMotionAccumulator.reset(device); + mTouchButtonAccumulator.reset(device); + InputMapper::reset(when); +} + +void ExternalStylusInputMapper::process(const RawEvent* rawEvent) { + mSingleTouchMotionAccumulator.process(rawEvent); + mTouchButtonAccumulator.process(rawEvent); + + if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { + sync(rawEvent->when); + } +} + +void ExternalStylusInputMapper::sync(nsecs_t when) { + mStylusState.clear(); + + mStylusState.when = when; + + mStylusState.toolType = mTouchButtonAccumulator.getToolType(); + if (mStylusState.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { + mStylusState.toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + } + + int32_t pressure = mSingleTouchMotionAccumulator.getAbsolutePressure(); + if (mRawPressureAxis.valid) { + mStylusState.pressure = float(pressure) / mRawPressureAxis.maxValue; + } else if (mTouchButtonAccumulator.isToolActive()) { + mStylusState.pressure = 1.0f; + } else { + mStylusState.pressure = 0.0f; + } + + mStylusState.buttons = mTouchButtonAccumulator.getButtonState(); + + mContext->dispatchExternalStylusState(mStylusState); +} + // --- JoystickInputMapper --- @@ -6520,7 +6988,7 @@ void JoystickInputMapper::sync(nsecs_t when, bool force) { uint32_t policyFlags = 0; NotifyMotionArgs args(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, policyFlags, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, + AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, ADISPLAY_ID_NONE, 1, &pointerProperties, &pointerCoords, 0, 0, 0); getListener()->notifyMotion(&args); } diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h index c5896d4591..7cb4680ce7 100644 --- a/services/inputflinger/InputReader.h +++ b/services/inputflinger/InputReader.h @@ -139,7 +139,10 @@ struct InputReaderConfiguration { CHANGE_DEVICE_ALIAS = 1 << 5, // The location calibration matrix changed. - TOUCH_AFFINE_TRANSFORMATION = 1 << 6, + CHANGE_TOUCH_AFFINE_TRANSFORMATION = 1 << 6, + + // The presence of an external stylus has changed. + CHANGE_EXTERNAL_STYLUS_PRESENCE = 1 << 7, // All devices must be reopened. CHANGE_MUST_REOPEN = 1 << 31, @@ -371,6 +374,31 @@ public: virtual void cancelVibrate(int32_t deviceId, int32_t token) = 0; }; +struct StylusState { + /* Time the stylus event was received. */ + nsecs_t when; + /* Pressure as reported by the stylus, normalized to the range [0, 1.0]. */ + float pressure; + /* The state of the stylus buttons as a bitfield (e.g. AMOTION_EVENT_BUTTON_SECONDARY). */ + uint32_t buttons; + /* Which tool type the stylus is currently using (e.g. AMOTION_EVENT_TOOL_TYPE_ERASER). */ + int32_t toolType; + + void copyFrom(const StylusState& other) { + when = other.when; + pressure = other.pressure; + buttons = other.buttons; + toolType = other.toolType; + } + + void clear() { + when = LLONG_MAX; + pressure = 0.f; + buttons = 0; + toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN; + } +}; + /* Internal interface used by individual input devices to access global input device state * and parameters maintained by the input reader. @@ -392,6 +420,9 @@ public: virtual void requestTimeoutAtTime(nsecs_t when) = 0; virtual int32_t bumpGeneration() = 0; + virtual void getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices) = 0; + virtual void dispatchExternalStylusState(const StylusState& outState) = 0; + virtual InputReaderPolicyInterface* getPolicy() = 0; virtual InputListenerInterface* getListener() = 0; virtual EventHubInterface* getEventHub() = 0; @@ -458,6 +489,8 @@ protected: virtual void fadePointer(); virtual void requestTimeoutAtTime(nsecs_t when); virtual int32_t bumpGeneration(); + virtual void getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices); + virtual void dispatchExternalStylusState(const StylusState& outState); virtual InputReaderPolicyInterface* getPolicy(); virtual InputListenerInterface* getListener(); virtual EventHubInterface* getEventHub(); @@ -496,6 +529,10 @@ private: void updateGlobalMetaStateLocked(); int32_t getGlobalMetaStateLocked(); + void notifyExternalStylusPresenceChanged(); + void getExternalStylusDevicesLocked(Vector<InputDeviceInfo>& outDevices); + void dispatchExternalStylusState(const StylusState& state); + void fadePointerLocked(); int32_t mGeneration; @@ -555,6 +592,9 @@ public: inline bool isExternal() { return mIsExternal; } inline void setExternal(bool external) { mIsExternal = external; } + inline void setMic(bool hasMic) { mHasMic = hasMic; } + inline bool hasMic() const { return mHasMic; } + inline bool isIgnored() { return mMappers.isEmpty(); } void dump(String8& dump); @@ -563,6 +603,7 @@ public: void reset(nsecs_t when); void process(const RawEvent* rawEvents, size_t count); void timeoutExpired(nsecs_t when); + void updateExternalStylusState(const StylusState& state); void getDeviceInfo(InputDeviceInfo* outDeviceInfo); int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); @@ -572,6 +613,7 @@ public: const int32_t* keyCodes, uint8_t* outFlags); void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token); void cancelVibrate(int32_t token); + void cancelTouch(nsecs_t when); int32_t getMetaState(); @@ -617,6 +659,7 @@ private: uint32_t mSources; bool mIsExternal; + bool mHasMic; bool mDropUntilNextSync; typedef int32_t (InputMapper::*GetStateFunc)(uint32_t sourceMask, int32_t code); @@ -830,9 +873,21 @@ struct CookedPointerData { return pointerCoords[idToIndex[id]]; } - inline bool isHovering(uint32_t pointerIndex) { + inline PointerCoords& editPointerCoordsWithId(uint32_t id) { + return pointerCoords[idToIndex[id]]; + } + + inline PointerProperties& editPointerPropertiesWithId(uint32_t id) { + return pointerProperties[idToIndex[id]]; + } + + inline bool isHovering(uint32_t pointerIndex) const { return hoveringIdBits.hasBit(pointerProperties[pointerIndex].id); } + + inline bool isTouching(uint32_t pointerIndex) const { + return touchingIdBits.hasBit(pointerProperties[pointerIndex].id); + } }; @@ -973,9 +1028,12 @@ public: virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token); virtual void cancelVibrate(int32_t token); + virtual void cancelTouch(nsecs_t when); virtual int32_t getMetaState(); + virtual void updateExternalStylusState(const StylusState& state); + virtual void fadePointer(); protected: @@ -987,6 +1045,7 @@ protected: static void dumpRawAbsoluteAxisInfo(String8& dump, const RawAbsoluteAxisInfo& axis, const char* name); + static void dumpStylusState(String8& dump, const StylusState& state); }; @@ -1191,7 +1250,9 @@ public: const int32_t* keyCodes, uint8_t* outFlags); virtual void fadePointer(); + virtual void cancelTouch(nsecs_t when); virtual void timeoutExpired(nsecs_t when); + virtual void updateExternalStylusState(const StylusState& state); protected: CursorButtonAccumulator mCursorButtonAccumulator; @@ -1331,36 +1392,86 @@ protected: // Affine location transformation/calibration struct TouchAffineTransformation mAffineTransform; - // Raw pointer axis information from the driver. RawPointerAxes mRawPointerAxes; - // Raw pointer sample data. - RawPointerData mCurrentRawPointerData; - RawPointerData mLastRawPointerData; + struct RawState { + nsecs_t when; + + // Raw pointer sample data. + RawPointerData rawPointerData; + + int32_t buttonState; + + // Scroll state. + int32_t rawVScroll; + int32_t rawHScroll; + + void copyFrom(const RawState& other) { + when = other.when; + rawPointerData.copyFrom(other.rawPointerData); + buttonState = other.buttonState; + rawVScroll = other.rawVScroll; + rawHScroll = other.rawHScroll; + } + + void clear() { + when = 0; + rawPointerData.clear(); + buttonState = 0; + rawVScroll = 0; + rawHScroll = 0; + } + }; + + struct CookedState { + // Cooked pointer sample data. + CookedPointerData cookedPointerData; - // Cooked pointer sample data. - CookedPointerData mCurrentCookedPointerData; - CookedPointerData mLastCookedPointerData; + // Id bits used to differentiate fingers, stylus and mouse tools. + BitSet32 fingerIdBits; + BitSet32 stylusIdBits; + BitSet32 mouseIdBits; - // Button state. - int32_t mCurrentButtonState; - int32_t mLastButtonState; + int32_t buttonState; - // Scroll state. - int32_t mCurrentRawVScroll; - int32_t mCurrentRawHScroll; + void copyFrom(const CookedState& other) { + cookedPointerData.copyFrom(other.cookedPointerData); + fingerIdBits = other.fingerIdBits; + stylusIdBits = other.stylusIdBits; + mouseIdBits = other.mouseIdBits; + buttonState = other.buttonState; + } - // Id bits used to differentiate fingers, stylus and mouse tools. - BitSet32 mCurrentFingerIdBits; // finger or unknown - BitSet32 mLastFingerIdBits; - BitSet32 mCurrentStylusIdBits; // stylus or eraser - BitSet32 mLastStylusIdBits; - BitSet32 mCurrentMouseIdBits; // mouse or lens - BitSet32 mLastMouseIdBits; + void clear() { + cookedPointerData.clear(); + fingerIdBits.clear(); + stylusIdBits.clear(); + mouseIdBits.clear(); + buttonState = 0; + } + }; + + Vector<RawState> mRawStatesPending; + RawState mCurrentRawState; + CookedState mCurrentCookedState; + RawState mLastRawState; + CookedState mLastCookedState; + + // State provided by an external stylus + StylusState mExternalStylusState; + int64_t mExternalStylusId; + nsecs_t mExternalStylusFusionTimeout; + bool mExternalStylusDataPending; // True if we sent a HOVER_ENTER event. bool mSentHoverEnter; + // Have we assigned pointer IDs for this stream + bool mHavePointerIds; + + // Is the current stream of direct touch events aborted + bool mCurrentMotionAborted; + // The time the primary pointer last went down. nsecs_t mDownTime; @@ -1380,11 +1491,13 @@ protected: virtual void parseCalibration(); virtual void resolveCalibration(); virtual void dumpCalibration(String8& dump); + virtual void updateAffineTransformation(); virtual void dumpAffineTransformation(String8& dump); + virtual void resolveExternalStylusPresence(); virtual bool hasStylus() const = 0; - virtual void updateAffineTransformation(); + virtual bool hasExternalStylus() const; - virtual void syncTouch(nsecs_t when, bool* outHavePointerIds) = 0; + virtual void syncTouch(nsecs_t when, RawState* outState) = 0; private: // The current viewport. @@ -1430,6 +1543,8 @@ private: float mTiltYCenter; float mTiltYScale; + bool mExternalStylusConnected; + // Oriented motion ranges for input device info. struct OrientedRanges { InputDeviceInfo::MotionRange x; @@ -1672,16 +1787,25 @@ private: VelocityControl mWheelXVelocityControl; VelocityControl mWheelYVelocityControl; + void resetExternalStylus(); + void clearStylusDataPendingFlags(); + void sync(nsecs_t when); bool consumeRawTouches(nsecs_t when, uint32_t policyFlags); + void processRawTouches(bool timeout); + void cookAndDispatch(nsecs_t when); void dispatchVirtualKey(nsecs_t when, uint32_t policyFlags, int32_t keyEventAction, int32_t keyEventFlags); void dispatchTouches(nsecs_t when, uint32_t policyFlags); void dispatchHoverExit(nsecs_t when, uint32_t policyFlags); void dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags); + void dispatchButtonRelease(nsecs_t when, uint32_t policyFlags); + void dispatchButtonPress(nsecs_t when, uint32_t policyFlags); + const BitSet32& findActiveIdBits(const CookedPointerData& cookedPointerData); void cookPointerData(); + void abortTouches(nsecs_t when, uint32_t policyFlags); void dispatchPointerUsage(nsecs_t when, uint32_t policyFlags, PointerUsage pointerUsage); void abortPointerUsage(nsecs_t when, uint32_t policyFlags); @@ -1702,13 +1826,17 @@ private: bool down, bool hovering); void abortPointerSimple(nsecs_t when, uint32_t policyFlags); + bool assignExternalStylusId(const RawState& state, bool timeout); + void applyExternalStylusButtonState(nsecs_t when); + void applyExternalStylusTouchState(nsecs_t when); + // Dispatches a motion event. // If the changedId is >= 0 and the action is POINTER_DOWN or POINTER_UP, the // method will take care of setting the index and transmuting the action to DOWN or UP // it is the first / last pointer to go down / up. void dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, - int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, - int32_t edgeFlags, + int32_t action, int32_t actionButton, + int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, const PointerProperties* properties, const PointerCoords* coords, const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime); @@ -1723,7 +1851,7 @@ private: bool isPointInsideSurface(int32_t x, int32_t y); const VirtualKey* findVirtualKeyHit(int32_t x, int32_t y); - void assignPointerIds(); + static void assignPointerIds(const RawState* last, RawState* current); }; @@ -1736,7 +1864,7 @@ public: virtual void process(const RawEvent* rawEvent); protected: - virtual void syncTouch(nsecs_t when, bool* outHavePointerIds); + virtual void syncTouch(nsecs_t when, RawState* outState); virtual void configureRawPointerAxes(); virtual bool hasStylus() const; @@ -1754,7 +1882,7 @@ public: virtual void process(const RawEvent* rawEvent); protected: - virtual void syncTouch(nsecs_t when, bool* outHavePointerIds); + virtual void syncTouch(nsecs_t when, RawState* outState); virtual void configureRawPointerAxes(); virtual bool hasStylus() const; @@ -1766,6 +1894,27 @@ private: int32_t mPointerTrackingIdMap[MAX_POINTER_ID + 1]; }; +class ExternalStylusInputMapper : public InputMapper { +public: + ExternalStylusInputMapper(InputDevice* device); + virtual ~ExternalStylusInputMapper() = default; + + virtual uint32_t getSources(); + virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); + virtual void dump(String8& dump); + virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); + virtual void reset(nsecs_t when); + virtual void process(const RawEvent* rawEvent); + virtual void sync(nsecs_t when); + +private: + SingleTouchMotionAccumulator mSingleTouchMotionAccumulator; + RawAbsoluteAxisInfo mRawPressureAxis; + TouchButtonAccumulator mTouchButtonAccumulator; + + StylusState mStylusState; +}; + class JoystickInputMapper : public InputMapper { public: diff --git a/services/inputflinger/InputWindow.cpp b/services/inputflinger/InputWindow.cpp index fda3ffa2bb..1b913c51b3 100644 --- a/services/inputflinger/InputWindow.cpp +++ b/services/inputflinger/InputWindow.cpp @@ -36,14 +36,16 @@ bool InputWindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const { } bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const { - return x >= frameLeft && x <= frameRight - && y >= frameTop && y <= frameBottom; + return x >= frameLeft && x < frameRight + && y >= frameTop && y < frameBottom; } bool InputWindowInfo::isTrustedOverlay() const { return layoutParamsType == TYPE_INPUT_METHOD || layoutParamsType == TYPE_INPUT_METHOD_DIALOG || layoutParamsType == TYPE_MAGNIFICATION_OVERLAY + || layoutParamsType == TYPE_STATUS_BAR + || layoutParamsType == TYPE_NAVIGATION_BAR || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY; } @@ -51,6 +53,11 @@ bool InputWindowInfo::supportsSplitTouch() const { return layoutParamsFlags & FLAG_SPLIT_TOUCH; } +bool InputWindowInfo::overlaps(const InputWindowInfo* other) const { + return frameLeft < other->frameRight && frameRight > other->frameLeft + && frameTop < other->frameBottom && frameBottom > other->frameTop; +} + // --- InputWindowHandle --- diff --git a/services/inputflinger/InputWindow.h b/services/inputflinger/InputWindow.h index 42457ce410..0ac7fce549 100644 --- a/services/inputflinger/InputWindow.h +++ b/services/inputflinger/InputWindow.h @@ -146,6 +146,8 @@ struct InputWindowInfo { bool isTrustedOverlay() const; bool supportsSplitTouch() const; + + bool overlaps(const InputWindowInfo* other) const; }; diff --git a/services/inputflinger/host/Android.mk b/services/inputflinger/host/Android.mk new file mode 100644 index 0000000000..b82817545b --- /dev/null +++ b/services/inputflinger/host/Android.mk @@ -0,0 +1,62 @@ +# Copyright (C) 2015 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. + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_CLANG := true + +LOCAL_SRC_FILES:= \ + InputFlinger.cpp \ + InputDriver.cpp \ + InputHost.cpp + +LOCAL_SHARED_LIBRARIES := \ + libbinder \ + libcrypto \ + libcutils \ + libinput \ + liblog \ + libutils \ + libhardware + + +# TODO: Move inputflinger to its own process and mark it hidden +#LOCAL_CFLAGS += -fvisibility=hidden + +LOCAL_CFLAGS += -Wno-unused-parameter + +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) + +LOCAL_MODULE := libinputflingerhost + +include $(BUILD_SHARED_LIBRARY) + +######################################################################## +# build input flinger executable +include $(CLEAR_VARS) + +LOCAL_CLANG := true + +LOCAL_SRC_FILES:= \ + main.cpp + +LOCAL_SHARED_LIBRARIES := \ + libbinder \ + libinputflingerhost \ + libutils + +LOCAL_MODULE := inputflinger + +include $(BUILD_EXECUTABLE) diff --git a/services/inputflinger/host/InputDriver.cpp b/services/inputflinger/host/InputDriver.cpp new file mode 100644 index 0000000000..630a596b7b --- /dev/null +++ b/services/inputflinger/host/InputDriver.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2015 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 <stdint.h> +#include <sys/types.h> + +#define LOG_TAG "InputDriver" + +#define LOG_NDEBUG 0 + +#include "InputDriver.h" +#include "InputHost.h" + +#include <hardware/input.h> +#include <utils/Log.h> +#include <utils/String8.h> + +#define INDENT2 " " + +namespace android { + +static input_host_callbacks_t kCallbacks = { + .create_device_identifier = create_device_identifier, + .create_device_definition = create_device_definition, + .create_input_report_definition = create_input_report_definition, + .create_output_report_definition = create_output_report_definition, + .input_device_definition_add_report = input_device_definition_add_report, + .input_report_definition_add_collection = input_report_definition_add_collection, + .input_report_definition_declare_usage_int = input_report_definition_declare_usage_int, + .input_report_definition_declare_usages_bool = input_report_definition_declare_usages_bool, + .register_device = register_device, + .input_allocate_report = input_allocate_report, + .input_report_set_usage_int = input_report_set_usage_int, + .input_report_set_usage_bool = input_report_set_usage_bool, + .report_event = report_event, + .input_get_device_property_map = input_get_device_property_map, + .input_get_device_property = input_get_device_property, + .input_get_property_key = input_get_property_key, + .input_get_property_value = input_get_property_value, + .input_free_device_property = input_free_device_property, + .input_free_device_property_map = input_free_device_property_map, +}; + +InputDriver::InputDriver(const char* name) : mName(String8(name)) { + const hw_module_t* module; + int err = input_open(&module, name); + LOG_ALWAYS_FATAL_IF(err != 0, "Input module %s not found", name); + mHal = reinterpret_cast<const input_module_t*>(module); +} + +void InputDriver::init(InputHostInterface* host) { + mHal->init(mHal, static_cast<input_host_t*>(host), kCallbacks); +} + +void InputDriver::dump(String8& result) { + result.appendFormat(INDENT2 "HAL Input Driver (%s)\n", mName.string()); +} + + +// HAL wrapper functions + +input_device_identifier_t* create_device_identifier(input_host_t* host, + const char* name, int32_t product_id, int32_t vendor_id, + input_bus_t bus, const char* unique_id) { + return nullptr; +} + +input_device_definition_t* create_device_definition(input_host_t* host) { + return nullptr; +} + +input_report_definition_t* create_input_report_definition(input_host_t* host) { + return nullptr; +} + +input_report_definition_t* create_output_report_definition(input_host_t* host) { + return nullptr; +} + +void input_device_definition_add_report(input_host_t* host, + input_device_definition_t* d, input_report_definition_t* r) { } + +void input_report_definition_add_collection(input_host_t* host, + input_report_definition_t* report, input_collection_id_t id, int32_t arity) { } + +void input_report_definition_declare_usage_int(input_host_t* host, + input_report_definition_t* report, input_collection_id_t id, + input_usage_t usage, int32_t min, int32_t max, float resolution) { } + +void input_report_definition_declare_usages_bool(input_host_t* host, + input_report_definition_t* report, input_collection_id_t id, + input_usage_t* usage, size_t usage_count) { } + + +input_device_handle_t* register_device(input_host_t* host, + input_device_identifier_t* id, input_device_definition_t* d) { + return nullptr; +} + +input_report_t* input_allocate_report(input_host_t* host, input_report_definition_t* r) { + return nullptr; +} +void input_report_set_usage_int(input_host_t* host, input_report_t* r, + input_collection_id_t id, input_usage_t usage, int32_t value, int32_t arity_index) { } + +void input_report_set_usage_bool(input_host_t* host, input_report_t* r, + input_collection_id_t id, input_usage_t usage, bool value, int32_t arity_index) { } + +void report_event(input_host_t* host, input_device_handle_t* d, input_report_t* report) { } + +input_property_map_t* input_get_device_property_map(input_host_t* host, + input_device_identifier_t* id) { + return nullptr; +} + +input_property_t* input_get_device_property(input_host_t* host, input_property_map_t* map, + const char* key) { + return nullptr; +} + +const char* input_get_property_key(input_host_t* host, input_property_t* property) { + return nullptr; +} + +const char* input_get_property_value(input_host_t* host, input_property_t* property) { + return nullptr; +} + +void input_free_device_property(input_host_t* host, input_property_t* property) { } + +void input_free_device_property_map(input_host_t* host, input_property_map_t* map) { } + +} // namespace android diff --git a/services/inputflinger/host/InputDriver.h b/services/inputflinger/host/InputDriver.h new file mode 100644 index 0000000000..7734ac2962 --- /dev/null +++ b/services/inputflinger/host/InputDriver.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2015 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_INPUT_DRIVER_H +#define ANDROID_INPUT_DRIVER_H + +#include <stdint.h> +#include <sys/types.h> + +#include "InputHost.h" + +#include <hardware/input.h> +#include <utils/RefBase.h> +#include <utils/String8.h> + +namespace android { + +class InputHostInterface; + +class InputDriverInterface : public virtual RefBase { +protected: + InputDriverInterface() = default; + virtual ~InputDriverInterface() = default; + +public: + virtual void init(InputHostInterface* host) = 0; + + virtual void dump(String8& result) = 0; +}; + +class InputDriver : public InputDriverInterface { +public: + InputDriver(const char* name); + virtual ~InputDriver() = default; + + virtual void init(InputHostInterface* host) override; + + virtual void dump(String8& result) override; + +private: + String8 mName; + const input_module_t* mHal; +}; + + +extern "C" { + +input_device_identifier_t* create_device_identifier(input_host_t* host, + const char* name, int32_t product_id, int32_t vendor_id, + input_bus_t bus, const char* unique_id); + +input_device_definition_t* create_device_definition(input_host_t* host); + +input_report_definition_t* create_input_report_definition(input_host_t* host); + +input_report_definition_t* create_output_report_definition(input_host_t* host); + +void input_device_definition_add_report(input_host_t* host, + input_device_definition_t* d, input_report_definition_t* r); + +void input_report_definition_add_collection(input_host_t* host, + input_report_definition_t* report, input_collection_id_t id, int32_t arity); + +void input_report_definition_declare_usage_int(input_host_t* host, + input_report_definition_t* report, input_collection_id_t id, + input_usage_t usage, int32_t min, int32_t max, float resolution); + +void input_report_definition_declare_usages_bool(input_host_t* host, + input_report_definition_t* report, input_collection_id_t id, + input_usage_t* usage, size_t usage_count); + + +input_device_handle_t* register_device(input_host_t* host, + input_device_identifier_t* id, input_device_definition_t* d); + +void unregister_device(input_host_t* host, input_device_handle_t* handle); + +input_report_t* input_allocate_report(input_host_t* host, input_report_definition_t* r); + +void input_report_set_usage_int(input_host_t* host, input_report_t* r, + input_collection_id_t id, input_usage_t usage, int32_t value, int32_t arity_index); + +void input_report_set_usage_bool(input_host_t* host, input_report_t* r, + input_collection_id_t id, input_usage_t usage, bool value, int32_t arity_index); + +void report_event(input_host_t* host, input_device_handle_t* d, input_report_t* report); + +input_property_map_t* input_get_device_property_map(input_host_t* host, + input_device_identifier_t* id); + +input_property_t* input_get_device_property(input_host_t* host, input_property_map_t* map, + const char* key); + +const char* input_get_property_key(input_host_t* host, input_property_t* property); + +const char* input_get_property_value(input_host_t* host, input_property_t* property); + +void input_free_device_property(input_host_t* host, input_property_t* property); + +void input_free_device_property_map(input_host_t* host, input_property_map_t* map); +} + +} // namespace android +#endif // ANDROID_INPUT_DRIVER_H diff --git a/services/inputflinger/host/InputFlinger.cpp b/services/inputflinger/host/InputFlinger.cpp new file mode 100644 index 0000000000..859c3b8332 --- /dev/null +++ b/services/inputflinger/host/InputFlinger.cpp @@ -0,0 +1,71 @@ +/* + * 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. + */ + +#define LOG_TAG "InputFlinger" + + +#include <stdint.h> +#include <unistd.h> + +#include <sys/types.h> + +#include "InputFlinger.h" +#include "InputDriver.h" + +#include <binder/IPCThreadState.h> +#include <binder/PermissionCache.h> +#include <hardware/input.h> +#include <cutils/log.h> +#include <private/android_filesystem_config.h> + +namespace android { + +const String16 sAccessInputFlingerPermission("android.permission.ACCESS_INPUT_FLINGER"); +const String16 sDumpPermission("android.permission.DUMP"); + + +InputFlinger::InputFlinger() : + BnInputFlinger() { + ALOGI("InputFlinger is starting"); + mHost = new InputHost(); + mHost->registerInputDriver(new InputDriver(INPUT_INSTANCE_EVDEV)); +} + +InputFlinger::~InputFlinger() { +} + +status_t InputFlinger::dump(int fd, const Vector<String16>& args) { + String8 result; + const IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + if ((uid != AID_SHELL) + && !PermissionCache::checkPermission(sDumpPermission, pid, uid)) { + result.appendFormat("Permission Denial: " + "can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid); + } else { + dumpInternal(result); + } + write(fd, result.string(), result.size()); + return OK; +} + +void InputFlinger::dumpInternal(String8& result) { + result.append("INPUT FLINGER (dumpsys inputflinger)\n"); + mHost->dump(result); +} + +}; // namespace android diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h new file mode 100644 index 0000000000..39e69e5efc --- /dev/null +++ b/services/inputflinger/host/InputFlinger.h @@ -0,0 +1,53 @@ +/* + * 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. + */ + +#ifndef ANDROID_INPUT_FLINGER_H +#define ANDROID_INPUT_FLINGER_H + +#include <stdint.h> +#include <sys/types.h> + +#include "InputHost.h" + +#include <cutils/compiler.h> +#include <input/IInputFlinger.h> +#include <utils/String8.h> +#include <utils/String16.h> +#include <utils/StrongPointer.h> + +namespace android { + +class InputFlinger : public BnInputFlinger { +public: + static char const* getServiceName() ANDROID_API { + return "inputflinger"; + } + + InputFlinger() ANDROID_API; + + virtual status_t dump(int fd, const Vector<String16>& args); + +private: + virtual ~InputFlinger(); + + void dumpInternal(String8& result); + + sp<InputHostInterface> mHost; +}; + +} // namespace android + +#endif // ANDROID_INPUT_FLINGER_H diff --git a/services/inputflinger/host/InputHost.cpp b/services/inputflinger/host/InputHost.cpp new file mode 100644 index 0000000000..51d3e6b579 --- /dev/null +++ b/services/inputflinger/host/InputHost.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2015 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 <vector> + +#include "InputDriver.h" +#include "InputHost.h" + +#include <utils/Log.h> +#include <utils/String8.h> + +#define INDENT " " + +namespace android { + +void InputHost::registerInputDriver(InputDriverInterface* driver) { + LOG_ALWAYS_FATAL_IF(driver == nullptr, "Cannot register a nullptr as an InputDriver!"); + driver->init(this); + mDrivers.push_back(driver); +} + +void InputHost::dump(String8& result) { + result.append(INDENT "Input Drivers:\n"); + for (size_t i = 0; i < mDrivers.size(); i++) { + mDrivers[i]->dump(result); + } +} + +} // namespace android diff --git a/services/inputflinger/host/InputHost.h b/services/inputflinger/host/InputHost.h new file mode 100644 index 0000000000..42a66e073e --- /dev/null +++ b/services/inputflinger/host/InputHost.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2015 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_INPUT_HOST_H +#define ANDROID_INPUT_HOST_H + +#include <vector> + +#include <hardware/input.h> +#include <utils/RefBase.h> +#include <utils/String8.h> +#include <utils/StrongPointer.h> + +#include "InputDriver.h" + +// Declare a concrete type for the HAL +struct input_host { +}; + +namespace android { + +class InputDriverInterface; + +class InputHostInterface : public input_host_t, public virtual RefBase { +protected: + InputHostInterface() = default; + virtual ~InputHostInterface() = default; + +public: + + virtual void registerInputDriver(InputDriverInterface* driver) = 0; + + virtual void dump(String8& result) = 0; +}; + +class InputHost : public InputHostInterface { +public: + InputHost() = default; + + virtual void registerInputDriver(InputDriverInterface* driver) override; + + virtual void dump(String8& result) override; + +private: + std::vector<sp<InputDriverInterface>> mDrivers; +}; + +} // namespace android +#endif // ANDRIOD_INPUT_HOST_H diff --git a/services/inputflinger/host/main.cpp b/services/inputflinger/host/main.cpp new file mode 100644 index 0000000000..0a517cc5d9 --- /dev/null +++ b/services/inputflinger/host/main.cpp @@ -0,0 +1,26 @@ +/* + * 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 <binder/BinderService.h> +#include "InputFlinger.h" + +using namespace android; + +int main(int, char**) { + ProcessState::self()->setThreadPoolMaxThreadCount(4); + BinderService<InputFlinger>::publishAndJoinThreadPool(true); + return 0; +} diff --git a/services/inputflinger/tests/Android.mk b/services/inputflinger/tests/Android.mk index 6dae82f404..4c433929ef 100644 --- a/services/inputflinger/tests/Android.mk +++ b/services/inputflinger/tests/Android.mk @@ -10,37 +10,26 @@ test_src_files := \ shared_libraries := \ libcutils \ liblog \ - libandroidfw \ libutils \ libhardware \ libhardware_legacy \ libui \ libskia \ - libstlport \ libinput \ libinputflinger \ libinputservice -static_libraries := \ - libgtest \ - libgtest_main - c_includes := \ - bionic \ - bionic/libstdc++/include \ - external/gtest/include \ - external/stlport/stlport \ external/skia/include/core -module_tags := eng tests +module_tags := tests $(foreach file,$(test_src_files), \ $(eval include $(CLEAR_VARS)) \ $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \ - $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \ $(eval LOCAL_C_INCLUDES := $(c_includes)) \ - $(eval LOCAL_CFLAGS += -Wno-unused-parameter) \ + $(eval LOCAL_CFLAGS += -Wno-unused-parameter) \ $(eval LOCAL_SRC_FILES := $(file)) \ $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \ $(eval LOCAL_MODULE_TAGS := $(module_tags)) \ diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 7aac6edfe1..2d8eaefa65 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -49,51 +49,49 @@ public: } private: - virtual void notifyConfigurationChanged(nsecs_t when) { + virtual void notifyConfigurationChanged(nsecs_t) { } - virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle, - const sp<InputWindowHandle>& inputWindowHandle, - const String8& reason) { + virtual nsecs_t notifyANR(const sp<InputApplicationHandle>&, + const sp<InputWindowHandle>&, + const String8&) { return 0; } - virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) { + virtual void notifyInputChannelBroken(const sp<InputWindowHandle>&) { } virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) { *outConfig = mConfig; } - virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) { + virtual bool filterInputEvent(const InputEvent*, uint32_t) { return true; } - virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) { + virtual void interceptKeyBeforeQueueing(const KeyEvent*, uint32_t&) { } - virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) { + virtual void interceptMotionBeforeQueueing(nsecs_t, uint32_t&) { } - virtual nsecs_t interceptKeyBeforeDispatching(const sp<InputWindowHandle>& inputWindowHandle, - const KeyEvent* keyEvent, uint32_t policyFlags) { + virtual nsecs_t interceptKeyBeforeDispatching(const sp<InputWindowHandle>&, + const KeyEvent*, uint32_t) { return 0; } - virtual bool dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle, - const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) { + virtual bool dispatchUnhandledKey(const sp<InputWindowHandle>&, + const KeyEvent*, uint32_t, KeyEvent*) { return false; } - virtual void notifySwitch(nsecs_t when, - uint32_t switchValues, uint32_t switchMask, uint32_t policyFlags) { + virtual void notifySwitch(nsecs_t, uint32_t, uint32_t, uint32_t) { } - virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) { + virtual void pokeUserActivity(nsecs_t, int32_t) { } - virtual bool checkInjectEventsPermissionNonReentrant( - int32_t injectorPid, int32_t injectorUid) { + virtual bool checkInjectEventsPermissionNonReentrant(int32_t, int32_t) { return false; } }; @@ -152,7 +150,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { // Rejects undefined motion actions. event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - /*action*/ -1, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, + /*action*/ -1, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( @@ -163,7 +161,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { // Rejects pointer down with invalid index. event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, + 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( @@ -173,7 +171,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_POINTER_DOWN | (-1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, + 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( @@ -184,7 +182,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { // Rejects pointer up with invalid index. event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, + 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( @@ -194,7 +192,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_POINTER_UP | (-1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, + 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( @@ -204,7 +202,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { // Rejects motion events with invalid number of pointers. event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, + AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 0, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( @@ -213,7 +211,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { << "Should reject motion events with 0 pointers."; event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, + AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( @@ -224,7 +222,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { // Rejects motion events with invalid pointer ids. pointerProperties[0].id = -1; event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, + AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( @@ -234,7 +232,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { pointerProperties[0].id = MAX_POINTER_ID + 1; event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, + AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( @@ -246,7 +244,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { pointerProperties[0].id = 1; pointerProperties[1].id = 1; event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, - AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, + AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 2, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index c6eb1fdd15..f34b810f1b 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -104,17 +104,16 @@ private: if (mY > mMaxY) mY = mMaxY; } - virtual void fade(Transition transition) { + virtual void fade(Transition) { } - virtual void unfade(Transition transition) { + virtual void unfade(Transition) { } - virtual void setPresentation(Presentation presentation) { + virtual void setPresentation(Presentation) { } - virtual void setSpots(const PointerCoords* spotCoords, - const uint32_t* spotIdToIndex, BitSet32 spotIdBits) { + virtual void setSpots(const PointerCoords*, const uint32_t*, BitSet32) { } virtual void clearSpots() { @@ -196,11 +195,11 @@ private: mInputDevices = inputDevices; } - virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const InputDeviceIdentifier& identifier) { + virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const InputDeviceIdentifier&) { return NULL; } - virtual String8 getDeviceAlias(const InputDeviceIdentifier& identifier) { + virtual String8 getDeviceAlias(const InputDeviceIdentifier&) { return String8::empty(); } }; @@ -482,7 +481,7 @@ private: return device ? device->identifier : InputDeviceIdentifier(); } - virtual int32_t getDeviceControllerNumber(int32_t deviceId) const { + virtual int32_t getDeviceControllerNumber(int32_t) const { return 0; } @@ -515,7 +514,7 @@ private: return false; } - virtual bool hasInputProperty(int32_t deviceId, int property) const { + virtual bool hasInputProperty(int32_t, int) const { return false; } @@ -553,8 +552,7 @@ private: return NULL; } - virtual status_t mapAxis(int32_t deviceId, int32_t scanCode, - AxisInfo* outAxisInfo) const { + virtual status_t mapAxis(int32_t, int32_t, AxisInfo*) const { return NAME_NOT_FOUND; } @@ -562,7 +560,7 @@ private: mExcludedDevices = devices; } - virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) { + virtual size_t getEvents(int, RawEvent* buffer, size_t) { if (mEvents.empty()) { return 0; } @@ -680,25 +678,25 @@ private: } } - virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const { + virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t) const { return NULL; } - virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map) { + virtual bool setKeyboardLayoutOverlay(int32_t, const sp<KeyCharacterMap>&) { return false; } - virtual void vibrate(int32_t deviceId, nsecs_t duration) { + virtual void vibrate(int32_t, nsecs_t) { } - virtual void cancelVibrate(int32_t deviceId) { + virtual void cancelVibrate(int32_t) { } - virtual bool isExternal(int32_t deviceId) const { + virtual bool isExternal(int32_t) const { return false; } - virtual void dump(String8& dump) { + virtual void dump(String8&) { } virtual void monitor() { @@ -763,23 +761,30 @@ private: return mListener.get(); } - virtual void disableVirtualKeysUntil(nsecs_t time) { + virtual void disableVirtualKeysUntil(nsecs_t) { } - virtual bool shouldDropVirtualKey(nsecs_t now, - InputDevice* device, int32_t keyCode, int32_t scanCode) { + virtual bool shouldDropVirtualKey(nsecs_t, InputDevice*, int32_t, int32_t) { return false; } virtual void fadePointer() { } - virtual void requestTimeoutAtTime(nsecs_t when) { + virtual void requestTimeoutAtTime(nsecs_t) { } virtual int32_t bumpGeneration() { return ++mGeneration; } + + virtual void getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices) { + + } + + virtual void dispatchExternalStylusState(const StylusState&) { + + } }; @@ -867,12 +872,11 @@ private: } } - virtual void configure(nsecs_t when, - const InputReaderConfiguration* config, uint32_t changes) { + virtual void configure(nsecs_t, const InputReaderConfiguration*, uint32_t) { mConfigureWasCalled = true; } - virtual void reset(nsecs_t when) { + virtual void reset(nsecs_t) { mResetWasCalled = true; } @@ -881,22 +885,22 @@ private: mProcessWasCalled = true; } - virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { + virtual int32_t getKeyCodeState(uint32_t, int32_t keyCode) { ssize_t index = mKeyCodeStates.indexOfKey(keyCode); return index >= 0 ? mKeyCodeStates.valueAt(index) : AKEY_STATE_UNKNOWN; } - virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode) { + virtual int32_t getScanCodeState(uint32_t, int32_t scanCode) { ssize_t index = mScanCodeStates.indexOfKey(scanCode); return index >= 0 ? mScanCodeStates.valueAt(index) : AKEY_STATE_UNKNOWN; } - virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode) { + virtual int32_t getSwitchState(uint32_t, int32_t switchCode) { ssize_t index = mSwitchStates.indexOfKey(switchCode); return index >= 0 ? mSwitchStates.valueAt(index) : AKEY_STATE_UNKNOWN; } - virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, + virtual bool markSupportedKeyCodes(uint32_t, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) { bool result = false; for (size_t i = 0; i < numCodes; i++) { @@ -1536,7 +1540,7 @@ protected: }; void KeyboardInputMapperTest::testDPadKeyRotation(KeyboardInputMapper* mapper, - int32_t originalScanCode, int32_t originalKeyCode, int32_t rotatedKeyCode) { + int32_t originalScanCode, int32_t, int32_t rotatedKeyCode) { NotifyKeyArgs args; process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, originalScanCode, 1); diff --git a/services/powermanager/Android.mk b/services/powermanager/Android.mk index d98b2dafd3..7b24c65554 100644 --- a/services/powermanager/Android.mk +++ b/services/powermanager/Android.mk @@ -2,14 +2,16 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ - IPowerManager.cpp + IPowerManager.cpp LOCAL_SHARED_LIBRARIES := \ - libutils \ - libbinder + libutils \ + libbinder LOCAL_MODULE:= libpowermanager LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code + include $(BUILD_SHARED_LIBRARY) diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp index 80845a287c..dd1bccfbec 100644 --- a/services/sensorservice/SensorDevice.cpp +++ b/services/sensorservice/SensorDevice.cpp @@ -79,16 +79,17 @@ void SensorDevice::dump(String8& result) sensor_t const* list; ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list); - result.appendFormat("halVersion %d\n", getHalDeviceVersion()); + result.appendFormat("halVersion 0x%08x\n", getHalDeviceVersion()); result.appendFormat("%d h/w sensors:\n", int(count)); Mutex::Autolock _l(mLock); for (size_t i=0 ; i<size_t(count) ; i++) { const Info& info = mActivationCount.valueFor(list[i].handle); + if (info.batchParams.isEmpty()) continue; result.appendFormat("handle=0x%08x, active-count=%zu, batch_period(ms)={ ", list[i].handle, info.batchParams.size()); for (size_t j = 0; j < info.batchParams.size(); j++) { - BatchParams params = info.batchParams.valueAt(j); + const BatchParams& params = info.batchParams.valueAt(j); result.appendFormat("%4.1f%s", params.batchDelay / 1e6f, j < info.batchParams.size() - 1 ? ", " : ""); } @@ -147,8 +148,12 @@ status_t SensorDevice::activate(void* ident, int handle, int enabled) if (enabled) { ALOGD_IF(DEBUG_CONNECTIONS, "enable index=%zd", info.batchParams.indexOfKey(ident)); + if (isClientDisabledLocked(ident)) { + return INVALID_OPERATION; + } + if (info.batchParams.indexOfKey(ident) >= 0) { - if (info.batchParams.size() == 1) { + if (info.numActiveClients() == 1) { // This is the first connection, we need to activate the underlying h/w sensor. actuateHardware = true; } @@ -160,7 +165,7 @@ status_t SensorDevice::activate(void* ident, int handle, int enabled) ALOGD_IF(DEBUG_CONNECTIONS, "disable index=%zd", info.batchParams.indexOfKey(ident)); if (info.removeBatchParamsForIdent(ident) >= 0) { - if (info.batchParams.size() == 0) { + if (info.numActiveClients() == 0) { // This is the last connection, we need to de-activate the underlying h/w sensor. actuateHardware = true; } else { @@ -181,10 +186,15 @@ status_t SensorDevice::activate(void* ident, int handle, int enabled) } else { // sensor wasn't enabled for this ident } + + if (isClientDisabledLocked(ident)) { + return NO_ERROR; + } } if (actuateHardware) { - ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w activate handle=%d enabled=%d", handle, enabled); + ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w activate handle=%d enabled=%d", handle, + enabled); err = mSensorDevice->activate( reinterpret_cast<struct sensors_poll_device_t *> (mSensorDevice), handle, enabled); ALOGE_IF(err, "Error %s sensor %d (%s)", enabled ? "activating" : "disabling", handle, @@ -197,7 +207,7 @@ status_t SensorDevice::activate(void* ident, int handle, int enabled) } // On older devices which do not support batch, call setDelay(). - if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1 && info.batchParams.size() > 0) { + 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); mSensorDevice->setDelay( @@ -279,6 +289,7 @@ status_t SensorDevice::setDelay(void* ident, int handle, int64_t samplingPeriodN samplingPeriodNs = MINIMUM_EVENTS_PERIOD; } Mutex::Autolock _l(mLock); + if (isClientDisabledLocked(ident)) return INVALID_OPERATION; Info& info( mActivationCount.editValueFor(handle) ); // If the underlying sensor is NOT in continuous mode, setDelay() should return an error. // Calling setDelay() in batch mode is an invalid operation. @@ -298,7 +309,6 @@ status_t SensorDevice::setDelay(void* ident, int handle, int64_t samplingPeriodN int SensorDevice::getHalDeviceVersion() const { if (!mSensorDevice) return -1; - return mSensorDevice->common.version; } @@ -306,12 +316,110 @@ 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 mSensorDevice->flush(mSensorDevice, handle); } +bool SensorDevice::isClientDisabled(void* ident) { + Mutex::Autolock _l(mLock); + return isClientDisabledLocked(ident); +} + +bool SensorDevice::isClientDisabledLocked(void* ident) { + return mDisabledClients.indexOf(ident) >= 0; +} + +void SensorDevice::enableAllSensors() { + Mutex::Autolock _l(mLock); + mDisabledClients.clear(); + const int halVersion = getHalDeviceVersion(); + for (size_t i = 0; i< mActivationCount.size(); ++i) { + Info& info = mActivationCount.editValueAt(i); + if (info.batchParams.isEmpty()) continue; + info.selectBatchParams(); + 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 = mSensorDevice->batch(mSensorDevice, 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)); + } + + if (err == NO_ERROR) { + err = mSensorDevice->activate( + reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice), + sensor_handle, 1); + ALOGE_IF(err, "Error activating sensor %d (%s)", sensor_handle, strerror(-err)); + } + + if (halVersion <= SENSORS_DEVICE_API_VERSION_1_0) { + err = mSensorDevice->setDelay( + reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice), + sensor_handle, info.bestBatchParams.batchDelay); + ALOGE_IF(err, "Error calling setDelay sensor %d (%s)", sensor_handle, strerror(-err)); + } + } +} + +void SensorDevice::disableAllSensors() { + Mutex::Autolock _l(mLock); + 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) { + const int sensor_handle = mActivationCount.keyAt(i); + ALOGD_IF(DEBUG_CONNECTIONS, "\t>> actuating h/w sensor disable handle=%d ", + sensor_handle); + mSensorDevice->activate( + reinterpret_cast<struct sensors_poll_device_t *> (mSensorDevice), + sensor_handle, 0); + // Add all the connections that were registered for this sensor to the disabled + // clients list. + for (size_t j = 0; j < info.batchParams.size(); ++j) { + mDisabledClients.add(info.batchParams.keyAt(j)); + } + } + } +} + +status_t SensorDevice::injectSensorData(const sensors_event_t *injected_sensor_event) { + ALOGD_IF(DEBUG_CONNECTIONS, + "sensor_event handle=%d ts=%lld data=%.2f, %.2f, %.2f %.2f %.2f %.2f", + injected_sensor_event->sensor, + injected_sensor_event->timestamp, injected_sensor_event->data[0], + injected_sensor_event->data[1], injected_sensor_event->data[2], + 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; + } + return mSensorDevice->inject_sensor_data(mSensorDevice, injected_sensor_event); +} + +status_t SensorDevice::setMode(uint32_t mode) { + if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_4) { + return INVALID_OPERATION; + } + return mSensorModule->set_operation_mode(mode); +} + // --------------------------------------------------------------------------- +int SensorDevice::Info::numActiveClients() { + SensorDevice& device(SensorDevice::getInstance()); + int num = 0; + for (size_t i = 0; i < batchParams.size(); ++i) { + if (!device.isClientDisabledLocked(batchParams.keyAt(i))) { + ++num; + } + } + return num; +} + status_t SensorDevice::Info::setBatchParamsForIdent(void* ident, int flags, int64_t samplingPeriodNs, int64_t maxBatchReportLatencyNs) { @@ -329,19 +437,16 @@ status_t SensorDevice::Info::setBatchParamsForIdent(void* ident, int flags, } void SensorDevice::Info::selectBatchParams() { - BatchParams bestParams(-1, -1, -1); - - if (batchParams.size() > 0) { - BatchParams params = batchParams.valueAt(0); - bestParams = params; - } + BatchParams bestParams(0, -1, -1); + SensorDevice& device(SensorDevice::getInstance()); - for (size_t i = 1; i < batchParams.size(); ++i) { + for (size_t i = 0; i < batchParams.size(); ++i) { + if (device.isClientDisabledLocked(batchParams.keyAt(i))) continue; BatchParams params = batchParams.valueAt(i); - if (params.batchDelay < bestParams.batchDelay) { + if (bestParams.batchDelay == -1 || params.batchDelay < bestParams.batchDelay) { bestParams.batchDelay = params.batchDelay; } - if (params.batchTimeout < bestParams.batchTimeout) { + if (bestParams.batchTimeout == -1 || params.batchTimeout < bestParams.batchTimeout) { bestParams.batchTimeout = params.batchTimeout; } } diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h index 761b48cf55..c48484994f 100644 --- a/services/sensorservice/SensorDevice.h +++ b/services/sensorservice/SensorDevice.h @@ -42,6 +42,7 @@ class SensorDevice : public Singleton<SensorDevice> { // Struct to store all the parameters(samplingPeriod, maxBatchReportLatency and flags) from // batch call. For continous mode clients, maxBatchReportLatency is set to zero. struct BatchParams { + // TODO: Get rid of flags parameter everywhere. int flags; nsecs_t batchDelay, batchTimeout; BatchParams() : flags(0), batchDelay(0), batchTimeout(0) {} @@ -65,7 +66,7 @@ class SensorDevice : public Singleton<SensorDevice> { // requested by the client. KeyedVector<void*, BatchParams> batchParams; - Info() : bestBatchParams(-1, -1, -1) {} + Info() : bestBatchParams(0, -1, -1) {} // Sets batch parameters for this ident. Returns error if this ident is not already present // in the KeyedVector above. status_t setBatchParamsForIdent(void* ident, int flags, int64_t samplingPeriodNs, @@ -75,10 +76,17 @@ class SensorDevice : public Singleton<SensorDevice> { // Removes batchParams for an ident and re-computes bestBatchParams. Returns the index of // the removed ident. If index >=0, ident is present and successfully removed. ssize_t removeBatchParamsForIdent(void* ident); + + int numActiveClients(); }; DefaultKeyedVector<int, Info> mActivationCount; + // Use this vector to determine which client is activated or deactivated. + SortedVector<void *> mDisabledClients; SensorDevice(); + + bool isClientDisabled(void* ident); + bool isClientDisabledLocked(void* ident); public: ssize_t getSensorList(sensor_t const** list); status_t initCheck() const; @@ -90,7 +98,11 @@ public: // Call batch with timeout zero instead of calling setDelay() for newer devices. status_t setDelay(void* ident, int handle, int64_t ns); status_t flush(void* ident, int handle); + status_t setMode(uint32_t mode); + void disableAllSensors(); + void enableAllSensors(); void autoDisable(void *ident, int handle); + status_t injectSensorData(const sensors_event_t *event); void dump(String8& result); }; diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index c316ef6eb8..40b21a96a0 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -31,6 +31,7 @@ #include <utils/Singleton.h> #include <utils/String16.h> +#include <binder/AppOpsManager.h> #include <binder/BinderService.h> #include <binder/IServiceManager.h> #include <binder/PermissionCache.h> @@ -63,7 +64,9 @@ namespace android { * */ -const char* SensorService::WAKE_LOCK_NAME = "SensorService"; +const char* SensorService::WAKE_LOCK_NAME = "SensorService_wakelock"; +// Permissions. +static const String16 sDump("android.permission.DUMP"); SensorService::SensorService() : mInitCheck(NO_INIT), mSocketBufferSize(SOCKET_BUFFER_SIZE_NON_BATCHED), @@ -74,7 +77,6 @@ SensorService::SensorService() void SensorService::onFirstRef() { ALOGD("nuSensorService starting..."); - SensorDevice& dev(SensorDevice::getInstance()); if (dev.initCheck() == NO_ERROR) { @@ -82,7 +84,7 @@ void SensorService::onFirstRef() ssize_t count = dev.getSensorList(&list); if (count > 0) { ssize_t orientationIndex = -1; - bool hasGyro = false; + bool hasGyro = false, hasAccel = false, hasMag = false; uint32_t virtualSensorsNeeds = (1<<SENSOR_TYPE_GRAVITY) | (1<<SENSOR_TYPE_LINEAR_ACCELERATION) | @@ -92,6 +94,12 @@ void SensorService::onFirstRef() for (ssize_t i=0 ; i<count ; i++) { registerSensor( new HardwareSensor(list[i]) ); switch (list[i].type) { + case SENSOR_TYPE_ACCELEROMETER: + hasAccel = true; + break; + case SENSOR_TYPE_MAGNETIC_FIELD: + hasMag = true; + break; case SENSOR_TYPE_ORIENTATION: orientationIndex = i; break; @@ -115,7 +123,7 @@ void SensorService::onFirstRef() // build the sensor list returned to users mUserSensorList = mSensorList; - if (hasGyro) { + if (hasGyro && hasAccel && hasMag) { Sensor aSensor; // Add Android virtual sensors if they're not already @@ -154,7 +162,7 @@ void SensorService::onFirstRef() // Check if the device really supports batching by looking at the FIFO event // counts for each sensor. bool batchingSupported = false; - for (int i = 0; i < mSensorList.size(); ++i) { + for (size_t i = 0; i < mSensorList.size(); ++i) { if (mSensorList[i].getFifoMaxEventCount() > 0) { batchingSupported = true; break; @@ -190,10 +198,16 @@ void SensorService::onFirstRef() mSensorEventBuffer = new sensors_event_t[minBufferSize]; mSensorEventScratch = new sensors_event_t[minBufferSize]; mMapFlushEventsToConnections = new SensorEventConnection const * [minBufferSize]; + mCurrentOperatingMode = NORMAL; + + mNextSensorRegIndex = 0; + for (int i = 0; i < SENSOR_REGISTRATIONS_BUF_SIZE; ++i) { + mLastNSensorRegistrations.push(); + } + mInitCheck = NO_ERROR; mAckReceiver = new SensorEventAckReceiver(this); mAckReceiver->run("SensorEventAckReceiver", PRIORITY_URGENT_DISPLAY); - mInitCheck = NO_ERROR; run("SensorService", PRIORITY_URGENT_DISPLAY); } } @@ -210,7 +224,7 @@ Sensor SensorService::registerSensor(SensorInterface* s) // add to our handle->SensorInterface mapping mSensorMap.add(sensor.getHandle(), s); // create an entry in the mLastEventSeen array - mLastEventSeen.add(sensor.getHandle(), event); + mLastEventSeen.add(sensor.getHandle(), NULL); return sensor; } @@ -228,9 +242,7 @@ SensorService::~SensorService() delete mSensorMap.valueAt(i); } -static const String16 sDump("android.permission.DUMP"); - -status_t SensorService::dump(int fd, const Vector<String16>& /*args*/) +status_t SensorService::dump(int fd, const Vector<String16>& args) { String8 result; if (!PermissionCache::checkCallingPermission(sDump)) { @@ -239,116 +251,188 @@ status_t SensorService::dump(int fd, const Vector<String16>& /*args*/) IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid()); } else { + if (args.size() > 2) { + return INVALID_OPERATION; + } Mutex::Autolock _l(mLock); - result.append("Sensor List:\n"); - for (size_t i=0 ; i<mSensorList.size() ; i++) { - const Sensor& s(mSensorList[i]); - const sensors_event_t& e(mLastEventSeen.valueFor(s.getHandle())); - result.appendFormat( - "%-15s| %-10s| version=%d |%-20s| 0x%08x | \"%s\" | type=%d |", - s.getName().string(), - s.getVendor().string(), - s.getVersion(), - s.getStringType().string(), - s.getHandle(), - s.getRequiredPermission().string(), - s.getType()); - - const int reportingMode = s.getReportingMode(); - if (reportingMode == AREPORTING_MODE_CONTINUOUS) { - result.append(" continuous | "); - } else if (reportingMode == AREPORTING_MODE_ON_CHANGE) { - result.append(" on-change | "); - } else if (reportingMode == AREPORTING_MODE_ONE_SHOT) { - result.append(" one-shot | "); - } else { - result.append(" special-trigger | "); + SensorDevice& dev(SensorDevice::getInstance()); + if (args.size() == 2 && args[0] == String16("restrict")) { + // If already in restricted mode. Ignore. + if (mCurrentOperatingMode == RESTRICTED) { + return status_t(NO_ERROR); } - - if (s.getMaxDelay() > 0) { - result.appendFormat("minRate=%.2fHz | ", 1e6f / s.getMaxDelay()); - } else { - result.appendFormat("maxDelay=%dus |", s.getMaxDelay()); + // If in any mode other than normal, ignore. + if (mCurrentOperatingMode != NORMAL) { + return INVALID_OPERATION; } - - if (s.getMinDelay() > 0) { - result.appendFormat("maxRate=%.2fHz | ", 1e6f / s.getMinDelay()); - } else { - result.appendFormat("minDelay=%dus |", s.getMinDelay()); + mCurrentOperatingMode = RESTRICTED; + 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 + // flush complete event is returned, we need to remove the connection from this queue. + for (size_t i=0 ; i< mActiveSensors.size(); ++i) { + mActiveSensors.valueAt(i)->clearAllPendingFlushConnections(); } - - if (s.getFifoMaxEventCount() > 0) { - result.appendFormat("FifoMax=%d events | ", - s.getFifoMaxEventCount()); - } else { - result.append("no batching | "); + mWhiteListedPackage.setTo(String8(args[1])); + return status_t(NO_ERROR); + } else if (args.size() == 1 && args[0] == String16("enable")) { + // If currently in restricted mode, reset back to NORMAL mode else ignore. + if (mCurrentOperatingMode == RESTRICTED) { + mCurrentOperatingMode = NORMAL; + dev.enableAllSensors(); } - - if (s.isWakeUpSensor()) { - result.appendFormat("wakeUp | "); + if (mCurrentOperatingMode == DATA_INJECTION) { + resetToNormalModeLocked(); + } + mWhiteListedPackage.clear(); + return status_t(NO_ERROR); + } else if (args.size() == 2 && args[0] == String16("data_injection")) { + if (mCurrentOperatingMode == NORMAL) { + dev.disableAllSensors(); + status_t err = dev.setMode(DATA_INJECTION); + if (err == NO_ERROR) { + mCurrentOperatingMode = DATA_INJECTION; + } else { + // Re-enable sensors. + dev.enableAllSensors(); + } + mWhiteListedPackage.setTo(String8(args[1])); + return NO_ERROR; + } else if (mCurrentOperatingMode == DATA_INJECTION) { + // Already in DATA_INJECTION mode. Treat this as a no_op. + return NO_ERROR; } else { - result.appendFormat("non-wakeUp | "); + // Transition to data injection mode supported only from NORMAL mode. + return INVALID_OPERATION; } + } else if (mSensorList.size() == 0) { + result.append("No Sensors on the device\n"); + } else { + // Default dump the sensor list and debugging information. + result.append("Sensor List:\n"); + for (size_t i=0 ; i<mSensorList.size() ; i++) { + const Sensor& s(mSensorList[i]); + result.appendFormat( + "%-15s| %-10s| version=%d |%-20s| 0x%08x | \"%s\" | type=%d |", + s.getName().string(), + s.getVendor().string(), + s.getVersion(), + s.getStringType().string(), + s.getHandle(), + s.getRequiredPermission().string(), + s.getType()); + + const int reportingMode = s.getReportingMode(); + if (reportingMode == AREPORTING_MODE_CONTINUOUS) { + result.append(" continuous | "); + } else if (reportingMode == AREPORTING_MODE_ON_CHANGE) { + result.append(" on-change | "); + } else if (reportingMode == AREPORTING_MODE_ONE_SHOT) { + result.append(" one-shot | "); + } else { + result.append(" special-trigger | "); + } - switch (s.getType()) { - case SENSOR_TYPE_ROTATION_VECTOR: - case SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR: - result.appendFormat( - "last=<%5.1f,%5.1f,%5.1f,%5.1f,%5.1f, %" PRId64 ">\n", - e.data[0], e.data[1], e.data[2], e.data[3], e.data[4], e.timestamp); - break; - case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED: - case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED: - result.appendFormat( - "last=<%5.1f,%5.1f,%5.1f,%5.1f,%5.1f,%5.1f, %" PRId64 ">\n", - e.data[0], e.data[1], e.data[2], e.data[3], e.data[4], e.data[5], - e.timestamp); - break; - case SENSOR_TYPE_GAME_ROTATION_VECTOR: - result.appendFormat( - "last=<%5.1f,%5.1f,%5.1f,%5.1f, %" PRId64 ">\n", - e.data[0], e.data[1], e.data[2], e.data[3], e.timestamp); - break; - case SENSOR_TYPE_SIGNIFICANT_MOTION: - case SENSOR_TYPE_STEP_DETECTOR: - result.appendFormat( "last=<%f %" PRId64 ">\n", e.data[0], e.timestamp); - break; - case SENSOR_TYPE_STEP_COUNTER: - result.appendFormat( "last=<%" PRIu64 ", %" PRId64 ">\n", e.u64.step_counter, - e.timestamp); - break; - default: - // default to 3 values - result.appendFormat( - "last=<%5.1f,%5.1f,%5.1f, %" PRId64 ">\n", - e.data[0], e.data[1], e.data[2], e.timestamp); - break; + if (s.getMaxDelay() > 0) { + result.appendFormat("minRate=%.2fHz | ", 1e6f / s.getMaxDelay()); + } else { + result.appendFormat("maxDelay=%dus |", s.getMaxDelay()); + } + + if (s.getMinDelay() > 0) { + result.appendFormat("maxRate=%.2fHz | ", 1e6f / s.getMinDelay()); + } else { + result.appendFormat("minDelay=%dus |", s.getMinDelay()); + } + + if (s.getFifoMaxEventCount() > 0) { + result.appendFormat("FifoMax=%d events | ", + s.getFifoMaxEventCount()); + } else { + result.append("no batching | "); + } + + if (s.isWakeUpSensor()) { + result.appendFormat("wakeUp | "); + } else { + result.appendFormat("non-wakeUp | "); + } + + int bufIndex = mLastEventSeen.indexOfKey(s.getHandle()); + if (bufIndex >= 0) { + const CircularBuffer* buf = mLastEventSeen.valueAt(bufIndex); + if (buf != NULL && s.getRequiredPermission().isEmpty()) { + buf->printBuffer(result); + } else { + result.append("last=<> \n"); + } + } + result.append("\n"); + } + SensorFusion::getInstance().dump(result); + SensorDevice::getInstance().dump(result); + + result.append("Active sensors:\n"); + for (size_t i=0 ; i<mActiveSensors.size() ; i++) { + int handle = mActiveSensors.keyAt(i); + result.appendFormat("%s (handle=0x%08x, connections=%zu)\n", + getSensorName(handle).string(), + handle, + mActiveSensors.valueAt(i)->getNumConnections()); } - result.append("\n"); - } - SensorFusion::getInstance().dump(result); - SensorDevice::getInstance().dump(result); - - result.append("Active sensors:\n"); - for (size_t i=0 ; i<mActiveSensors.size() ; i++) { - int handle = mActiveSensors.keyAt(i); - result.appendFormat("%s (handle=0x%08x, connections=%zu)\n", - getSensorName(handle).string(), - handle, - mActiveSensors.valueAt(i)->getNumConnections()); - } - result.appendFormat("Socket Buffer size = %d events\n", - mSocketBufferSize/sizeof(sensors_event_t)); - result.appendFormat("WakeLock Status: %s \n", mWakeLockAcquired ? "acquired" : "not held"); - result.appendFormat("%zd active connections\n", mActiveConnections.size()); + result.appendFormat("Socket Buffer size = %d events\n", + mSocketBufferSize/sizeof(sensors_event_t)); + result.appendFormat("WakeLock Status: %s \n", mWakeLockAcquired ? "acquired" : + "not held"); + result.appendFormat("Mode :"); + switch(mCurrentOperatingMode) { + case NORMAL: + result.appendFormat(" NORMAL\n"); + break; + case RESTRICTED: + result.appendFormat(" RESTRICTED : %s\n", mWhiteListedPackage.string()); + break; + case DATA_INJECTION: + result.appendFormat(" DATA_INJECTION : %s\n", mWhiteListedPackage.string()); + } + 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) { - result.appendFormat("Connection Number: %zu \n", i); - connection->dump(result); + for (size_t i=0 ; i < mActiveConnections.size() ; i++) { + sp<SensorEventConnection> connection(mActiveConnections[i].promote()); + if (connection != 0) { + result.appendFormat("Connection Number: %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) % + SENSOR_REGISTRATIONS_BUF_SIZE; + const int startIndex = currentIndex; + do { + const SensorRegistrationInfo& reg_info = mLastNSensorRegistrations[currentIndex]; + if (SensorRegistrationInfo::isSentinel(reg_info)) { + // Ignore sentinel, proceed to next item. + currentIndex = (currentIndex - 1 + SENSOR_REGISTRATIONS_BUF_SIZE) % + SENSOR_REGISTRATIONS_BUF_SIZE; + continue; + } + if (reg_info.mActivated) { + result.appendFormat("%02d:%02d:%02d activated package=%s handle=0x%08x " + "samplingRate=%dus maxReportLatency=%dus\n", + reg_info.mHour, reg_info.mMin, reg_info.mSec, + reg_info.mPackageName.string(), reg_info.mSensorHandle, + reg_info.mSamplingRateUs, reg_info.mMaxReportLatencyUs); + } else { + result.appendFormat("%02d:%02d:%02d de-activated package=%s handle=0x%08x\n", + reg_info.mHour, reg_info.mMin, reg_info.mSec, + reg_info.mPackageName.string(), reg_info.mSensorHandle); + } + currentIndex = (currentIndex - 1 + SENSOR_REGISTRATIONS_BUF_SIZE) % + SENSOR_REGISTRATIONS_BUF_SIZE; + } while(startIndex != currentIndex); } } write(fd, result.string(), result.size()); @@ -371,8 +455,9 @@ void SensorService::cleanupAutoDisabledSensorLocked(const sp<SensorEventConnecti sensor->autoDisable(connection.get(), handle); cleanupWithoutDisableLocked(connection, handle); } + } - } + } } bool SensorService::threadLoop() @@ -554,7 +639,6 @@ void SensorService::setWakeLockAcquiredLocked(bool acquire) { } } - bool SensorService::isWakeLockAcquired() { Mutex::Autolock _l(mLock); return mWakeLockAcquired; @@ -577,19 +661,15 @@ bool SensorService::SensorEventAckReceiver::threadLoop() { void SensorService::recordLastValueLocked( const sensors_event_t* buffer, size_t count) { - const sensors_event_t* last = NULL; for (size_t i = 0; i < count; i++) { - const sensors_event_t* event = &buffer[i]; - if (event->type != SENSOR_TYPE_META_DATA) { - if (last && event->sensor != last->sensor) { - mLastEventSeen.editValueFor(last->sensor) = *last; + if (buffer[i].type != SENSOR_TYPE_META_DATA) { + CircularBuffer* &circular_buf = mLastEventSeen.editValueFor(buffer[i].sensor); + if (circular_buf == NULL) { + circular_buf = new CircularBuffer(buffer[i].type); } - last = event; + circular_buf->addEvent(buffer[i]); } } - if (last) { - mLastEventSeen.editValueFor(last->sensor) = *last; - } } void SensorService::sortEventBuffer(sensors_event_t* buffer, size_t count) @@ -630,12 +710,11 @@ bool SensorService::isWakeUpSensorEvent(const sensors_event_t& event) const { return sensor != NULL && sensor->getSensor().isWakeUpSensor(); } - SensorService::SensorRecord * SensorService::getSensorRecord(int handle) { return mActiveSensors.valueFor(handle); } -Vector<Sensor> SensorService::getSensorList() +Vector<Sensor> SensorService::getSensorList(const String16& opPackageName) { char value[PROPERTY_VALUE_MAX]; property_get("debug.sensors", value, "0"); @@ -644,27 +723,65 @@ Vector<Sensor> SensorService::getSensorList() Vector<Sensor> accessibleSensorList; for (size_t i = 0; i < initialSensorList.size(); i++) { Sensor sensor = initialSensorList[i]; - if (canAccessSensor(sensor)) { + if (canAccessSensor(sensor, "getSensorList", opPackageName)) { accessibleSensorList.add(sensor); } else { - String8 infoMessage; - infoMessage.appendFormat( - "Skipped sensor %s because it requires permission %s", - sensor.getName().string(), - sensor.getRequiredPermission().string()); - ALOGI(infoMessage.string()); + ALOGI("Skipped sensor %s because it requires permission %s and app op %d", + sensor.getName().string(), + sensor.getRequiredPermission().string(), + sensor.getRequiredAppOp()); } } return accessibleSensorList; } -sp<ISensorEventConnection> SensorService::createSensorEventConnection() -{ +sp<ISensorEventConnection> SensorService::createSensorEventConnection(const String8& packageName, + int requestedMode, const String16& opPackageName) { + // Only 2 modes supported for a SensorEventConnection ... NORMAL and DATA_INJECTION. + if (requestedMode != NORMAL && requestedMode != DATA_INJECTION) { + return NULL; + } + + Mutex::Autolock _l(mLock); + // To create a client in DATA_INJECTION mode to inject data, SensorService should already be + // operating in DI mode. + if (requestedMode == DATA_INJECTION) { + if (mCurrentOperatingMode != DATA_INJECTION) return NULL; + if (!isWhiteListedPackage(packageName)) return NULL; + } + uid_t uid = IPCThreadState::self()->getCallingUid(); - sp<SensorEventConnection> result(new SensorEventConnection(this, uid)); + sp<SensorEventConnection> result(new SensorEventConnection(this, uid, packageName, + requestedMode == DATA_INJECTION, opPackageName)); + if (requestedMode == DATA_INJECTION) { + if (mActiveConnections.indexOf(result) < 0) { + mActiveConnections.add(result); + } + // Add the associated file descriptor to the Looper for polling whenever there is data to + // be injected. + result->updateLooperRegistration(mLooper); + } return result; } +int SensorService::isDataInjectionEnabled() { + Mutex::Autolock _l(mLock); + return (mCurrentOperatingMode == DATA_INJECTION); +} + +status_t SensorService::resetToNormalMode() { + Mutex::Autolock _l(mLock); + return resetToNormalModeLocked(); +} + +status_t SensorService::resetToNormalModeLocked() { + SensorDevice& dev(SensorDevice::getInstance()); + dev.enableAllSensors(); + status_t err = dev.setMode(NORMAL); + mCurrentOperatingMode = NORMAL; + return err; +} + void SensorService::cleanupConnection(SensorEventConnection* c) { Mutex::Autolock _l(mLock); @@ -711,7 +828,8 @@ Sensor SensorService::getSensorFromHandle(int handle) const { } status_t SensorService::enable(const sp<SensorEventConnection>& connection, - int handle, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags) + int handle, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags, + const String16& opPackageName) { if (mInitCheck != NO_ERROR) return mInitCheck; @@ -721,11 +839,16 @@ status_t SensorService::enable(const sp<SensorEventConnection>& connection, return BAD_VALUE; } - if (!verifyCanAccessSensor(sensor->getSensor(), "Tried enabling")) { + if (!canAccessSensor(sensor->getSensor(), "Tried enabling", opPackageName)) { return BAD_VALUE; } Mutex::Autolock _l(mLock); + if ((mCurrentOperatingMode == RESTRICTED || mCurrentOperatingMode == DATA_INJECTION) + && !isWhiteListedPackage(connection->getPackageName())) { + return INVALID_OPERATION; + } + SensorRecord* rec = mActiveSensors.valueFor(handle); if (rec == 0) { rec = new SensorRecord(connection); @@ -741,14 +864,24 @@ status_t SensorService::enable(const sp<SensorEventConnection>& connection, if (sensor->getSensor().getReportingMode() == AREPORTING_MODE_ON_CHANGE) { // NOTE: The wake_up flag of this event may get set to // WAKE_UP_SENSOR_EVENT_NEEDS_ACK if this is a wake_up event. - sensors_event_t& event(mLastEventSeen.editValueFor(handle)); - if (event.version == sizeof(sensors_event_t)) { - if (isWakeUpSensorEvent(event) && !mWakeLockAcquired) { - setWakeLockAcquiredLocked(true); - } - connection->sendEvents(&event, 1, NULL); - if (!connection->needsWakeLock() && mWakeLockAcquired) { - checkWakeLockStateLocked(); + CircularBuffer *circular_buf = mLastEventSeen.valueFor(handle); + if (circular_buf) { + sensors_event_t event; + memset(&event, 0, sizeof(event)); + // It is unlikely that this buffer is empty as the sensor is already active. + // One possible corner case may be two applications activating an on-change + // sensor at the same time. + if(circular_buf->populateLastEvent(&event)) { + event.sensor = handle; + if (event.version == sizeof(sensors_event_t)) { + if (isWakeUpSensorEvent(event) && !mWakeLockAcquired) { + setWakeLockAcquiredLocked(true); + } + connection->sendEvents(&event, 1, NULL); + if (!connection->needsWakeLock() && mWakeLockAcquired) { + checkWakeLockStateLocked(); + } + } } } } @@ -776,7 +909,7 @@ status_t SensorService::enable(const sp<SensorEventConnection>& connection, "rate=%" PRId64 " timeout== %" PRId64"", handle, reservedFlags, samplingPeriodNs, maxBatchReportLatencyNs); - status_t err = sensor->batch(connection.get(), handle, reservedFlags, samplingPeriodNs, + status_t err = sensor->batch(connection.get(), handle, 0, samplingPeriodNs, maxBatchReportLatencyNs); // Call flush() before calling activate() on the sensor. Wait for a first flush complete @@ -801,6 +934,19 @@ status_t SensorService::enable(const sp<SensorEventConnection>& connection, if (err == NO_ERROR) { connection->updateLooperRegistration(mLooper); + SensorRegistrationInfo ®_info = + mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex); + reg_info.mSensorHandle = handle; + reg_info.mSamplingRateUs = samplingPeriodNs/1000; + reg_info.mMaxReportLatencyUs = maxBatchReportLatencyNs/1000; + reg_info.mActivated = true; + reg_info.mPackageName = connection->getPackageName(); + time_t rawtime = time(NULL); + struct tm * timeinfo = localtime(&rawtime); + reg_info.mHour = timeinfo->tm_hour; + reg_info.mMin = timeinfo->tm_min; + reg_info.mSec = timeinfo->tm_sec; + mNextSensorRegIndex = (mNextSensorRegIndex + 1) % SENSOR_REGISTRATIONS_BUF_SIZE; } if (err != NO_ERROR) { @@ -821,6 +967,20 @@ status_t SensorService::disable(const sp<SensorEventConnection>& connection, if (err == NO_ERROR) { SensorInterface* sensor = mSensorMap.valueFor(handle); err = sensor ? sensor->activate(connection.get(), false) : status_t(BAD_VALUE); + + } + if (err == NO_ERROR) { + SensorRegistrationInfo ®_info = + mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex); + reg_info.mActivated = false; + reg_info.mPackageName= connection->getPackageName(); + reg_info.mSensorHandle = handle; + time_t rawtime = time(NULL); + struct tm * timeinfo = localtime(&rawtime); + reg_info.mHour = timeinfo->tm_hour; + reg_info.mMin = timeinfo->tm_min; + reg_info.mSec = timeinfo->tm_sec; + mNextSensorRegIndex = (mNextSensorRegIndex + 1) % SENSOR_REGISTRATIONS_BUF_SIZE; } return err; } @@ -855,7 +1015,7 @@ status_t SensorService::cleanupWithoutDisableLocked( } status_t SensorService::setEventRate(const sp<SensorEventConnection>& connection, - int handle, nsecs_t ns) + int handle, nsecs_t ns, const String16& opPackageName) { if (mInitCheck != NO_ERROR) return mInitCheck; @@ -864,7 +1024,7 @@ status_t SensorService::setEventRate(const sp<SensorEventConnection>& connection if (!sensor) return BAD_VALUE; - if (!verifyCanAccessSensor(sensor->getSensor(), "Tried configuring")) { + if (!canAccessSensor(sensor->getSensor(), "Tried configuring", opPackageName)) { return BAD_VALUE; } @@ -879,7 +1039,8 @@ status_t SensorService::setEventRate(const sp<SensorEventConnection>& connection return sensor->setDelay(connection.get(), handle, ns); } -status_t SensorService::flushSensor(const sp<SensorEventConnection>& connection) { +status_t SensorService::flushSensor(const sp<SensorEventConnection>& connection, + const String16& opPackageName) { if (mInitCheck != NO_ERROR) return mInitCheck; SensorDevice& dev(SensorDevice::getInstance()); const int halVersion = dev.getHalDeviceVersion(); @@ -899,6 +1060,10 @@ status_t SensorService::flushSensor(const sp<SensorEventConnection>& connection) // flush complete event. connection->incrementPendingFlushCount(handle); } else { + if (!canAccessSensor(sensor->getSensor(), "Tried flushing", opPackageName)) { + err = INVALID_OPERATION; + continue; + } status_t err_flush = sensor->flush(connection.get(), handle); if (err_flush == NO_ERROR) { SensorRecord* rec = mActiveSensors.valueFor(handle); @@ -910,23 +1075,42 @@ status_t SensorService::flushSensor(const sp<SensorEventConnection>& connection) return err; } -bool SensorService::canAccessSensor(const Sensor& sensor) { - return (sensor.getRequiredPermission().isEmpty()) || - PermissionCache::checkCallingPermission(String16(sensor.getRequiredPermission())); -} +bool SensorService::canAccessSensor(const Sensor& sensor, const char* operation, + const String16& opPackageName) { + const String8& requiredPermission = sensor.getRequiredPermission(); -bool SensorService::verifyCanAccessSensor(const Sensor& sensor, const char* operation) { - if (canAccessSensor(sensor)) { + if (requiredPermission.length() <= 0) { return true; + } + + bool hasPermission = false; + + // Runtime permissions can't use the cache as they may change. + if (sensor.isRequiredPermissionRuntime()) { + hasPermission = checkPermission(String16(requiredPermission), + IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid()); } else { - String8 errorMessage; - errorMessage.appendFormat( - "%s a sensor (%s) without holding its required permission: %s", - operation, - sensor.getName().string(), - sensor.getRequiredPermission().string()); + hasPermission = PermissionCache::checkCallingPermission(String16(requiredPermission)); + } + + if (!hasPermission) { + ALOGE("%s a sensor (%s) without holding its required permission: %s", + operation, sensor.getName().string(), sensor.getRequiredPermission().string()); return false; } + + const int32_t opCode = sensor.getRequiredAppOp(); + if (opCode >= 0) { + AppOpsManager appOps; + if (appOps.noteOp(opCode, IPCThreadState::self()->getCallingUid(), opPackageName) + != AppOpsManager::MODE_ALLOWED) { + ALOGE("%s a sensor (%s) without enabled required app op: %D", + operation, sensor.getName().string(), opCode); + return false; + } + } + + return true; } void SensorService::checkWakeLockState() { @@ -972,6 +1156,33 @@ void SensorService::populateActiveConnections( } } +bool SensorService::isWhiteListedPackage(const String8& packageName) { + return (packageName.contains(mWhiteListedPackage.string())); +} + +int SensorService::getNumEventsForSensorType(int sensor_event_type) { + switch (sensor_event_type) { + case SENSOR_TYPE_ROTATION_VECTOR: + case SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR: + return 5; + + case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED: + case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED: + return 6; + + case SENSOR_TYPE_GAME_ROTATION_VECTOR: + return 4; + + case SENSOR_TYPE_SIGNIFICANT_MOTION: + case SENSOR_TYPE_STEP_DETECTOR: + case SENSOR_TYPE_STEP_COUNTER: + return 1; + + default: + return 3; + } +} + // --------------------------------------------------------------------------- SensorService::SensorRecord::SensorRecord( const sp<SensorEventConnection>& connection) @@ -1028,12 +1239,121 @@ SensorService::SensorRecord::getFirstPendingFlushConnection() { return NULL; } +void SensorService::SensorRecord::clearAllPendingFlushConnections() { + mPendingFlushConnections.clear(); +} + + +// --------------------------------------------------------------------------- +SensorService::TrimmedSensorEvent::TrimmedSensorEvent(int sensorType) { + mTimestamp = -1; + const int numData = SensorService::getNumEventsForSensorType(sensorType); + if (sensorType == SENSOR_TYPE_STEP_COUNTER) { + mStepCounter = 0; + } else { + mData = new float[numData]; + for (int i = 0; i < numData; ++i) { + mData[i] = -1.0; + } + } + mHour = mMin = mSec = INT32_MIN; +} + +bool SensorService::TrimmedSensorEvent::isSentinel(const TrimmedSensorEvent& event) { + return (event.mHour == INT32_MIN && event.mMin == INT32_MIN && event.mSec == INT32_MIN); +} +// -------------------------------------------------------------------------- +SensorService::CircularBuffer::CircularBuffer(int sensor_event_type) { + mNextInd = 0; + mBufSize = CIRCULAR_BUF_SIZE; + if (sensor_event_type == SENSOR_TYPE_STEP_COUNTER || + sensor_event_type == SENSOR_TYPE_SIGNIFICANT_MOTION || + sensor_event_type == SENSOR_TYPE_ACCELEROMETER) { + mBufSize = CIRCULAR_BUF_SIZE * 5; + } + mTrimmedSensorEventArr = new TrimmedSensorEvent *[mBufSize]; + mSensorType = sensor_event_type; + for (int i = 0; i < mBufSize; ++i) { + mTrimmedSensorEventArr[i] = new TrimmedSensorEvent(mSensorType); + } +} + +void SensorService::CircularBuffer::addEvent(const sensors_event_t& sensor_event) { + TrimmedSensorEvent *curr_event = mTrimmedSensorEventArr[mNextInd]; + curr_event->mTimestamp = sensor_event.timestamp; + if (mSensorType == SENSOR_TYPE_STEP_COUNTER) { + curr_event->mStepCounter = sensor_event.u64.step_counter; + } else { + memcpy(curr_event->mData, sensor_event.data, + sizeof(float) * SensorService::getNumEventsForSensorType(mSensorType)); + } + time_t rawtime = time(NULL); + struct tm * timeinfo = localtime(&rawtime); + curr_event->mHour = timeinfo->tm_hour; + curr_event->mMin = timeinfo->tm_min; + curr_event->mSec = timeinfo->tm_sec; + mNextInd = (mNextInd + 1) % mBufSize; +} + +void SensorService::CircularBuffer::printBuffer(String8& result) const { + const int numData = SensorService::getNumEventsForSensorType(mSensorType); + int i = mNextInd, eventNum = 1; + result.appendFormat("last %d events = < ", mBufSize); + do { + if (TrimmedSensorEvent::isSentinel(*mTrimmedSensorEventArr[i])) { + // Sentinel, ignore. + i = (i + 1) % mBufSize; + continue; + } + result.appendFormat("%d) ", eventNum++); + if (mSensorType == SENSOR_TYPE_STEP_COUNTER) { + result.appendFormat("%llu,", mTrimmedSensorEventArr[i]->mStepCounter); + } else { + for (int j = 0; j < numData; ++j) { + result.appendFormat("%5.1f,", mTrimmedSensorEventArr[i]->mData[j]); + } + } + result.appendFormat("%lld %02d:%02d:%02d ", mTrimmedSensorEventArr[i]->mTimestamp, + mTrimmedSensorEventArr[i]->mHour, mTrimmedSensorEventArr[i]->mMin, + mTrimmedSensorEventArr[i]->mSec); + i = (i + 1) % mBufSize; + } while (i != mNextInd); + result.appendFormat(">\n"); +} + +bool SensorService::CircularBuffer::populateLastEvent(sensors_event_t *event) { + int lastEventInd = (mNextInd - 1 + mBufSize) % mBufSize; + // Check if the buffer is empty. + if (TrimmedSensorEvent::isSentinel(*mTrimmedSensorEventArr[lastEventInd])) { + return false; + } + event->version = sizeof(sensors_event_t); + event->type = mSensorType; + event->timestamp = mTrimmedSensorEventArr[lastEventInd]->mTimestamp; + if (mSensorType == SENSOR_TYPE_STEP_COUNTER) { + event->u64.step_counter = mTrimmedSensorEventArr[lastEventInd]->mStepCounter; + } else { + memcpy(event->data, mTrimmedSensorEventArr[lastEventInd]->mData, + sizeof(float) * SensorService::getNumEventsForSensorType(mSensorType)); + } + return true; +} + +SensorService::CircularBuffer::~CircularBuffer() { + for (int i = 0; i < mBufSize; ++i) { + delete mTrimmedSensorEventArr[i]; + } + delete [] mTrimmedSensorEventArr; +} + // --------------------------------------------------------------------------- SensorService::SensorEventConnection::SensorEventConnection( - const sp<SensorService>& service, uid_t uid) + const sp<SensorService>& service, uid_t uid, String8 packageName, bool isDataInjectionMode, + const String16& opPackageName) : mService(service), mUid(uid), mWakeLockRefCount(0), mHasLooperCallbacks(false), - mDead(false), mEventCache(NULL), mCacheSize(0), mMaxCacheSize(0) { + mDead(false), mDataInjectionMode(isDataInjectionMode), mEventCache(NULL), + mCacheSize(0), mMaxCacheSize(0), mPackageName(packageName), mOpPackageName(opPackageName) { mChannel = new BitTube(mService->mSocketBufferSize); #if DEBUG_CONNECTIONS mEventsReceived = mEventsSentFromCache = mEventsSent = 0; @@ -1065,8 +1385,10 @@ void SensorService::SensorEventConnection::resetWakeLockRefCount() { void SensorService::SensorEventConnection::dump(String8& result) { Mutex::Autolock _l(mConnectionLock); - result.appendFormat("\t WakeLockRefCount %d | uid %d | cache size %d | max cache size %d\n", - mWakeLockRefCount, mUid, mCacheSize, mMaxCacheSize); + result.appendFormat("\tOperating Mode: %s\n",mDataInjectionMode ? "DATA_INJECTION" : "NORMAL"); + result.appendFormat("\t %s | WakeLockRefCount %d | uid %d | cache size %d | " + "max cache size %d\n", mPackageName.string(), mWakeLockRefCount, mUid, mCacheSize, + mMaxCacheSize); for (size_t i = 0; i < mSensorInfo.size(); ++i) { const FlushInfo& flushInfo = mSensorInfo.valueAt(i); result.appendFormat("\t %s 0x%08x | status: %s | pending flush events %d \n", @@ -1090,7 +1412,8 @@ void SensorService::SensorEventConnection::dump(String8& result) { bool SensorService::SensorEventConnection::addSensor(int32_t handle) { Mutex::Autolock _l(mConnectionLock); - if (!verifyCanAccessSensor(mService->getSensorFromHandle(handle), "Tried adding")) { + if (!canAccessSensor(mService->getSensorFromHandle(handle), + "Tried adding", mOpPackageName)) { return false; } if (mSensorInfo.indexOfKey(handle) < 0) { @@ -1129,6 +1452,10 @@ bool SensorService::SensorEventConnection::hasOneShotSensors() const { return false; } +String8 SensorService::SensorEventConnection::getPackageName() const { + return mPackageName; +} + void SensorService::SensorEventConnection::setFirstFlushPending(int32_t handle, bool value) { Mutex::Autolock _l(mConnectionLock); @@ -1146,7 +1473,8 @@ void SensorService::SensorEventConnection::updateLooperRegistration(const sp<Loo void SensorService::SensorEventConnection::updateLooperRegistrationLocked( const sp<Looper>& looper) { - bool isConnectionActive = mSensorInfo.size() > 0; + bool isConnectionActive = (mSensorInfo.size() > 0 && !mDataInjectionMode) || + mDataInjectionMode; // If all sensors are unregistered OR Looper has encountered an error, we // can remove the Fd from the Looper if it has been previously added. if (!isConnectionActive || mDead) { @@ -1160,6 +1488,7 @@ void SensorService::SensorEventConnection::updateLooperRegistrationLocked( int looper_flags = 0; if (mCacheSize > 0) looper_flags |= ALOOPER_EVENT_OUTPUT; + if (mDataInjectionMode) looper_flags |= ALOOPER_EVENT_INPUT; for (size_t i = 0; i < mSensorInfo.size(); ++i) { const int handle = mSensorInfo.keyAt(i); if (mService->getSensorFromHandle(handle).isWakeUpSensor()) { @@ -1203,7 +1532,7 @@ status_t SensorService::SensorEventConnection::sendEvents( sensors_event_t* scratch, SensorEventConnection const * const * mapFlushEventsToConnections) { // filter out events not for this connection - size_t count = 0; + int count = 0; Mutex::Autolock _l(mConnectionLock); if (scratch) { size_t i=0; @@ -1495,7 +1824,7 @@ status_t SensorService::SensorEventConnection::enableDisable( status_t err; if (enabled) { err = mService->enable(this, handle, samplingPeriodNs, maxBatchReportLatencyNs, - reservedFlags); + reservedFlags, mOpPackageName); } else { err = mService->disable(this, handle); @@ -1506,11 +1835,11 @@ status_t SensorService::SensorEventConnection::enableDisable( status_t SensorService::SensorEventConnection::setEventRate( int handle, nsecs_t samplingPeriodNs) { - return mService->setEventRate(this, handle, samplingPeriodNs); + return mService->setEventRate(this, handle, samplingPeriodNs, mOpPackageName); } status_t SensorService::SensorEventConnection::flush() { - return mService->flushSensor(this); + return mService->flushSensor(this, mOpPackageName); } int SensorService::SensorEventConnection::handleEvent(int fd, int events, void* /*data*/) { @@ -1526,26 +1855,55 @@ int SensorService::SensorEventConnection::handleEvent(int fd, int events, void* updateLooperRegistrationLocked(mService->getLooper()); } mService->checkWakeLockState(); + if (mDataInjectionMode) { + // If the Looper has encountered some error in data injection mode, reset SensorService + // back to normal mode. + mService->resetToNormalMode(); + mDataInjectionMode = false; + } return 1; } if (events & ALOOPER_EVENT_INPUT) { - uint32_t numAcks = 0; - ssize_t ret = ::recv(fd, &numAcks, sizeof(numAcks), MSG_DONTWAIT); + unsigned char buf[sizeof(sensors_event_t)]; + ssize_t numBytesRead = ::recv(fd, buf, sizeof(buf), MSG_DONTWAIT); { Mutex::Autolock _l(mConnectionLock); - // Sanity check to ensure there are no read errors in recv, numAcks is always - // within the range and not zero. If any of the above don't hold reset mWakeLockRefCount - // to zero. - if (ret != sizeof(numAcks) || numAcks > mWakeLockRefCount || numAcks == 0) { - ALOGE("Looper read error ret=%d numAcks=%d", ret, numAcks); - mWakeLockRefCount = 0; - } else { - mWakeLockRefCount -= numAcks; - } + if (numBytesRead == sizeof(sensors_event_t)) { + if (!mDataInjectionMode) { + ALOGE("Data injected in normal mode, dropping event" + "package=%s uid=%d", mPackageName.string(), mUid); + // Unregister call backs. + return 0; + } + SensorDevice& dev(SensorDevice::getInstance()); + sensors_event_t sensor_event; + memset(&sensor_event, 0, sizeof(sensor_event)); + memcpy(&sensor_event, buf, sizeof(sensors_event_t)); + Sensor sensor = mService->getSensorFromHandle(sensor_event.sensor); + sensor_event.type = sensor.getType(); + dev.injectSensorData(&sensor_event); #if DEBUG_CONNECTIONS - mTotalAcksReceived += numAcks; + ++mEventsReceived; #endif + } else if (numBytesRead == sizeof(uint32_t)) { + uint32_t numAcks = 0; + memcpy(&numAcks, buf, numBytesRead); + // Sanity check to ensure there are no read errors in recv, numAcks is always + // within the range and not zero. If any of the above don't hold reset + // mWakeLockRefCount to zero. + if (numAcks > 0 && numAcks < mWakeLockRefCount) { + mWakeLockRefCount -= numAcks; + } else { + mWakeLockRefCount = 0; + } +#if DEBUG_CONNECTIONS + mTotalAcksReceived += numAcks; +#endif + } else { + // Read error, reset wakelock refcount. + mWakeLockRefCount = 0; + } } // Check if wakelock can be released by sensorservice. mConnectionLock needs to be released // here as checkWakeLockState() will need it. @@ -1564,8 +1922,8 @@ int SensorService::SensorEventConnection::handleEvent(int fd, int events, void* } int SensorService::SensorEventConnection::computeMaxCacheSizeLocked() const { - int fifoWakeUpSensors = 0; - int fifoNonWakeUpSensors = 0; + size_t fifoWakeUpSensors = 0; + size_t fifoNonWakeUpSensors = 0; for (size_t i = 0; i < mSensorInfo.size(); ++i) { const Sensor& sensor = mService->getSensorFromHandle(mSensorInfo.keyAt(i)); if (sensor.getFifoReservedEventCount() == sensor.getFifoMaxEventCount()) { diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h index 8719487e2c..9a573ae78c 100644 --- a/services/sensorservice/SensorService.h +++ b/services/sensorservice/SensorService.h @@ -27,6 +27,7 @@ #include <utils/AndroidThreads.h> #include <utils/RefBase.h> #include <utils/Looper.h> +#include <utils/String8.h> #include <binder/BinderService.h> @@ -37,6 +38,13 @@ #include "SensorInterface.h" +#if __clang__ +// Clang warns about SensorEventConnection::dump hiding BBinder::dump +// The cause isn't fixable without changing the API, so let's tell clang +// this is indeed intentional. +#pragma clang diagnostic ignored "-Woverloaded-virtual" +#endif + // --------------------------------------------------------------------------- #define DEBUG_CONNECTIONS false @@ -45,6 +53,9 @@ // For older HALs which don't support batching, use a smaller socket buffer size. #define SOCKET_BUFFER_SIZE_NON_BATCHED 4 * 1024 +#define CIRCULAR_BUF_SIZE 10 +#define SENSOR_REGISTRATIONS_BUF_SIZE 20 + struct sensors_poll_device_t; struct sensors_module_t; @@ -58,6 +69,51 @@ class SensorService : { friend class BinderService<SensorService>; + enum Mode { + // The regular operating mode where any application can register/unregister/call flush on + // sensors. + NORMAL = 0, + // This mode is only used for testing purposes. Not all HALs support this mode. In this + // mode, the HAL ignores the sensor data provided by physical sensors and accepts the data + // that is injected from the SensorService as if it were the real sensor data. This mode + // is primarily used for testing various algorithms like vendor provided SensorFusion, + // Step Counter and Step Detector etc. Typically in this mode, there will be a client + // (a SensorEventConnection) which will be injecting sensor data into the HAL. Normal apps + // can unregister and register for any sensor that supports injection. Registering to sensors + // that do not support injection will give an error. + // TODO(aakella) : Allow exactly one client to inject sensor data at a time. + DATA_INJECTION = 1, + // This mode is used only for testing sensors. Each sensor can be tested in isolation with + // the required sampling_rate and maxReportLatency parameters without having to think about + // the data rates requested by other applications. End user devices are always expected to be + // in NORMAL mode. When this mode is first activated, all active sensors from all connections + // are disabled. Calling flush() will return an error. In this mode, only the requests from + // selected apps whose package names are whitelisted are allowed (typically CTS apps). Only + // these apps can register/unregister/call flush() on sensors. If SensorService switches to + // NORMAL mode again, all sensors that were previously registered to are activated with the + // corresponding paramaters if the application hasn't unregistered for sensors in the mean + // time. + // NOTE: Non whitelisted app whose sensors were previously deactivated may still receive + // events if a whitelisted app requests data from the same sensor. + RESTRICTED = 2 + + // State Transitions supported. + // RESTRICTED <--- NORMAL ---> DATA_INJECTION + // ---> <--- + + // Shell commands to switch modes in SensorService. + // 1) Put SensorService in RESTRICTED mode with packageName .cts. If it is already in + // restricted mode it is treated as a NO_OP (and packageName is NOT changed). + // $ adb shell dumpsys sensorservice restrict .cts. + // + // 2) Put SensorService in DATA_INJECTION mode with packageName .xts. If it is already in + // data_injection mode it is treated as a NO_OP (and packageName is NOT changed). + // $ adb shell dumpsys sensorservice data_injection .xts. + // + // 3) Reset sensorservice back to NORMAL mode. + // $ adb shell dumpsys sensorservice enable + }; + static const char* WAKE_LOCK_NAME; static char const* getServiceName() ANDROID_API { return "sensorservice"; } @@ -70,8 +126,10 @@ class SensorService : virtual bool threadLoop(); // ISensorServer interface - virtual Vector<Sensor> getSensorList(); - virtual sp<ISensorEventConnection> createSensorEventConnection(); + virtual Vector<Sensor> getSensorList(const String16& opPackageName); + virtual sp<ISensorEventConnection> createSensorEventConnection(const String8& packageName, + int requestedMode, const String16& opPackageName); + virtual int isDataInjectionEnabled(); virtual status_t dump(int fd, const Vector<String16>& args); class SensorEventConnection : public BnSensorEventConnection, public LooperCallback { @@ -126,7 +184,6 @@ class SensorService : // connection FD may be added to the Looper. The flags to set are determined by the internal // state of the connection. FDs are added to the looper when wake-up sensors are registered // (to poll for acknowledgements) and when write fails on the socket when there are too many - // events (to poll when the FD is available for writing). FDs are removed when there is an // error and the other end hangs up or when this client unregisters for this connection. void updateLooperRegistration(const sp<Looper>& looper); void updateLooperRegistrationLocked(const sp<Looper>& looper); @@ -149,6 +206,8 @@ class SensorService : // mWakeLockRefCount is reset to zero. needsWakeLock method will always return false, if // this flag is set. bool mDead; + + bool mDataInjectionMode; struct FlushInfo { // The number of flush complete events dropped for this sensor is stored here. // They are sent separately before the next batch of events. @@ -162,14 +221,16 @@ class SensorService : KeyedVector<int, FlushInfo> mSensorInfo; sensors_event_t *mEventCache; int mCacheSize, mMaxCacheSize; - + String8 mPackageName; + const String16 mOpPackageName; #if DEBUG_CONNECTIONS int mEventsReceived, mEventsSent, mEventsSentFromCache; int mTotalAcksNeeded, mTotalAcksReceived; #endif public: - SensorEventConnection(const sp<SensorService>& service, uid_t uid); + SensorEventConnection(const sp<SensorService>& service, uid_t uid, String8 packageName, + bool isDataInjectionMode, const String16& opPackageName); status_t sendEvents(sensors_event_t const* buffer, size_t count, sensors_event_t* scratch, @@ -183,6 +244,7 @@ class SensorService : void dump(String8& result); bool needsWakeLock(); void resetWakeLockRefCount(); + String8 getPackageName() const; uid_t getUid() const { return mUid; } }; @@ -201,6 +263,7 @@ class SensorService : void addPendingFlushConnection(const sp<SensorEventConnection>& connection); void removeFirstPendingFlushConnection(); SensorEventConnection * getFirstPendingFlushConnection(); + void clearAllPendingFlushConnections(); }; class SensorEventAckReceiver : public Thread { @@ -210,6 +273,63 @@ class SensorService : SensorEventAckReceiver(const sp<SensorService>& service): mService(service) {} }; + // sensor_event_t with only the data and the timestamp. + struct TrimmedSensorEvent { + union { + float *mData; + uint64_t mStepCounter; + }; + // Timestamp from the sensor_event. + int64_t mTimestamp; + // HH:MM:SS local time at which this sensor event is read at SensorService. Useful + // for debugging. + int32_t mHour, mMin, mSec; + + TrimmedSensorEvent(int sensorType); + static bool isSentinel(const TrimmedSensorEvent& event); + + ~TrimmedSensorEvent() { + delete [] mData; + } + }; + + // A circular buffer of TrimmedSensorEvents. The size of this buffer is typically 10. The + // last N events generated from the sensor are stored in this buffer. The buffer is NOT + // cleared when the sensor unregisters and as a result one may see very old data in the + // dumpsys output but this is WAI. + class CircularBuffer { + int mNextInd; + int mSensorType; + int mBufSize; + TrimmedSensorEvent ** mTrimmedSensorEventArr; + public: + CircularBuffer(int sensor_event_type); + void addEvent(const sensors_event_t& sensor_event); + void printBuffer(String8& buffer) const; + bool populateLastEvent(sensors_event_t *event); + ~CircularBuffer(); + }; + + struct SensorRegistrationInfo { + int32_t mSensorHandle; + String8 mPackageName; + bool mActivated; + int32_t mSamplingRateUs; + int32_t mMaxReportLatencyUs; + int32_t mHour, mMin, mSec; + + SensorRegistrationInfo() : mPackageName() { + mSensorHandle = mSamplingRateUs = mMaxReportLatencyUs = INT32_MIN; + mHour = mMin = mSec = INT32_MIN; + mActivated = false; + } + + static bool isSentinel(const SensorRegistrationInfo& info) { + return (info.mHour == INT32_MIN && info.mMin == INT32_MIN && info.mSec == INT32_MIN); + } + }; + + static int getNumEventsForSensorType(int sensor_event_type); String8 getSensorName(int handle) const; bool isVirtualSensor(int handle) const; Sensor getSensorFromHandle(int handle) const; @@ -224,8 +344,8 @@ class SensorService : const sp<SensorEventConnection>& connection, int handle); void cleanupAutoDisabledSensorLocked(const sp<SensorEventConnection>& connection, sensors_event_t const* buffer, const int count); - static bool canAccessSensor(const Sensor& sensor); - static bool verifyCanAccessSensor(const Sensor& sensor, const char* operation); + static bool canAccessSensor(const Sensor& sensor, const char* operation, + const String16& opPackageName); // SensorService acquires a partial wakelock for delivering events from wake up sensors. This // method checks whether all the events from these wake up sensors have been delivered to the // corresponding applications, if yes the wakelock is released. @@ -254,6 +374,15 @@ class SensorService : // to the output vector. void populateActiveConnections(SortedVector< sp<SensorEventConnection> >* activeConnections); + // If SensorService is operating in RESTRICTED mode, only select whitelisted packages are + // allowed to register for or call flush on sensors. Typically only cts test packages are + // allowed. + bool isWhiteListedPackage(const String8& packageName); + + // Reset the state of SensorService to NORMAL mode. + status_t resetToNormalMode(); + status_t resetToNormalModeLocked(); + // constants Vector<Sensor> mSensorList; Vector<Sensor> mUserSensorListDebug; @@ -275,17 +404,28 @@ class SensorService : bool mWakeLockAcquired; sensors_event_t *mSensorEventBuffer, *mSensorEventScratch; SensorEventConnection const **mMapFlushEventsToConnections; + Mode mCurrentOperatingMode; + // This packagaName is set when SensorService is in RESTRICTED or DATA_INJECTION mode. Only + // applications with this packageName are allowed to activate/deactivate or call flush on + // sensors. To run CTS this is can be set to ".cts." and only CTS tests will get access to + // sensors. + String8 mWhiteListedPackage; // The size of this vector is constant, only the items are mutable - KeyedVector<int32_t, sensors_event_t> mLastEventSeen; + KeyedVector<int32_t, CircularBuffer *> mLastEventSeen; + int mNextSensorRegIndex; + Vector<SensorRegistrationInfo> mLastNSensorRegistrations; public: void cleanupConnection(SensorEventConnection* connection); status_t enable(const sp<SensorEventConnection>& connection, int handle, - nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags); + nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags, + const String16& opPackageName); status_t disable(const sp<SensorEventConnection>& connection, int handle); - status_t setEventRate(const sp<SensorEventConnection>& connection, int handle, nsecs_t ns); - status_t flushSensor(const sp<SensorEventConnection>& connection); + status_t setEventRate(const sp<SensorEventConnection>& connection, int handle, nsecs_t ns, + const String16& opPackageName); + status_t flushSensor(const sp<SensorEventConnection>& connection, + const String16& opPackageName); }; // --------------------------------------------------------------------------- diff --git a/services/sensorservice/tests/sensorservicetest.cpp b/services/sensorservice/tests/sensorservicetest.cpp index 1025fa83f8..cfdf6a38e5 100644 --- a/services/sensorservice/tests/sensorservicetest.cpp +++ b/services/sensorservice/tests/sensorservicetest.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include <inttypes.h> #include <android/sensor.h> #include <gui/Sensor.h> #include <gui/SensorManager.h> @@ -25,7 +26,7 @@ using namespace android; static nsecs_t sStartTime = 0; -int receiver(int fd, int events, void* data) +int receiver(__unused int fd, __unused int events, void* data) { sp<SensorEventQueue> q((SensorEventQueue*)data); ssize_t n; @@ -44,7 +45,7 @@ int receiver(int fd, int events, void* data) oldTimeStamp = buffer[i].timestamp; if (buffer[i].type == Sensor::TYPE_ACCELEROMETER) { - printf("%lld\t%8f\t%8f\t%8f\t%f\n", + printf("%" PRId64 "\t%8f\t%8f\t%8f\t%f\n", buffer[i].timestamp, buffer[i].data[0], buffer[i].data[1], buffer[i].data[2], 1.0/t); @@ -59,9 +60,9 @@ int receiver(int fd, int events, void* data) } -int main(int argc, char** argv) +int main() { - SensorManager& mgr(SensorManager::getInstance()); + SensorManager mgr(String16("Sensor Service Test")); Sensor const* const* list; ssize_t count = mgr.getSensorList(&list); diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index eade2e2210..1eb23616c3 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -1,10 +1,10 @@ -LOCAL_PATH:= $(call my-dir) +LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_CLANG := true LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -LOCAL_SRC_FILES:= \ +LOCAL_SRC_FILES := \ Client.cpp \ DisplayDevice.cpp \ DispSync.cpp \ @@ -37,18 +37,18 @@ LOCAL_SRC_FILES:= \ RenderEngine/GLES20RenderEngine.cpp -LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\" +LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\" LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES ifeq ($(TARGET_BOARD_PLATFORM),omap4) - LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY + LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY endif ifeq ($(TARGET_BOARD_PLATFORM),s5pc110) - LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY + LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY endif ifeq ($(TARGET_DISABLE_TRIPLE_BUFFERING),true) - LOCAL_CFLAGS += -DTARGET_DISABLE_TRIPLE_BUFFERING + LOCAL_CFLAGS += -DTARGET_DISABLE_TRIPLE_BUFFERING endif ifeq ($(TARGET_FORCE_HWC_FOR_VIRTUAL_DISPLAYS),true) @@ -56,7 +56,7 @@ ifeq ($(TARGET_FORCE_HWC_FOR_VIRTUAL_DISPLAYS),true) endif ifneq ($(NUM_FRAMEBUFFER_SURFACE_BUFFERS),) - LOCAL_CFLAGS += -DNUM_FRAMEBUFFER_SURFACE_BUFFERS=$(NUM_FRAMEBUFFER_SURFACE_BUFFERS) + LOCAL_CFLAGS += -DNUM_FRAMEBUFFER_SURFACE_BUFFERS=$(NUM_FRAMEBUFFER_SURFACE_BUFFERS) endif ifeq ($(TARGET_RUNNING_WITHOUT_SYNC_FRAMEWORK),true) @@ -93,20 +93,22 @@ LOCAL_CFLAGS += -fvisibility=hidden -Werror=format LOCAL_CFLAGS += -std=c++11 LOCAL_SHARED_LIBRARIES := \ - libcutils \ - liblog \ - libdl \ - libhardware \ - libutils \ - libEGL \ - libGLESv1_CM \ - libGLESv2 \ - libbinder \ - libui \ - libgui \ - libpowermanager - -LOCAL_MODULE:= libsurfaceflinger + libcutils \ + liblog \ + libdl \ + libhardware \ + libutils \ + libEGL \ + libGLESv1_CM \ + libGLESv2 \ + libbinder \ + libui \ + libgui \ + libpowermanager + +LOCAL_MODULE := libsurfaceflinger + +LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code include $(BUILD_SHARED_LIBRARY) @@ -114,46 +116,56 @@ include $(BUILD_SHARED_LIBRARY) # build surfaceflinger's executable include $(CLEAR_VARS) +LOCAL_CLANG := true + LOCAL_LDFLAGS := -Wl,--version-script,art/sigchainlib/version-script.txt -Wl,--export-dynamic -LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\" -LOCAL_CPPFLAGS:= -std=c++11 +LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\" +LOCAL_CPPFLAGS := -std=c++11 -LOCAL_SRC_FILES:= \ - main_surfaceflinger.cpp +LOCAL_SRC_FILES := \ + main_surfaceflinger.cpp LOCAL_SHARED_LIBRARIES := \ - libsurfaceflinger \ - libcutils \ - liblog \ - libbinder \ - libutils \ - libdl + libsurfaceflinger \ + libcutils \ + liblog \ + libbinder \ + libutils \ + libdl LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain -LOCAL_MODULE:= surfaceflinger +LOCAL_MODULE := surfaceflinger ifdef TARGET_32_BIT_SURFACEFLINGER LOCAL_32_BIT_ONLY := true endif +LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code + include $(BUILD_EXECUTABLE) ############################################################### # uses jni which may not be available in PDK ifneq ($(wildcard libnativehelper/include),) include $(CLEAR_VARS) -LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\" -LOCAL_SRC_FILES:= \ +LOCAL_CLANG := true + +LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\" +LOCAL_CPPFLAGS := -std=c++11 + +LOCAL_SRC_FILES := \ DdmConnection.cpp LOCAL_SHARED_LIBRARIES := \ - libcutils \ - liblog \ - libdl + libcutils \ + liblog \ + libdl + +LOCAL_MODULE := libsurfaceflinger_ddmconnection -LOCAL_MODULE:= libsurfaceflinger_ddmconnection +LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code include $(BUILD_SHARED_LIBRARY) endif # libnativehelper diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp index f7d32d0143..49389e062f 100644 --- a/services/surfaceflinger/Client.cpp +++ b/services/surfaceflinger/Client.cpp @@ -93,7 +93,7 @@ status_t Client::onTransact( const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); const int self_pid = getpid(); - if (CC_UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != 0)) { + if (CC_UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != AID_SYSTEM && uid != 0)) { // we're called from a different process, do the real check if (!PermissionCache::checkCallingPermission(sAccessSurfaceFlinger)) { diff --git a/services/surfaceflinger/DdmConnection.cpp b/services/surfaceflinger/DdmConnection.cpp index 2477921e34..659c2c8e49 100644 --- a/services/surfaceflinger/DdmConnection.cpp +++ b/services/surfaceflinger/DdmConnection.cpp @@ -59,12 +59,14 @@ void DdmConnection::start(const char* name) { } jint (*JNI_CreateJavaVM)(JavaVM** p_vm, JNIEnv** p_env, void* vm_args); - JNI_CreateJavaVM = (typeof JNI_CreateJavaVM)dlsym(libart_dso, "JNI_CreateJavaVM"); + JNI_CreateJavaVM = reinterpret_cast<decltype(JNI_CreateJavaVM)>( + dlsym(libart_dso, "JNI_CreateJavaVM")); ALOGE_IF(!JNI_CreateJavaVM, "DdmConnection: %s", dlerror()); jint (*registerNatives)(JNIEnv* env, jclass clazz); - registerNatives = (typeof registerNatives)dlsym(libandroid_runtime_dso, - "Java_com_android_internal_util_WithFramework_registerNatives"); + registerNatives = reinterpret_cast<decltype(registerNatives)>( + dlsym(libandroid_runtime_dso, + "Java_com_android_internal_util_WithFramework_registerNatives")); ALOGE_IF(!registerNatives, "DdmConnection: %s", dlerror()); if (!JNI_CreateJavaVM || !registerNatives) { diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h index 96efc3491a..67142b69db 100644 --- a/services/surfaceflinger/DispSync.h +++ b/services/surfaceflinger/DispSync.h @@ -139,7 +139,7 @@ private: enum { MAX_RESYNC_SAMPLES = 32 }; enum { MIN_RESYNC_SAMPLES_FOR_UPDATE = 3 }; enum { NUM_PRESENT_SAMPLES = 8 }; - enum { MAX_RESYNC_SAMPLES_WITHOUT_PRESENT = 12 }; + enum { MAX_RESYNC_SAMPLES_WITHOUT_PRESENT = 4 }; // mPeriod is the computed period of the modeled vsync events in // nanoseconds. diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 564f9748e1..13d44f39b5 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -44,6 +44,18 @@ using namespace android; // ---------------------------------------------------------------------------- +#ifdef EGL_ANDROID_swap_rectangle +static constexpr bool kEGLAndroidSwapRectangle = true; +#else +static constexpr bool kEGLAndroidSwapRectangle = false; +#endif + +#if !defined(EGL_EGLEXT_PROTOTYPES) || !defined(EGL_ANDROID_swap_rectangle) +// Dummy implementation in case it is missing. +inline void eglSetSwapRectangleANDROID (EGLDisplay, EGLSurface, EGLint, EGLint, EGLint, EGLint) { +} +#endif + /* * Initialize the display to the specified values. * @@ -84,7 +96,6 @@ DisplayDevice::DisplayDevice( */ EGLSurface surface; - EGLint w, h; EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (config == EGL_NO_CONFIG) { config = RenderEngine::chooseEglConfig(display, format); @@ -188,19 +199,14 @@ void DisplayDevice::flip(const Region& dirty) const { mFlinger->getRenderEngine().checkErrors(); - EGLDisplay dpy = mDisplay; - EGLSurface surface = mSurface; - -#ifdef EGL_ANDROID_swap_rectangle - if (mFlags & SWAP_RECTANGLE) { - const Region newDirty(dirty.intersect(bounds())); - const Rect b(newDirty.getBounds()); - eglSetSwapRectangleANDROID(dpy, surface, - b.left, b.top, b.width(), b.height()); + if (kEGLAndroidSwapRectangle) { + if (mFlags & SWAP_RECTANGLE) { + const Region newDirty(dirty.intersect(bounds())); + const Rect b(newDirty.getBounds()); + eglSetSwapRectangleANDROID(mDisplay, mSurface, + b.left, b.top, b.width(), b.height()); + } } -#else - (void) dirty; // Eliminate unused parameter warning -#endif mPageFlipCount++; } @@ -511,6 +517,6 @@ void DisplayDevice::dump(String8& result) const { tr[0][2], tr[1][2], tr[2][2]); String8 surfaceDump; - mDisplaySurface->dump(surfaceDump); + mDisplaySurface->dumpAsString(surfaceDump); result.append(surfaceDump); } diff --git a/services/surfaceflinger/DisplayHardware/DisplaySurface.h b/services/surfaceflinger/DisplayHardware/DisplaySurface.h index e60c4fb7b9..2f743c1901 100644 --- a/services/surfaceflinger/DisplayHardware/DisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/DisplaySurface.h @@ -70,7 +70,7 @@ public: // frame's buffer. virtual void onFrameCommitted() = 0; - virtual void dump(String8& result) const = 0; + virtual void dumpAsString(String8& result) const = 0; virtual void resizeBuffers(const uint32_t w, const uint32_t h) = 0; diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp index 22d3cecbfd..6ef3295b07 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -29,8 +29,9 @@ #include <EGL/egl.h> #include <hardware/hardware.h> -#include <gui/Surface.h> +#include <gui/BufferItem.h> #include <gui/GraphicBufferAlloc.h> +#include <gui/Surface.h> #include <ui/GraphicBuffer.h> #include "FramebufferSurface.h" @@ -86,7 +87,7 @@ status_t FramebufferSurface::advanceFrame() { status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence) { Mutex::Autolock lock(mMutex); - BufferQueue::BufferItem item; + BufferItem item; status_t err = acquireBufferLocked(&item, 0); if (err == BufferQueue::NO_BUFFER_AVAILABLE) { outBuffer = mCurrentBuffer; @@ -160,23 +161,7 @@ status_t FramebufferSurface::compositionComplete() return mHwc.fbCompositionComplete(); } -// Since DisplaySurface and ConsumerBase both have a method with this -// signature, results will vary based on the static pointer type the caller is -// using: -// void dump(FrameBufferSurface* fbs, String8& s) { -// // calls FramebufferSurface::dump() -// fbs->dump(s); -// -// // calls ConsumerBase::dump() since it is non-virtual -// static_cast<ConsumerBase*>(fbs)->dump(s); -// -// // calls FramebufferSurface::dump() since it is virtual -// static_cast<DisplaySurface*>(fbs)->dump(s); -// } -// To make sure that all of these end up doing the same thing, we just redirect -// to ConsumerBase::dump() here. It will take the internal lock, and then call -// virtual dumpLocked(), which is where the real work happens. -void FramebufferSurface::dump(String8& result) const { +void FramebufferSurface::dumpAsString(String8& result) const { ConsumerBase::dump(result); } diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h index 8605862e5c..3d1784086e 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h @@ -44,10 +44,7 @@ public: virtual status_t compositionComplete(); virtual status_t advanceFrame(); virtual void onFrameCommitted(); - - // Implementation of DisplaySurface::dump(). Note that ConsumerBase also - // has a non-virtual dump() with the same signature. - virtual void dump(String8& result) const; + virtual void dumpAsString(String8& result) const; // Cannot resize a buffers in a FramebufferSurface. Only works with virtual // displays. diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index edfed491b4..2dad005171 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -305,13 +305,16 @@ void HWComposer::vsync(int disp, int64_t timestamp) { } void HWComposer::hotplug(int disp, int connected) { - if (disp == HWC_DISPLAY_PRIMARY || disp >= VIRTUAL_DISPLAY_ID_BASE) { + if (disp >= VIRTUAL_DISPLAY_ID_BASE) { ALOGE("hotplug event received for invalid display: disp=%d connected=%d", disp, connected); return; } queryDisplayProperties(disp); - mEventHandler.onHotplugReceived(disp, bool(connected)); + // Do not teardown or recreate the primary display + if (disp != HWC_DISPLAY_PRIMARY) { + mEventHandler.onHotplugReceived(disp, bool(connected)); + } } static float getDefaultDensity(uint32_t width, uint32_t height) { @@ -461,7 +464,7 @@ sp<Fence> HWComposer::getDisplayFence(int disp) const { } uint32_t HWComposer::getFormat(int disp) const { - if (uint32_t(disp)>31 || !mAllocatedDisplayIDs.hasBit(disp)) { + if (static_cast<uint32_t>(disp) >= MAX_HWC_DISPLAYS || !mAllocatedDisplayIDs.hasBit(disp)) { return HAL_PIXEL_FORMAT_RGBA_8888; } else { return mDisplayData[disp].format; @@ -632,6 +635,7 @@ status_t HWComposer::setFramebufferTarget(int32_t id, } status_t HWComposer::prepare() { + Mutex::Autolock _l(mDisplayLock); for (size_t i=0 ; i<mNumDisplays ; i++) { DisplayData& disp(mDisplayData[i]); if (disp.framebufferTarget) { @@ -1020,6 +1024,21 @@ public: SharedBuffer const* sb = reg.getSharedBuffer(&visibleRegion.numRects); visibleRegion.rects = reinterpret_cast<hwc_rect_t const *>(sb->data()); } + virtual void setSurfaceDamage(const Region& reg) { + if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_5)) { + return; + } + hwc_region_t& surfaceDamage = getLayer()->surfaceDamage; + // We encode default full-screen damage as INVALID_RECT upstream, but as + // 0 rects for HWComposer + if (reg.isRect() && reg.getBounds() == Rect::INVALID_RECT) { + surfaceDamage.numRects = 0; + surfaceDamage.rects = NULL; + return; + } + SharedBuffer const* sb = reg.getSharedBuffer(&surfaceDamage.numRects); + surfaceDamage.rects = reinterpret_cast<hwc_rect_t const *>(sb->data()); + } virtual void setSidebandStream(const sp<NativeHandle>& stream) { ALOG_ASSERT(stream->handle() != NULL); getLayer()->compositionType = HWC_SIDEBAND; @@ -1050,6 +1069,18 @@ public: } getLayer()->acquireFenceFd = -1; + + if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_5)) { + return; + } + + hwc_region_t& surfaceDamage = getLayer()->surfaceDamage; + sb = SharedBuffer::bufferFromData(surfaceDamage.rects); + if (sb) { + sb->release(); + surfaceDamage.numRects = 0; + surfaceDamage.rects = NULL; + } } }; @@ -1105,8 +1136,6 @@ static String8 getFormatStr(PixelFormat format) { case PIXEL_FORMAT_RGB_888: return String8("RGB_888"); case PIXEL_FORMAT_RGB_565: return String8("RGB_565"); case PIXEL_FORMAT_BGRA_8888: return String8("BGRA_8888"); - case PIXEL_FORMAT_sRGB_A_8888: return String8("sRGB_A_8888"); - case PIXEL_FORMAT_sRGB_X_8888: return String8("sRGB_x_8888"); case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: return String8("ImplDef"); default: @@ -1117,6 +1146,7 @@ static String8 getFormatStr(PixelFormat format) { } void HWComposer::dump(String8& result) const { + Mutex::Autolock _l(mDisplayLock); if (mHwc) { result.appendFormat("Hardware Composer state (version %08x):\n", hwcApiVersion(mHwc)); result.appendFormat(" mDebugForceFakeVSync=%d\n", mDebugForceFakeVSync); diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index a62ac5c652..cc98b4c20a 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -168,6 +168,7 @@ public: virtual void setFrame(const Rect& frame) = 0; virtual void setCrop(const FloatRect& crop) = 0; virtual void setVisibleRegionScreen(const Region& reg) = 0; + virtual void setSurfaceDamage(const Region& reg) = 0; virtual void setSidebandStream(const sp<NativeHandle>& stream) = 0; virtual void setBuffer(const sp<GraphicBuffer>& buffer) = 0; virtual void setAcquireFenceFd(int fenceFd) = 0; @@ -353,6 +354,8 @@ private: // mLists[i>0] can be NULL. that display is to be ignored struct hwc_display_contents_1* mLists[MAX_HWC_DISPLAYS]; DisplayData mDisplayData[MAX_HWC_DISPLAYS]; + // protect mDisplayData from races between prepare and dump + mutable Mutex mDisplayLock; size_t mNumDisplays; cb_context* mCBContext; diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index c3d45ee09a..ba4c1981af 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -18,6 +18,8 @@ #include "VirtualDisplaySurface.h" #include "HWComposer.h" +#include <gui/BufferItem.h> + // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- @@ -234,6 +236,7 @@ void VirtualDisplaySurface::onFrameCommitted() { status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot, QueueBufferInput( systemTime(), false /* isAutoTimestamp */, + HAL_DATASPACE_UNKNOWN, Rect(mSinkBufferWidth, mSinkBufferHeight), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0 /* transform */, true /* async*/, @@ -254,7 +257,7 @@ void VirtualDisplaySurface::onFrameCommitted() { resetPerFrameState(); } -void VirtualDisplaySurface::dump(String8& /* result */) const { +void VirtualDisplaySurface::dumpAsString(String8& /* result */) const { } void VirtualDisplaySurface::resizeBuffers(const uint32_t w, const uint32_t h) { @@ -284,7 +287,7 @@ status_t VirtualDisplaySurface::setBufferCount(int bufferCount) { } status_t VirtualDisplaySurface::dequeueBuffer(Source source, - uint32_t format, uint32_t usage, int* sslot, sp<Fence>* fence) { + PixelFormat format, uint32_t usage, int* sslot, sp<Fence>* fence) { LOG_FATAL_IF(mDisplayId < 0, "mDisplayId=%d but should not be < 0.", mDisplayId); // Don't let a slow consumer block us bool async = (source == SOURCE_SINK); @@ -329,7 +332,7 @@ status_t VirtualDisplaySurface::dequeueBuffer(Source source, } status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence, bool async, - uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { + uint32_t w, uint32_t h, PixelFormat format, uint32_t usage) { if (mDisplayId < 0) return mSource[SOURCE_SINK]->dequeueBuffer(pslot, fence, async, w, h, format, usage); @@ -364,7 +367,7 @@ status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence, bool usage |= GRALLOC_USAGE_HW_COMPOSER; const sp<GraphicBuffer>& buf = mProducerBuffers[mOutputProducerSlot]; if ((usage & ~buf->getUsage()) != 0 || - (format != 0 && format != (uint32_t)buf->getPixelFormat()) || + (format != 0 && format != buf->getPixelFormat()) || (w != 0 && w != mSinkBufferWidth) || (h != 0 && h != mSinkBufferHeight)) { VDS_LOGV("dequeueBuffer: dequeueing new output buffer: " @@ -435,7 +438,7 @@ status_t VirtualDisplaySurface::queueBuffer(int pslot, // Now acquire the buffer from the scratch pool -- should be the same // slot and fence as we just queued. Mutex::Autolock lock(mMutex); - BufferQueue::BufferItem item; + BufferItem item; result = acquireBufferLocked(&item, 0); if (result != NO_ERROR) return result; @@ -453,12 +456,13 @@ status_t VirtualDisplaySurface::queueBuffer(int pslot, // Extract the GLES release fence for HWC to acquire int64_t timestamp; bool isAutoTimestamp; + android_dataspace dataSpace; Rect crop; int scalingMode; uint32_t transform; bool async; - input.deflate(×tamp, &isAutoTimestamp, &crop, &scalingMode, - &transform, &async, &mFbFence); + input.deflate(×tamp, &isAutoTimestamp, &dataSpace, &crop, + &scalingMode, &transform, &async, &mFbFence); mFbProducerSlot = pslot; mOutputFence = mFbFence; @@ -517,11 +521,24 @@ status_t VirtualDisplaySurface::setSidebandStream(const sp<NativeHandle>& /*stre } void VirtualDisplaySurface::allocateBuffers(bool /* async */, - uint32_t /* width */, uint32_t /* height */, uint32_t /* format */, + uint32_t /* width */, uint32_t /* height */, PixelFormat /* format */, uint32_t /* usage */) { // TODO: Should we actually allocate buffers for a virtual display? } +status_t VirtualDisplaySurface::allowAllocation(bool /* allow */) { + return INVALID_OPERATION; +} + +status_t VirtualDisplaySurface::setGenerationNumber(uint32_t /* generation */) { + ALOGE("setGenerationNumber not supported on VirtualDisplaySurface"); + return INVALID_OPERATION; +} + +String8 VirtualDisplaySurface::getConsumerName() const { + return String8("VirtualDisplaySurface"); +} + void VirtualDisplaySurface::updateQueueBufferOutput( const QueueBufferOutput& qbo) { uint32_t w, h, transformHint, numPendingBuffers; diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index 363dce2066..6298751f30 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -86,7 +86,7 @@ public: virtual status_t compositionComplete(); virtual status_t advanceFrame(); virtual void onFrameCommitted(); - virtual void dump(String8& result) const; + virtual void dumpAsString(String8& result) const; virtual void resizeBuffers(const uint32_t w, const uint32_t h); private: @@ -100,7 +100,7 @@ private: virtual status_t requestBuffer(int pslot, sp<GraphicBuffer>* outBuf); virtual status_t setBufferCount(int bufferCount); virtual status_t dequeueBuffer(int* pslot, sp<Fence>* fence, bool async, - uint32_t w, uint32_t h, uint32_t format, uint32_t usage); + uint32_t w, uint32_t h, PixelFormat format, uint32_t usage); virtual status_t detachBuffer(int slot); virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence); @@ -114,13 +114,16 @@ private: virtual status_t disconnect(int api); virtual status_t setSidebandStream(const sp<NativeHandle>& stream); virtual void allocateBuffers(bool async, uint32_t width, uint32_t height, - uint32_t format, uint32_t usage); + PixelFormat format, uint32_t usage); + virtual status_t allowAllocation(bool allow); + virtual status_t setGenerationNumber(uint32_t generationNumber); + virtual String8 getConsumerName() const override; // // Utility methods // static Source fbSourceForCompositionType(CompositionType type); - status_t dequeueBuffer(Source source, uint32_t format, uint32_t usage, + status_t dequeueBuffer(Source source, PixelFormat format, uint32_t usage, int* sslot, sp<Fence>* fence); void updateQueueBufferOutput(const QueueBufferOutput& qbo); void resetPerFrameState(); diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp index 9b6360ef72..f760200006 100644 --- a/services/surfaceflinger/EventThread.cpp +++ b/services/surfaceflinger/EventThread.cpp @@ -71,6 +71,11 @@ void EventThread::sendVsyncHintOff() { mVsyncHintSent = false; } +void EventThread::setPhaseOffset(nsecs_t phaseOffset) { + Mutex::Autolock _l(mLock); + mVSyncSource->setPhaseOffset(phaseOffset); +} + void EventThread::sendVsyncHintOnLocked() { struct itimerspec ts; if(!mVsyncHintSent) { diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h index d1c4fcd987..9ba179ad7b 100644 --- a/services/surfaceflinger/EventThread.h +++ b/services/surfaceflinger/EventThread.h @@ -51,6 +51,7 @@ public: virtual ~VSyncSource() {} virtual void setVSyncEnabled(bool enable) = 0; virtual void setCallback(const sp<Callback>& callback) = 0; + virtual void setPhaseOffset(nsecs_t phaseOffset) = 0; }; class EventThread : public Thread, private VSyncSource::Callback { @@ -99,6 +100,8 @@ public: void dump(String8& result) const; void sendVsyncHintOff(); + void setPhaseOffset(nsecs_t phaseOffset); + private: virtual bool threadLoop(); virtual void onFirstRef(); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 5e3dfabb39..5ff79a9e3b 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -64,7 +64,6 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client, mTextureName(-1U), mPremultipliedAlpha(true), mName("unnamed"), - mDebug(false), mFormat(PIXEL_FORMAT_NONE), mTransactionFlags(0), mQueuedFrames(0), @@ -77,11 +76,15 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client, mFiltering(false), mNeedsFiltering(false), mMesh(Mesh::TRIANGLE_FAN, 4, 2, 2), - mSecure(false), mProtectedByApp(false), mHasSurface(false), mClientRef(client), - mPotentialCursor(false) + mPotentialCursor(false), + mQueueItemLock(), + mQueueItemCondition(), + mQueueItems(), + mLastFrameNumberReceived(0), + mUpdateTexImageFailed(false) { mCurrentCrop.makeInvalid(); mFlinger->getRenderEngine().genTextures(1, &mTextureName); @@ -92,6 +95,8 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client, layerFlags |= layer_state_t::eLayerHidden; if (flags & ISurfaceComposerClient::eOpaque) layerFlags |= layer_state_t::eLayerOpaque; + if (flags & ISurfaceComposerClient::eSecure) + layerFlags |= layer_state_t::eLayerSecure; if (flags & ISurfaceComposerClient::eNonPremultiplied) mPremultipliedAlpha = false; @@ -164,20 +169,54 @@ void Layer::onFrameAvailable(const BufferItem& item) { // Add this buffer from our internal queue tracker { // Autolock scope Mutex::Autolock lock(mQueueItemLock); + + // Reset the frame number tracker when we receive the first buffer after + // a frame number reset + if (item.mFrameNumber == 1) { + mLastFrameNumberReceived = 0; + } + + // Ensure that callbacks are handled in order + while (item.mFrameNumber != mLastFrameNumberReceived + 1) { + status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, + ms2ns(500)); + if (result != NO_ERROR) { + ALOGE("[%s] Timed out waiting on callback", mName.string()); + } + } + mQueueItems.push_back(item); + android_atomic_inc(&mQueuedFrames); + + // Wake up any pending callbacks + mLastFrameNumberReceived = item.mFrameNumber; + mQueueItemCondition.broadcast(); } - android_atomic_inc(&mQueuedFrames); mFlinger->signalLayerUpdate(); } void Layer::onFrameReplaced(const BufferItem& item) { Mutex::Autolock lock(mQueueItemLock); + + // Ensure that callbacks are handled in order + while (item.mFrameNumber != mLastFrameNumberReceived + 1) { + status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, + ms2ns(500)); + if (result != NO_ERROR) { + ALOGE("[%s] Timed out waiting on callback", mName.string()); + } + } + if (mQueueItems.empty()) { ALOGE("Can't replace a frame on an empty queue"); return; } mQueueItems.editItemAt(0) = item; + + // Wake up any pending callbacks + mLastFrameNumberReceived = item.mFrameNumber; + mQueueItemCondition.broadcast(); } void Layer::onSidebandStreamChanged() { @@ -218,7 +257,6 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h, mFormat = format; mPotentialCursor = (flags & ISurfaceComposerClient::eCursorWindow) ? true : false; - mSecure = (flags & ISurfaceComposerClient::eSecure) ? true : false; mProtectedByApp = (flags & ISurfaceComposerClient::eProtectedByApp) ? true : false; mCurrentOpacity = getOpacityForFormat(format); @@ -513,6 +551,7 @@ void Layer::setPerFrameData(const sp<const DisplayDevice>& hw, const Transform& tr = hw->getTransform(); Region visible = tr.transform(visibleRegion.intersect(hw->getViewport())); layer.setVisibleRegionScreen(visible); + layer.setSurfaceDamage(surfaceDamageRegion); if (mSidebandStream.get()) { layer.setSidebandStream(mSidebandStream); @@ -693,7 +732,6 @@ void Layer::clearWithOpenGL( void Layer::drawWithOpenGL(const sp<const DisplayDevice>& hw, const Region& /* clip */, bool useIdentityTransform) const { - const uint32_t fbHeight = hw->getHeight(); const State& s(getDrawingState()); computeGeometry(hw, mMesh, useIdentityTransform); @@ -766,7 +804,6 @@ bool Layer::getOpacityForFormat(uint32_t format) { switch (format) { case HAL_PIXEL_FORMAT_RGBA_8888: case HAL_PIXEL_FORMAT_BGRA_8888: - case HAL_PIXEL_FORMAT_sRGB_A_8888: return false; } // in all other case, we have no blending (also for unknown formats) @@ -814,6 +851,12 @@ bool Layer::isOpaque(const Layer::State& s) const return ((s.flags & layer_state_t::eLayerOpaque) != 0) || mCurrentOpacity; } +bool Layer::isSecure() const +{ + const Layer::State& s(mDrawingState); + return (s.flags & layer_state_t::eLayerSecure); +} + bool Layer::isProtected() const { const sp<GraphicBuffer>& activeBuffer(mActiveBuffer); @@ -911,7 +954,7 @@ uint32_t Layer::doTransaction(uint32_t flags) { const bool resizePending = (c.requested.w != c.active.w) || (c.requested.h != c.active.h); - if (resizePending) { + if (resizePending && mSidebandStream == NULL) { // don't let Layer::doTransaction update the drawing state // if we have a pending resize, unless we are in fixed-size mode. // the drawing state will be updated only once we receive a buffer @@ -920,6 +963,10 @@ uint32_t Layer::doTransaction(uint32_t flags) { // in particular, we want to make sure the clip (which is part // of the geometry state) is latched together with the size but is // latched immediately when no resizing is involved. + // + // If a sideband stream is attached, however, we want to skip this + // optimization so that transactions aren't missed when a buffer + // never arrives flags |= eDontUpdateGeometryState; } @@ -1037,16 +1084,43 @@ bool Layer::setLayerStack(uint32_t layerStack) { return true; } +void Layer::useSurfaceDamage() { + if (mFlinger->mForceFullDamage) { + surfaceDamageRegion = Region::INVALID_REGION; + } else { + surfaceDamageRegion = mSurfaceFlingerConsumer->getSurfaceDamage(); + } +} + +void Layer::useEmptyDamage() { + surfaceDamageRegion.clear(); +} + // ---------------------------------------------------------------------------- // pageflip handling... // ---------------------------------------------------------------------------- bool Layer::shouldPresentNow(const DispSync& dispSync) const { + if (mSidebandStreamChanged) { + return true; + } + Mutex::Autolock lock(mQueueItemLock); + if (mQueueItems.empty()) { + return false; + } + auto timestamp = mQueueItems[0].mTimestamp; nsecs_t expectedPresent = mSurfaceFlingerConsumer->computeExpectedPresent(dispSync); - return mQueueItems.empty() ? - false : mQueueItems[0].mTimestamp < expectedPresent; + + // Ignore timestamps more than a second in the future + bool isPlausible = timestamp < (expectedPresent + s2ns(1)); + ALOGW_IF(!isPlausible, "[%s] Timestamp %" PRId64 " seems implausible " + "relative to expectedPresent %" PRId64, mName.string(), timestamp, + expectedPresent); + + bool isDue = timestamp < expectedPresent; + return isDue || !isPlausible; } bool Layer::onPreComposition() { @@ -1097,6 +1171,10 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) { // mSidebandStreamChanged was true mSidebandStream = mSurfaceFlingerConsumer->getSidebandStream(); + if (mSidebandStream != NULL) { + setTransactionFlags(eTransactionNeeded); + mFlinger->setTransactionFlags(eTraversalNeeded); + } recomputeVisibleRegions = true; const State& s(getDrawingState()); @@ -1133,7 +1211,7 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) } virtual bool reject(const sp<GraphicBuffer>& buf, - const IGraphicBufferConsumer::BufferItem& item) { + const BufferItem& item) { if (buf == NULL) { return false; } @@ -1229,21 +1307,62 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) Reject r(mDrawingState, getCurrentState(), recomputeVisibleRegions, getProducerStickyTransform() != 0); + uint64_t maxFrameNumber = 0; + { + Mutex::Autolock lock(mQueueItemLock); + maxFrameNumber = mLastFrameNumberReceived; + } + status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r, - mFlinger->mPrimaryDispSync); + mFlinger->mPrimaryDispSync, maxFrameNumber); if (updateResult == BufferQueue::PRESENT_LATER) { // Producer doesn't want buffer to be displayed yet. Signal a // layer update so we check again at the next opportunity. mFlinger->signalLayerUpdate(); return outDirtyRegion; + } else if (updateResult == SurfaceFlingerConsumer::BUFFER_REJECTED) { + // If the buffer has been rejected, remove it from the shadow queue + // and return early + Mutex::Autolock lock(mQueueItemLock); + mQueueItems.removeAt(0); + android_atomic_dec(&mQueuedFrames); + return outDirtyRegion; + } else if (updateResult != NO_ERROR || mUpdateTexImageFailed) { + // This can occur if something goes wrong when trying to create the + // EGLImage for this buffer. If this happens, the buffer has already + // been released, so we need to clean up the queue and bug out + // early. + { + Mutex::Autolock lock(mQueueItemLock); + mQueueItems.clear(); + android_atomic_and(0, &mQueuedFrames); + } + + // Once we have hit this state, the shadow queue may no longer + // correctly reflect the incoming BufferQueue's contents, so even if + // updateTexImage starts working, the only safe course of action is + // to continue to ignore updates. + mUpdateTexImageFailed = true; + + return outDirtyRegion; } - // Remove this buffer from our internal queue tracker { // Autolock scope + auto currentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber(); + Mutex::Autolock lock(mQueueItemLock); + + // Remove any stale buffers that have been dropped during + // updateTexImage + while (mQueueItems[0].mFrameNumber != currentFrameNumber) { + mQueueItems.removeAt(0); + android_atomic_dec(&mQueuedFrames); + } + mQueueItems.removeAt(0); } + // Decrement the queued-frames count. Signal another event if we // have more frames pending. if (android_atomic_dec(&mQueuedFrames) > 1) { @@ -1352,6 +1471,7 @@ void Layer::dump(String8& result, Colorizer& colorizer) const s.activeTransparentRegion.dump(result, "transparentRegion"); visibleRegion.dump(result, "visibleRegion"); + surfaceDamageRegion.dump(result, "surfaceDamageRegion"); sp<Client> client(mClientRef.promote()); result.appendFormat( " " diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 1d4eee7789..c1e5e9ff19 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -76,6 +76,7 @@ public: Region visibleRegion; Region coveredRegion; Region visibleNonTransparentRegion; + Region surfaceDamageRegion; // Layer serial number. This gives layers an explicit ordering, so we // have a stable sort order when their layer stack and Z-order are @@ -137,6 +138,12 @@ public: bool setCrop(const Rect& crop); bool setLayerStack(uint32_t layerStack); + // If we have received a new buffer this frame, we will pass its surface + // damage down to hardware composer. Otherwise, we must send a region with + // one empty rect. + void useSurfaceDamage(); + void useEmptyDamage(); + uint32_t getTransactionFlags(uint32_t flags); uint32_t setTransactionFlags(uint32_t flags); @@ -167,7 +174,7 @@ public: * isSecure - true if this surface is secure, that is if it prevents * screenshots or VNC servers. */ - virtual bool isSecure() const { return mSecure; } + virtual bool isSecure() const; /* * isProtected - true if the layer may contain protected content in the @@ -332,9 +339,9 @@ protected: private: // Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener - virtual void onFrameAvailable(const BufferItem& item); - virtual void onFrameReplaced(const BufferItem& item); - virtual void onSidebandStreamChanged(); + virtual void onFrameAvailable(const BufferItem& item) override; + virtual void onFrameReplaced(const BufferItem& item) override; + virtual void onSidebandStreamChanged() override; void commitTransaction(); @@ -364,7 +371,6 @@ private: uint32_t mTextureName; // from GLES bool mPremultipliedAlpha; String8 mName; - mutable bool mDebug; PixelFormat mFormat; // these are protected by an external lock @@ -396,7 +402,6 @@ private: mutable Texture mTexture; // page-flip thread (currently main thread) - bool mSecure; // no screenshots bool mProtectedByApp; // application requires protected path to external sink // protected by mLock @@ -410,7 +415,10 @@ private: // Local copy of the queued contents of the incoming BufferQueue mutable Mutex mQueueItemLock; + Condition mQueueItemCondition; Vector<BufferItem> mQueueItems; + uint64_t mLastFrameNumberReceived; + bool mUpdateTexImageFailed; // This is only modified from the main thread }; // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp index 8739682ef5..fb7af97741 100644 --- a/services/surfaceflinger/MonitoredProducer.cpp +++ b/services/surfaceflinger/MonitoredProducer.cpp @@ -49,7 +49,7 @@ MonitoredProducer::~MonitoredProducer() { wp<IBinder> mProducer; }; - mFlinger->postMessageAsync(new MessageCleanUpList(mFlinger, asBinder())); + mFlinger->postMessageAsync(new MessageCleanUpList(mFlinger, asBinder(this))); } status_t MonitoredProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) { @@ -61,7 +61,7 @@ status_t MonitoredProducer::setBufferCount(int bufferCount) { } status_t MonitoredProducer::dequeueBuffer(int* slot, sp<Fence>* fence, - bool async, uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { + bool async, uint32_t w, uint32_t h, PixelFormat format, uint32_t usage) { return mProducer->dequeueBuffer(slot, fence, async, w, h, format, usage); } @@ -106,12 +106,24 @@ status_t MonitoredProducer::setSidebandStream(const sp<NativeHandle>& stream) { } void MonitoredProducer::allocateBuffers(bool async, uint32_t width, - uint32_t height, uint32_t format, uint32_t usage) { + uint32_t height, PixelFormat format, uint32_t usage) { mProducer->allocateBuffers(async, width, height, format, usage); } +status_t MonitoredProducer::allowAllocation(bool allow) { + return mProducer->allowAllocation(allow); +} + +status_t MonitoredProducer::setGenerationNumber(uint32_t generationNumber) { + return mProducer->setGenerationNumber(generationNumber); +} + +String8 MonitoredProducer::getConsumerName() const { + return mProducer->getConsumerName(); +} + IBinder* MonitoredProducer::onAsBinder() { - return mProducer->asBinder().get(); + return IInterface::asBinder(mProducer).get(); } // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h index f6ccc51cbb..da95766ceb 100644 --- a/services/surfaceflinger/MonitoredProducer.h +++ b/services/surfaceflinger/MonitoredProducer.h @@ -37,7 +37,7 @@ public: virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf); virtual status_t setBufferCount(int bufferCount); virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, bool async, - uint32_t w, uint32_t h, uint32_t format, uint32_t usage); + uint32_t w, uint32_t h, PixelFormat format, uint32_t usage); virtual status_t detachBuffer(int slot); virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence); @@ -52,7 +52,10 @@ public: virtual status_t disconnect(int api); virtual status_t setSidebandStream(const sp<NativeHandle>& stream); virtual void allocateBuffers(bool async, uint32_t width, uint32_t height, - uint32_t format, uint32_t usage); + PixelFormat format, uint32_t usage); + virtual status_t allowAllocation(bool allow); + virtual status_t setGenerationNumber(uint32_t generationNumber); + virtual String8 getConsumerName() const override; virtual IBinder* onAsBinder(); private: diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/services/surfaceflinger/RenderEngine/Description.cpp index 1adcd1f5ac..0dab872682 100644 --- a/services/surfaceflinger/RenderEngine/Description.cpp +++ b/services/surfaceflinger/RenderEngine/Description.cpp @@ -88,5 +88,9 @@ void Description::setColorMatrix(const mat4& mtx) { mColorMatrixEnabled = (mtx != identity); } +const mat4& Description::getColorMatrix() const { + return mColorMatrix; +} + } /* namespace android */ diff --git a/services/surfaceflinger/RenderEngine/Description.h b/services/surfaceflinger/RenderEngine/Description.h index 43b835f02b..8a3447c5a1 100644 --- a/services/surfaceflinger/RenderEngine/Description.h +++ b/services/surfaceflinger/RenderEngine/Description.h @@ -66,6 +66,7 @@ public: void setColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); void setProjectionMatrix(const mat4& mtx); void setColorMatrix(const mat4& mtx); + const mat4& getColorMatrix() const; private: bool mUniformsDirty; diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp index c2768f33a7..1a9f59b582 100644 --- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp @@ -43,12 +43,6 @@ GLES11RenderEngine::GLES11RenderEngine() { glDisable(GL_DITHER); glDisable(GL_CULL_FACE); - struct pack565 { - inline uint16_t operator() (int r, int g, int b) const { - return (r<<11)|(g<<5)|b; - } - } pack565; - const uint16_t protTexData[] = { 0 }; glGenTextures(1, &mProtectedTexName); glBindTexture(GL_TEXTURE_2D, mProtectedTexName); @@ -268,14 +262,6 @@ void GLES11RenderEngine::drawMesh(const Mesh& mesh) { } } -void GLES11RenderEngine::beginGroup(const mat4& /*colorTransform*/) { - // doesn't do anything in GLES 1.1 -} - -void GLES11RenderEngine::endGroup() { - // doesn't do anything in GLES 1.1 -} - void GLES11RenderEngine::dump(String8& result) { RenderEngine::dump(result); } diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h index 87eb3e4e4f..08de6465f4 100644 --- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h @@ -62,9 +62,6 @@ protected: virtual void drawMesh(const Mesh& mesh); - virtual void beginGroup(const mat4& colorTransform); - virtual void endGroup(); - virtual size_t getMaxTextureSize() const; virtual size_t getMaxViewportDims() const; }; diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp index 8ebafbced3..1fabaf5bee 100644 --- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp @@ -48,12 +48,6 @@ GLES20RenderEngine::GLES20RenderEngine() : glPixelStorei(GL_UNPACK_ALIGNMENT, 4); glPixelStorei(GL_PACK_ALIGNMENT, 4); - struct pack565 { - inline uint16_t operator() (int r, int g, int b) const { - return (r<<11)|(g<<5)|b; - } - } pack565; - const uint16_t protTexData[] = { 0 }; glGenTextures(1, &mProtectedTexName); glBindTexture(GL_TEXTURE_2D, mProtectedTexName); @@ -175,6 +169,12 @@ void GLES20RenderEngine::setupLayerBlackedOut() { mState.setTexture(texture); } +mat4 GLES20RenderEngine::setupColorTransform(const mat4& colorTransform) { + mat4 oldTransform = mState.getColorMatrix(); + mState.setColorMatrix(colorTransform); + return oldTransform; +} + void GLES20RenderEngine::disableTexturing() { mState.disableTexture(); } @@ -243,78 +243,6 @@ void GLES20RenderEngine::drawMesh(const Mesh& mesh) { } } -void GLES20RenderEngine::beginGroup(const mat4& colorTransform) { - - GLuint tname, name; - // create the texture - glGenTextures(1, &tname); - glBindTexture(GL_TEXTURE_2D, tname); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mVpWidth, mVpHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - - // create a Framebuffer Object to render into - glGenFramebuffers(1, &name); - glBindFramebuffer(GL_FRAMEBUFFER, name); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tname, 0); - - Group group; - group.texture = tname; - group.fbo = name; - group.width = mVpWidth; - group.height = mVpHeight; - group.colorTransform = colorTransform; - - mGroupStack.push(group); -} - -void GLES20RenderEngine::endGroup() { - - const Group group(mGroupStack.top()); - mGroupStack.pop(); - - // activate the previous render target - GLuint fbo = 0; - if (!mGroupStack.isEmpty()) { - fbo = mGroupStack.top().fbo; - } - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - - // set our state - Texture texture(Texture::TEXTURE_2D, group.texture); - texture.setDimensions(group.width, group.height); - glBindTexture(GL_TEXTURE_2D, group.texture); - - mState.setPlaneAlpha(1.0f); - mState.setPremultipliedAlpha(true); - mState.setOpaque(false); - mState.setTexture(texture); - mState.setColorMatrix(group.colorTransform); - glDisable(GL_BLEND); - - Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2, 2); - Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>()); - Mesh::VertexArray<vec2> texCoord(mesh.getTexCoordArray<vec2>()); - position[0] = vec2(0, 0); - position[1] = vec2(group.width, 0); - position[2] = vec2(group.width, group.height); - position[3] = vec2(0, group.height); - texCoord[0] = vec2(0, 0); - texCoord[1] = vec2(1, 0); - texCoord[2] = vec2(1, 1); - texCoord[3] = vec2(0, 1); - drawMesh(mesh); - - // reset color matrix - mState.setColorMatrix(mat4()); - - // free our fbo and texture - glDeleteFramebuffers(1, &group.fbo); - glDeleteTextures(1, &group.texture); -} - void GLES20RenderEngine::dump(String8& result) { RenderEngine::dump(result); } diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h index 3d6243e2e1..819356a62b 100644 --- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h @@ -72,14 +72,12 @@ protected: virtual void setupLayerTexturing(const Texture& texture); virtual void setupLayerBlackedOut(); virtual void setupFillWithColor(float r, float g, float b, float a); + virtual mat4 setupColorTransform(const mat4& colorTransform); virtual void disableTexturing(); virtual void disableBlending(); virtual void drawMesh(const Mesh& mesh); - virtual void beginGroup(const mat4& colorTransform); - virtual void endGroup(); - virtual size_t getMaxTextureSize() const; virtual size_t getMaxViewportDims() const; }; diff --git a/services/surfaceflinger/RenderEngine/Mesh.cpp b/services/surfaceflinger/RenderEngine/Mesh.cpp index 3f50cb0a96..ffd9be2a8a 100644 --- a/services/surfaceflinger/RenderEngine/Mesh.cpp +++ b/services/surfaceflinger/RenderEngine/Mesh.cpp @@ -16,14 +16,40 @@ #include "Mesh.h" +#include <utils/Log.h> + namespace android { Mesh::Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordSize) : mVertexCount(vertexCount), mVertexSize(vertexSize), mTexCoordsSize(texCoordSize), mPrimitive(primitive) { - mVertices = new float[(vertexSize + texCoordSize) * vertexCount]; - mStride = mVertexSize + mTexCoordsSize; + if (vertexCount == 0) { + mVertices = new float[1]; + mVertices[0] = 0.0f; + mStride = 0; + return; + } + + size_t stride = vertexSize + texCoordSize; + size_t remainder = (stride * vertexCount) / vertexCount; + // Since all of the input parameters are unsigned, if stride is less than + // either vertexSize or texCoordSize, it must have overflowed. remainder + // will be equal to stride as long as stride * vertexCount doesn't overflow. + if ((stride < vertexSize) || (remainder != stride)) { + ALOGE("Overflow in Mesh(..., %zu, %zu, %zu)", vertexCount, vertexSize, + texCoordSize); + mVertices = new float[1]; + mVertices[0] = 0.0f; + mVertexCount = 0; + mVertexSize = 0; + mTexCoordsSize = 0; + mStride = 0; + return; + } + + mVertices = new float[stride * vertexCount]; + mStride = stride; } Mesh::~Mesh() { diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp index 0de5cca293..ba11259ac2 100644 --- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp +++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp @@ -199,10 +199,8 @@ String8 ProgramCache::generateFragmentShader(const Key& needs) { // un-premultiply if needed before linearization fs << "gl_FragColor.rgb = gl_FragColor.rgb/gl_FragColor.a;"; } - fs << "gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(2.2));"; fs << "vec4 transformed = colorMatrix * vec4(gl_FragColor.rgb, 1);"; fs << "gl_FragColor.rgb = transformed.rgb/transformed.a;"; - fs << "gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(1.0 / 2.2));"; if (!needs.isOpaque() && needs.isPremultiplied()) { // and re-premultiply if needed after gamma correction fs << "gl_FragColor.rgb = gl_FragColor.rgb*gl_FragColor.a;"; diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp index a77e0e9d23..7cd42e4052 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp @@ -283,7 +283,6 @@ status_t RenderEngine::BindImageAsFramebuffer::getStatus() const { static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs, EGLint attribute, EGLint wanted, EGLConfig* outConfig) { - EGLConfig config = NULL; EGLint numConfigs = -1, n = 0; eglGetConfigs(dpy, NULL, 0, &numConfigs); EGLConfig* const configs = new EGLConfig[numConfigs]; diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h index 8d7529cb31..31a961efe3 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/RenderEngine.h @@ -99,18 +99,16 @@ public: virtual void setupLayerBlackedOut() = 0; virtual void setupFillWithColor(float r, float g, float b, float a) = 0; + virtual mat4 setupColorTransform(const mat4& /* colorTransform */) { + return mat4(); + } + virtual void disableTexturing() = 0; virtual void disableBlending() = 0; // drawing virtual void drawMesh(const Mesh& mesh) = 0; - // grouping - // creates a color-transform group, everything drawn in the group will be - // transformed by the given color transform when endGroup() is called. - virtual void beginGroup(const mat4& colorTransform) = 0; - virtual void endGroup() = 0; - // queries virtual size_t getMaxTextureSize() const = 0; virtual size_t getMaxViewportDims() const = 0; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 079b840be3..e4c917a372 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -145,10 +145,15 @@ SurfaceFlinger::SurfaceFlinger() mDebugInTransaction(0), mLastTransactionTime(0), mBootFinished(false), + mForceFullDamage(false), mPrimaryHWVsyncEnabled(false), mHWVsyncAvailable(false), mDaltonize(false), - mHasColorMatrix(false) + mHasColorMatrix(false), + mHasPoweredOff(false), + mFrameBuckets(), + mTotalTime(0), + mLastSwapTime(0) { ALOGI("SurfaceFlinger is starting"); @@ -319,17 +324,20 @@ public: DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync, const char* label) : mValue(0), - mPhaseOffset(phaseOffset), mTraceVsync(traceVsync), mVsyncOnLabel(String8::format("VsyncOn-%s", label)), mVsyncEventLabel(String8::format("VSYNC-%s", label)), - mDispSync(dispSync) {} + mDispSync(dispSync), + mCallbackMutex(), + mCallback(), + mVsyncMutex(), + mPhaseOffset(phaseOffset), + mEnabled(false) {} virtual ~DispSyncSource() {} virtual void setVSyncEnabled(bool enable) { - // Do NOT lock the mutex here so as to avoid any mutex ordering issues - // with locking it in the onDispSyncEvent callback. + Mutex::Autolock lock(mVsyncMutex); if (enable) { status_t err = mDispSync->addEventListener(mPhaseOffset, static_cast<DispSync::Callback*>(this)); @@ -347,18 +355,54 @@ public: } //ATRACE_INT(mVsyncOnLabel.string(), 0); } + mEnabled = enable; } virtual void setCallback(const sp<VSyncSource::Callback>& callback) { - Mutex::Autolock lock(mMutex); + Mutex::Autolock lock(mCallbackMutex); mCallback = callback; } + virtual void setPhaseOffset(nsecs_t phaseOffset) { + Mutex::Autolock lock(mVsyncMutex); + + // Normalize phaseOffset to [0, period) + auto period = mDispSync->getPeriod(); + phaseOffset %= period; + if (phaseOffset < 0) { + // If we're here, then phaseOffset is in (-period, 0). After this + // operation, it will be in (0, period) + phaseOffset += period; + } + mPhaseOffset = phaseOffset; + + // If we're not enabled, we don't need to mess with the listeners + if (!mEnabled) { + return; + } + + // Remove the listener with the old offset + status_t err = mDispSync->removeEventListener( + static_cast<DispSync::Callback*>(this)); + if (err != NO_ERROR) { + ALOGE("error unregistering vsync callback: %s (%d)", + strerror(-err), err); + } + + // Add a listener with the new offset + err = mDispSync->addEventListener(mPhaseOffset, + static_cast<DispSync::Callback*>(this)); + if (err != NO_ERROR) { + ALOGE("error registering vsync callback: %s (%d)", + strerror(-err), err); + } + } + private: virtual void onDispSyncEvent(nsecs_t when) { sp<VSyncSource::Callback> callback; { - Mutex::Autolock lock(mMutex); + Mutex::Autolock lock(mCallbackMutex); callback = mCallback; if (mTraceVsync) { @@ -374,21 +418,24 @@ private: int mValue; - const nsecs_t mPhaseOffset; const bool mTraceVsync; const String8 mVsyncOnLabel; const String8 mVsyncEventLabel; DispSync* mDispSync; + + Mutex mCallbackMutex; // Protects the following sp<VSyncSource::Callback> mCallback; - Mutex mMutex; + + Mutex mVsyncMutex; // Protects the following + nsecs_t mPhaseOffset; + bool mEnabled; }; void SurfaceFlinger::init() { ALOGI( "SurfaceFlinger's main thread ready to run. " "Initializing graphics H/W..."); - status_t err; Mutex::Autolock _l(mStateLock); // initialize EGL for the default display @@ -497,13 +544,13 @@ size_t SurfaceFlinger::getMaxViewportDims() const { bool SurfaceFlinger::authenticateSurfaceTexture( const sp<IGraphicBufferProducer>& bufferProducer) const { Mutex::Autolock _l(mStateLock); - sp<IBinder> surfaceTextureBinder(bufferProducer->asBinder()); + sp<IBinder> surfaceTextureBinder(IInterface::asBinder(bufferProducer)); return mGraphicBufferProducerList.indexOf(surfaceTextureBinder) >= 0; } status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display, Vector<DisplayInfo>* configs) { - if (configs == NULL) { + if ((configs == NULL) || (display.get() == NULL)) { return BAD_VALUE; } @@ -607,7 +654,7 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display, return NO_ERROR; } -status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>& display, +status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>& /* display */, DisplayStatInfo* stats) { if (stats == NULL) { return BAD_VALUE; @@ -621,7 +668,11 @@ status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>& display, } int SurfaceFlinger::getActiveConfig(const sp<IBinder>& display) { - return getDisplayDevice(display)->getActiveConfig(); + sp<DisplayDevice> device(getDisplayDevice(display)); + if (device != NULL) { + return device->getActiveConfig(); + } + return BAD_VALUE; } void SurfaceFlinger::setActiveConfigInternal(const sp<DisplayDevice>& hw, int mode) { @@ -950,8 +1001,8 @@ void SurfaceFlinger::postComposition() } } + const sp<const DisplayDevice> hw(getDefaultDisplayDevice()); if (kIgnorePresentFences) { - const sp<const DisplayDevice> hw(getDefaultDisplayDevice()); if (hw->isDisplayOn()) { enableHardwareVsync(); } @@ -970,6 +1021,26 @@ void SurfaceFlinger::postComposition() } mAnimFrameTracker.advanceFrame(); } + + if (hw->getPowerMode() == HWC_POWER_MODE_OFF) { + return; + } + + nsecs_t currentTime = systemTime(); + if (mHasPoweredOff) { + mHasPoweredOff = false; + } else { + nsecs_t period = mPrimaryDispSync.getPeriod(); + nsecs_t elapsedTime = currentTime - mLastSwapTime; + size_t numPeriods = static_cast<size_t>(elapsedTime / period); + if (numPeriods < NUM_BUCKETS - 1) { + mFrameBuckets[numPeriods] += elapsedTime; + } else { + mFrameBuckets[NUM_BUCKETS - 1] += elapsedTime; + } + mTotalTime += elapsedTime; + } + mLastSwapTime = currentTime; } void SurfaceFlinger::rebuildLayerStacks() { @@ -1288,7 +1359,9 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) // this display is in both lists. see if something changed. const DisplayDeviceState& state(curr[j]); const wp<IBinder>& display(curr.keyAt(j)); - if (state.surface->asBinder() != draw[i].surface->asBinder()) { + const sp<IBinder> state_binder = IInterface::asBinder(state.surface); + const sp<IBinder> draw_binder = IInterface::asBinder(draw[i].surface); + if (state_binder != draw_binder) { // changing the surface is like destroying and // recreating the DisplayDevice, so we just remove it // from the drawing state, so that it get re-added @@ -1720,12 +1793,17 @@ bool SurfaceFlinger::handlePageFlip() frameQueued = true; if (layer->shouldPresentNow(mPrimaryDispSync)) { layersWithQueuedFrames.push_back(layer.get()); + } else { + layer->useEmptyDamage(); } + } else { + layer->useEmptyDamage(); } } for (size_t i = 0, count = layersWithQueuedFrames.size() ; i<count ; i++) { Layer* layer = layersWithQueuedFrames[i]; const Region dirty(layer->latchBuffer(visibleRegions)); + layer->useSurfaceDamage(); const Layer::State& s(layer->getDrawingState()); invalidateLayerStack(s.layerStack, dirty); } @@ -1794,9 +1872,9 @@ void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& hw, if (mDaltonize) { colorMatrix = colorMatrix * mDaltonizer(); } - engine.beginGroup(colorMatrix); + mat4 oldMatrix = engine.setupColorTransform(colorMatrix); doComposeSurfaces(hw, dirtyRegion); - engine.endGroup(); + engine.setupColorTransform(oldMatrix); } // update the swap region and clear the dirty region @@ -1940,18 +2018,25 @@ void SurfaceFlinger::drawWormhole(const sp<const DisplayDevice>& hw, const Regio engine.fillRegionWithColor(region, height, 0, 0, 0, 0); } -void SurfaceFlinger::addClientLayer(const sp<Client>& client, +status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBinder>& handle, const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc) { + // add this layer to the current state list + { + Mutex::Autolock _l(mStateLock); + if (mCurrentState.layersSortedByZ.size() >= MAX_LAYERS) { + return NO_MEMORY; + } + mCurrentState.layersSortedByZ.add(lbc); + mGraphicBufferProducerList.add(IInterface::asBinder(gbc)); + } + // attach this layer to the client client->attachLayer(handle, lbc); - // add this layer to the current state list - Mutex::Autolock _l(mStateLock); - mCurrentState.layersSortedByZ.add(lbc); - mGraphicBufferProducerList.add(gbc->asBinder()); + return NO_ERROR; } status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer) { @@ -2024,7 +2109,7 @@ void SurfaceFlinger::setTransactionState( // NOTE: it would be better to use RTTI as we could directly check // that we have a Client*. however, RTTI is disabled in Android. if (s.client != NULL) { - sp<IBinder> binder = s.client->asBinder(); + sp<IBinder> binder = IInterface::asBinder(s.client); if (binder != NULL) { if (binder->queryLocalInterface(ISurfaceComposerClient::descriptor) != NULL) { sp<Client> client( static_cast<Client *>(s.client.get()) ); @@ -2070,7 +2155,7 @@ uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s) if (disp.isValid()) { const uint32_t what = s.what; if (what & DisplayState::eSurfaceChanged) { - if (disp.surface->asBinder() != s.surface->asBinder()) { + if (IInterface::asBinder(disp.surface) != IInterface::asBinder(s.surface)) { disp.surface = s.surface; flags |= eDisplayTransactionNeeded; } @@ -2149,9 +2234,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( if (layer->setTransparentRegionHint(s.transparentRegion)) flags |= eTraversalNeeded; } - if ((what & layer_state_t::eVisibilityChanged) || - (what & layer_state_t::eOpacityChanged)) { - // TODO: should we just use an eFlagsChanged for this? + if (what & layer_state_t::eFlagsChanged) { if (layer->setFlags(s.flags, s.mask)) flags |= eTraversalNeeded; } @@ -2207,10 +2290,16 @@ status_t SurfaceFlinger::createLayer( break; } - if (result == NO_ERROR) { - addClientLayer(client, *handle, *gbp, layer); - setTransactionFlags(eTransactionNeeded); + if (result != NO_ERROR) { + return result; + } + + result = addClientLayer(client, *handle, *gbp, layer); + if (result != NO_ERROR) { + return result; } + + setTransactionFlags(eTransactionNeeded); return result; } @@ -2343,6 +2432,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw, } mVisibleRegionsDirty = true; + mHasPoweredOff = true; repaintEverything(); } else if (mode == HWC_POWER_MODE_OFF) { if (type == DisplayDevice::DISPLAY_PRIMARY) { @@ -2401,18 +2491,15 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) result.appendFormat("Permission Denial: " "can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid); } else { - // Try to get the main lock, but don't insist if we can't + // Try to get the main lock, but give up after one second // (this would indicate SF is stuck, but we want to be able to // print something in dumpsys). - int retry = 3; - while (mStateLock.tryLock()<0 && --retry>=0) { - usleep(1000000); - } - const bool locked(retry >= 0); + status_t err = mStateLock.timedLock(s2ns(1)); + bool locked = (err == NO_ERROR); if (!locked) { - result.append( - "SurfaceFlinger appears to be unresponsive, " - "dumping anyways (no locks held)\n"); + result.appendFormat( + "SurfaceFlinger appears to be unresponsive (%s [%d]), " + "dumping anyways (no locks held)\n", strerror(-err), err); } bool dumpAll = true; @@ -2446,6 +2533,13 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) mPrimaryDispSync.dump(result); dumpAll = false; } + + if ((index < numArgs) && + (args[index] == String16("--static-screen"))) { + index++; + dumpStaticScreenStats(result); + dumpAll = false; + } } if (dumpAll) { @@ -2549,6 +2643,23 @@ void SurfaceFlinger::logFrameStats() { result.append(config); } +void SurfaceFlinger::dumpStaticScreenStats(String8& result) const +{ + result.appendFormat("Static screen stats:\n"); + for (size_t b = 0; b < NUM_BUCKETS - 1; ++b) { + float bucketTimeSec = mFrameBuckets[b] / 1e9; + float percent = 100.0f * + static_cast<float>(mFrameBuckets[b]) / mTotalTime; + result.appendFormat(" < %zd frames: %.3f s (%.1f%%)\n", + b + 1, bucketTimeSec, percent); + } + float bucketTimeSec = mFrameBuckets[NUM_BUCKETS - 1] / 1e9; + float percent = 100.0f * + static_cast<float>(mFrameBuckets[NUM_BUCKETS - 1]) / mTotalTime; + result.appendFormat(" %zd+ frames: %.3f s (%.1f%%)\n", + NUM_BUCKETS - 1, bucketTimeSec, percent); +} + void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index, String8& result) const { @@ -2595,6 +2706,11 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index, mHwc->getRefreshPeriod(HWC_DISPLAY_PRIMARY)); result.append("\n"); + // Dump static screen stats + result.append("\n"); + dumpStaticScreenStats(result); + result.append("\n"); + /* * Dump the visible layer list */ @@ -2742,7 +2858,7 @@ status_t SurfaceFlinger::onTransact( IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); - if ((uid != AID_GRAPHICS) && + if ((uid != AID_GRAPHICS && uid != AID_SYSTEM) && !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) { ALOGE("Permission Denial: " "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid); @@ -2873,6 +2989,21 @@ status_t SurfaceFlinger::onTransact( mPrimaryDispSync.setRefreshSkipCount(n); return NO_ERROR; } + case 1017: { + n = data.readInt32(); + mForceFullDamage = static_cast<bool>(n); + return NO_ERROR; + } + case 1018: { // Modify Choreographer's phase offset + n = data.readInt32(); + mEventThread->setPhaseOffset(static_cast<nsecs_t>(n)); + return NO_ERROR; + } + case 1019: { // Modify SurfaceFlinger's phase offset + n = data.readInt32(); + mSFEventThread->setPhaseOffset(static_cast<nsecs_t>(n)); + return NO_ERROR; + } } } return err; @@ -2961,7 +3092,7 @@ class GraphicProducerWrapper : public BBinder, public MessageHandler { // Prevent reads below from happening before the read from Message atomic_thread_fence(memory_order_acquire); if (what == MSG_API_CALL) { - result = impl->asBinder()->transact(code, data[0], reply); + result = IInterface::asBinder(impl)->transact(code, data[0], reply); barrier.open(); } else if (what == MSG_EXIT) { exitRequested = true; @@ -3011,7 +3142,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, // if we have secure windows on this display, never allow the screen capture // unless the producer interface is local (i.e.: we can take a screenshot for // ourselves). - if (!producer->asBinder()->localBinder()) { + if (!IInterface::asBinder(producer)->localBinder()) { Mutex::Autolock _l(mStateLock); sp<const DisplayDevice> hw(getDisplayDevice(display)); if (hw->getSecureLayerVisible()) { @@ -3075,7 +3206,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, result = flinger->captureScreenImplLocked(hw, producer, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform, rotation); - static_cast<GraphicProducerWrapper*>(producer->asBinder().get())->exit(result); + static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result); return true; } }; @@ -3117,9 +3248,10 @@ void SurfaceFlinger::renderScreenImplLocked( RenderEngine& engine(getRenderEngine()); // get screen geometry - const uint32_t hw_w = hw->getWidth(); - const uint32_t hw_h = hw->getHeight(); - const bool filtering = reqWidth != hw_w || reqWidth != hw_h; + const int32_t hw_w = hw->getWidth(); + const int32_t hw_h = hw->getHeight(); + const bool filtering = static_cast<int32_t>(reqWidth) != hw_w || + static_cast<int32_t>(reqHeight) != hw_h; // if a default or invalid sourceCrop is passed in, set reasonable values if (sourceCrop.width() == 0 || sourceCrop.height() == 0 || @@ -3132,13 +3264,13 @@ void SurfaceFlinger::renderScreenImplLocked( if (sourceCrop.left < 0) { ALOGE("Invalid crop rect: l = %d (< 0)", sourceCrop.left); } - if (static_cast<uint32_t>(sourceCrop.right) > hw_w) { + if (sourceCrop.right > hw_w) { ALOGE("Invalid crop rect: r = %d (> %d)", sourceCrop.right, hw_w); } if (sourceCrop.top < 0) { ALOGE("Invalid crop rect: t = %d (< 0)", sourceCrop.top); } - if (static_cast<uint32_t>(sourceCrop.bottom) > hw_h) { + if (sourceCrop.bottom > hw_h) { ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, hw_h); } @@ -3185,8 +3317,12 @@ status_t SurfaceFlinger::captureScreenImplLocked( ATRACE_CALL(); // get screen geometry - const uint32_t hw_w = hw->getWidth(); - const uint32_t hw_h = hw->getHeight(); + uint32_t hw_w = hw->getWidth(); + uint32_t hw_h = hw->getHeight(); + + if (rotation & Transform::ROT_90) { + std::swap(hw_w, hw_h); + } if ((reqWidth > hw_w) || (reqHeight > hw_h)) { ALOGE("size mismatch (%d, %d) > (%d, %d)", @@ -3202,8 +3338,8 @@ status_t SurfaceFlinger::captureScreenImplLocked( sp<Surface> sur = new Surface(producer, false); ANativeWindow* window = sur.get(); - status_t result = NO_ERROR; - if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) == NO_ERROR) { + status_t result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL); + if (result == NO_ERROR) { uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; @@ -3293,7 +3429,7 @@ status_t SurfaceFlinger::captureScreenImplLocked( result = BAD_VALUE; } // queueBuffer takes ownership of syncFd - window->queueBuffer(window, buffer, syncFd); + result = window->queueBuffer(window, buffer, syncFd); } } else { result = BAD_VALUE; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 4deb815521..3759a92400 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -144,6 +144,8 @@ private: // every half hour. enum { LOG_FRAME_STATS_PERIOD = 30*60*60 }; + static const size_t MAX_LAYERS = 4096; + // We're reference counted, never destroy SurfaceFlinger directly virtual ~SurfaceFlinger(); @@ -305,7 +307,7 @@ private: status_t removeLayer(const sp<Layer>& layer); // add a layer to SurfaceFlinger - void addClientLayer(const sp<Client>& client, + status_t addClientLayer(const sp<Client>& client, const sp<IBinder>& handle, const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc); @@ -416,6 +418,8 @@ private: void logFrameStats(); + void dumpStaticScreenStats(String8& result) const; + /* ------------------------------------------------------------------------ * Attributes */ @@ -469,6 +473,7 @@ private: volatile nsecs_t mDebugInTransaction; nsecs_t mLastTransactionTime; bool mBootFinished; + bool mForceFullDamage; // these are thread safe mutable MessageQueue mEventQueue; @@ -493,6 +498,13 @@ private: mat4 mColorMatrix; bool mHasColorMatrix; + + // Static screen stats + bool mHasPoweredOff; + static const size_t NUM_BUCKETS = 8; // < 1-7, 7+ + nsecs_t mFrameBuckets[NUM_BUCKETS]; + nsecs_t mTotalTime; + nsecs_t mLastSwapTime; }; }; // namespace android diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp index 7de6ac428a..ed1f31b554 100644 --- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp +++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp @@ -21,6 +21,8 @@ #include <private/gui/SyncFeatures.h> +#include <gui/BufferItem.h> + #include <utils/Errors.h> #include <utils/NativeHandle.h> #include <utils/Trace.h> @@ -30,7 +32,7 @@ namespace android { // --------------------------------------------------------------------------- status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter, - const DispSync& dispSync) + const DispSync& dispSync, uint64_t maxFrameNumber) { ATRACE_CALL(); ALOGV("updateTexImage"); @@ -47,12 +49,13 @@ status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter, return err; } - BufferQueue::BufferItem item; + BufferItem item; // Acquire the next buffer. // In asynchronous mode the list is guaranteed to be one buffer // deep, while in synchronous mode we use the oldest buffer. - err = acquireBufferLocked(&item, computeExpectedPresent(dispSync)); + err = acquireBufferLocked(&item, computeExpectedPresent(dispSync), + maxFrameNumber); if (err != NO_ERROR) { if (err == BufferQueue::NO_BUFFER_AVAILABLE) { err = NO_ERROR; @@ -72,7 +75,7 @@ status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter, int buf = item.mBuf; if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) { releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, EGL_NO_SYNC_KHR); - return NO_ERROR; + return BUFFER_REJECTED; } // Release the previous buffer. @@ -101,11 +104,13 @@ status_t SurfaceFlingerConsumer::bindTextureImage() return bindTextureImageLocked(); } -status_t SurfaceFlingerConsumer::acquireBufferLocked( - BufferQueue::BufferItem *item, nsecs_t presentWhen) { - status_t result = GLConsumer::acquireBufferLocked(item, presentWhen); +status_t SurfaceFlingerConsumer::acquireBufferLocked(BufferItem* item, + nsecs_t presentWhen, uint64_t maxFrameNumber) { + status_t result = GLConsumer::acquireBufferLocked(item, presentWhen, + maxFrameNumber); if (result == NO_ERROR) { mTransformToDisplayInverse = item->mTransformToDisplayInverse; + mSurfaceDamage = item->mSurfaceDamage; } return result; } @@ -114,6 +119,10 @@ bool SurfaceFlingerConsumer::getTransformToDisplayInverse() const { return mTransformToDisplayInverse; } +const Region& SurfaceFlingerConsumer::getSurfaceDamage() const { + return mSurfaceDamage; +} + sp<NativeHandle> SurfaceFlingerConsumer::getSidebandStream() const { return mConsumer->getSidebandStream(); } diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h index 28f2f6aeb5..779e5b77b2 100644 --- a/services/surfaceflinger/SurfaceFlingerConsumer.h +++ b/services/surfaceflinger/SurfaceFlingerConsumer.h @@ -28,6 +28,8 @@ namespace android { */ class SurfaceFlingerConsumer : public GLConsumer { public: + static const status_t BUFFER_REJECTED = UNKNOWN_ERROR + 8; + struct ContentsChangedListener: public FrameAvailableListener { virtual void onSidebandStreamChanged() = 0; }; @@ -35,31 +37,34 @@ public: SurfaceFlingerConsumer(const sp<IGraphicBufferConsumer>& consumer, uint32_t tex) : GLConsumer(consumer, tex, GLConsumer::TEXTURE_EXTERNAL, false, false), - mTransformToDisplayInverse(false) + mTransformToDisplayInverse(false), mSurfaceDamage() {} class BufferRejecter { friend class SurfaceFlingerConsumer; virtual bool reject(const sp<GraphicBuffer>& buf, - const IGraphicBufferConsumer::BufferItem& item) = 0; + const BufferItem& item) = 0; protected: virtual ~BufferRejecter() { } }; - virtual status_t acquireBufferLocked(BufferQueue::BufferItem *item, nsecs_t presentWhen); + virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen, + uint64_t maxFrameNumber = 0) override; // This version of updateTexImage() takes a functor that may be used to // reject the newly acquired buffer. Unlike the GLConsumer version, // this does not guarantee that the buffer has been bound to the GL // texture. - status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync); + status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync, + uint64_t maxFrameNumber = 0); // See GLConsumer::bindTextureImageLocked(). status_t bindTextureImage(); // must be called from SF main thread bool getTransformToDisplayInverse() const; + const Region& getSurfaceDamage() const; // Sets the contents changed listener. This should be used instead of // ConsumerBase::setFrameAvailableListener(). @@ -78,6 +83,9 @@ private: // it is displayed onto. This is applied after GLConsumer::mCurrentTransform. // This must be set/read from SurfaceFlinger's main thread. bool mTransformToDisplayInverse; + + // The portion of this surface that has changed since the previous frame + Region mSurfaceDamage; }; // ---------------------------------------------------------------------------- diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp index 90e3f7de9e..a74bc4cd91 100644 --- a/services/surfaceflinger/main_surfaceflinger.cpp +++ b/services/surfaceflinger/main_surfaceflinger.cpp @@ -14,9 +14,7 @@ * limitations under the License. */ -#if defined(HAVE_PTHREADS) #include <sys/resource.h> -#endif #include <cutils/sched_policy.h> #include <binder/IServiceManager.h> @@ -39,9 +37,8 @@ int main(int, char**) { // instantiate surfaceflinger sp<SurfaceFlinger> flinger = new SurfaceFlinger(); -#if defined(HAVE_PTHREADS) setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY); -#endif + set_sched_policy(0, SP_FOREGROUND); // initialize before clients can connect diff --git a/services/surfaceflinger/tests/Android.mk b/services/surfaceflinger/tests/Android.mk index e2108602ee..979062e3c8 100644 --- a/services/surfaceflinger/tests/Android.mk +++ b/services/surfaceflinger/tests/Android.mk @@ -1,6 +1,7 @@ # Build the unit tests, LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE := SurfaceFlinger_test @@ -15,16 +16,9 @@ LOCAL_SHARED_LIBRARIES := \ libbinder \ libcutils \ libgui \ - libstlport \ libui \ libutils \ -LOCAL_C_INCLUDES := \ - bionic \ - bionic/libstdc++/include \ - external/gtest/include \ - external/stlport/stlport \ - # Build the binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE) # to integrate with auto-test framework. include $(BUILD_NATIVE_TEST) diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index 4d363c8a00..dcde512017 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -16,6 +16,8 @@ #include <gtest/gtest.h> +#include <android/native_window.h> + #include <binder/IMemory.h> #include <gui/ISurfaceComposer.h> @@ -53,21 +55,23 @@ static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, class ScreenCapture : public RefBase { public: static void captureScreen(sp<ScreenCapture>* sc) { - sp<IMemoryHeap> heap; - uint32_t w=0, h=0; - PixelFormat fmt=0; + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + IGraphicBufferProducer::QueueBufferOutput bufferOutput; + sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1); sp<ISurfaceComposer> sf(ComposerService::getComposerService()); - sp<IBinder> display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); - ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &heap, &w, &h, &fmt, 0, 0, - 0, INT_MAX)); - ASSERT_TRUE(heap != NULL); - ASSERT_EQ(PIXEL_FORMAT_RGBA_8888, fmt); - *sc = new ScreenCapture(w, h, heap); + sp<IBinder> display(sf->getBuiltInDisplay( + ISurfaceComposer::eDisplayIdMain)); + ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(), 0, 0, + 0, INT_MAX, false)); + *sc = new ScreenCapture(cpuConsumer); } void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) { - const uint8_t* img = reinterpret_cast<const uint8_t*>(mHeap->base()); - const uint8_t* pixel = img + (4 * (y*mWidth + x)); + ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mBuf.format); + const uint8_t* img = static_cast<const uint8_t*>(mBuf.data); + const uint8_t* pixel = img + (4 * (y * mBuf.stride + x)); if (r != pixel[0] || g != pixel[1] || b != pixel[2]) { String8 err(String8::format("pixel @ (%3d, %3d): " "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]", @@ -77,15 +81,17 @@ public: } private: - ScreenCapture(uint32_t w, uint32_t h, const sp<IMemoryHeap>& heap) : - mWidth(w), - mHeight(h), - mHeap(heap) - {} - - const uint32_t mWidth; - const uint32_t mHeight; - sp<IMemoryHeap> mHeap; + ScreenCapture(const sp<CpuConsumer>& cc) : + mCC(cc) { + EXPECT_EQ(NO_ERROR, mCC->lockNextBuffer(&mBuf)); + } + + ~ScreenCapture() { + mCC->unlockBuffer(mBuf); + } + + sp<CpuConsumer> mCC; + CpuConsumer::LockedBuffer mBuf; }; class LayerUpdateTest : public ::testing::Test { diff --git a/services/surfaceflinger/tests/vsync/vsync.cpp b/services/surfaceflinger/tests/vsync/vsync.cpp index b0d54c4e0b..aa72c79248 100644 --- a/services/surfaceflinger/tests/vsync/vsync.cpp +++ b/services/surfaceflinger/tests/vsync/vsync.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include <android/looper.h> #include <gui/DisplayEventReceiver.h> #include <utils/Looper.h> diff --git a/services/surfaceflinger/tests/waitforvsync/waitforvsync.cpp b/services/surfaceflinger/tests/waitforvsync/waitforvsync.cpp index 279b88b059..b88b04a897 100644 --- a/services/surfaceflinger/tests/waitforvsync/waitforvsync.cpp +++ b/services/surfaceflinger/tests/waitforvsync/waitforvsync.cpp @@ -23,6 +23,7 @@ #include <errno.h> #include <string.h> #include <stdio.h> +#include <unistd.h> #ifndef FBIO_WAITFORVSYNC #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) |