Merge "Delete the entire profile directory when the app is uninstalled" into nyc-dev
diff --git a/cmds/dumpstate/bugreport-format.md b/cmds/dumpstate/bugreport-format.md
index fc43250..484f97f 100644
--- a/cmds/dumpstate/bugreport-format.md
+++ b/cmds/dumpstate/bugreport-format.md
@@ -41,6 +41,8 @@
under the `FS` folder. For example, a `/dirA/dirB/fileC` file in the device
would generate a `FS/dirA/dirB/fileC` entry in the zip file.
+When systrace is enabled, the zip file will contain a `systrace.txt` file as well.
+
The flat file also has some minor changes:
- Tombstone files were removed and added to the zip file.
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index f0fb856..b391d76 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -27,7 +27,6 @@
#include <stdlib.h>
#include <string>
#include <string.h>
-#include <sys/capability.h>
#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/stat.h>
@@ -63,6 +62,7 @@
static std::set<std::string> mount_points;
void add_mountinfo();
static bool add_zip_entry(const std::string& entry_name, const std::string& entry_path);
+static bool add_zip_entry_from_fd(const std::string& entry_name, int fd);
#define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
@@ -90,7 +90,7 @@
* See bugreport-format.txt for more info.
*/
// TODO: change to "v1" before final N build
-static std::string VERSION_DEFAULT = "v1-dev2";
+static std::string VERSION_DEFAULT = "v1-dev3";
/* gets the tombstone data, according to the bugreport type: if zipped gets all tombstones,
* otherwise gets just those modified in the last half an hour. */
@@ -168,6 +168,42 @@
closedir(d);
}
+static void dump_systrace() {
+ if (!zip_writer) {
+ MYLOGD("Not dumping systrace because zip_writer is not set\n");
+ return;
+ }
+ const char* path = "/sys/kernel/debug/tracing/tracing_on";
+ long int is_tracing;
+ if (read_file_as_long(path, &is_tracing)) {
+ return; // error already logged
+ }
+ if (is_tracing <= 0) {
+ MYLOGD("Skipping systrace because '%s' content is '%ld'\n", path, is_tracing);
+ return;
+ }
+
+ DurationReporter duration_reporter("SYSTRACE", nullptr);
+ // systrace output can be many MBs, so we need to redirect its stdout straight to the zip file
+ // by forking and using a pipe.
+ int pipefd[2];
+ pipe(pipefd);
+ if (fork() == 0) {
+ close(pipefd[0]); // close reading end in the child
+ dup2(pipefd[1], STDOUT_FILENO); // send stdout to the pipe
+ dup2(pipefd[1], STDERR_FILENO); // send stderr to the pipe
+ close(pipefd[1]); // this descriptor is no longer needed
+
+ // TODO: ideally it should use run_command, but it doesn't work well with pipes.
+ // The drawback of calling execl directly is that we're not timing out if it hangs.
+ MYLOGD("Running '/system/bin/atrace --async_dump', which can take several seconds");
+ execl("/system/bin/atrace", "/system/bin/atrace", "--async_dump", nullptr);
+ } else {
+ close(pipefd[1]); // close the write end of the pipe in the parent
+ add_zip_entry_from_fd("systrace.txt", pipefd[0]); // write output to zip file
+ }
+}
+
static bool skip_not_stat(const char *path) {
static const char stat[] = "/stat";
size_t len = strlen(path);
@@ -845,10 +881,7 @@
printf("== Android Framework Services\n");
printf("========================================================\n");
- /* the full dumpsys is starting to take a long time, so we need
- to increase its timeout. we really need to do the timeouts in
- dumpsys itself... */
- run_command("DUMPSYS", 60, "dumpsys", "--skip", "meminfo,cpuinfo", NULL);
+ run_command("DUMPSYS", 60, "dumpsys", "-t", "60", "--skip", "meminfo,cpuinfo", NULL);
printf("========================================================\n");
printf("== Checkins\n");
@@ -967,49 +1000,6 @@
return std::string(hash_buffer);
}
-/* switch to non-root user and group */
-bool drop_root() {
- /* ensure we will keep capabilities when we drop root */
- if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
- MYLOGE("prctl(PR_SET_KEEPCAPS) failed: %s\n", strerror(errno));
- return false;
- }
-
- gid_t groups[] = { AID_LOG, AID_SDCARD_R, AID_SDCARD_RW,
- AID_MOUNT, AID_INET, AID_NET_BW_STATS, AID_READPROC };
- if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
- MYLOGE("Unable to setgroups, aborting: %s\n", strerror(errno));
- return false;
- }
- if (setgid(AID_SHELL) != 0) {
- MYLOGE("Unable to setgid, aborting: %s\n", strerror(errno));
- return false;
- }
- if (setuid(AID_SHELL) != 0) {
- MYLOGE("Unable to setuid, aborting: %s\n", strerror(errno));
- return false;
- }
-
- 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_SYSLOG)].permitted = CAP_TO_MASK(CAP_SYSLOG);
- capdata[CAP_TO_INDEX(CAP_SYSLOG)].effective = CAP_TO_MASK(CAP_SYSLOG);
- capdata[0].inheritable = 0;
- capdata[1].inheritable = 0;
-
- if (capset(&capheader, &capdata[0]) < 0) {
- MYLOGE("capset failed: %s\n", strerror(errno));
- return false;
- }
-
- return true;
-}
-
int main(int argc, char *argv[]) {
struct sigaction sigact;
int do_add_date = 0;
@@ -1058,7 +1048,9 @@
}
/* parse arguments */
- log_args("Dumpstate command line", argc, const_cast<const char **>(argv));
+ std::string args;
+ format_args(argc, const_cast<const char **>(argv), &args);
+ MYLOGD("Dumpstate command line: %s\n", args.c_str());
int c;
while ((c = getopt(argc, argv, "dho:svqzpPBRV:")) != -1) {
switch (c) {
@@ -1250,10 +1242,13 @@
// duration is logged into MYLOG instead.
print_header(version);
+ // Dumps systrace right away, otherwise it will be filled with unnecessary events.
+ dump_systrace();
+
// Invoking the following dumpsys calls before dump_traces() to try and
// keep the system stats as close to its initial state as possible.
- run_command("DUMPSYS MEMINFO", 30, SU_PATH, "shell", "dumpsys", "meminfo", "-a", NULL);
- run_command("DUMPSYS CPUINFO", 30, SU_PATH, "shell", "dumpsys", "cpuinfo", "-a", NULL);
+ run_command_as_shell("DUMPSYS MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "-a", NULL);
+ run_command_as_shell("DUMPSYS CPUINFO", 10, "dumpsys", "cpuinfo", "-a", NULL);
/* collect stack traces from Dalvik and native processes (needs root) */
dump_traces_path = dump_traces();
@@ -1263,7 +1258,7 @@
add_dir(RECOVERY_DIR, true);
add_mountinfo();
- if (!drop_root()) {
+ if (!drop_root_user()) {
return -1;
}
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 9c975d2..02d1256 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -85,6 +85,9 @@
/* prints the contents of a file */
int dump_file(const char *title, const char *path);
+/* saves the the contents of a file as a long */
+int read_file_as_long(const char *path, long int *output);
+
/* prints the contents of the fd
* fd must have been opened with the flag O_NONBLOCK.
*/
@@ -100,13 +103,20 @@
bool (*skip)(const char *path),
int (*dump_from_fd)(const char *title, const char *path, int fd));
+// TODO: need to refactor all those run_command variations; there shold be just one, receiving an
+// optional CommandOptions objects with values such as run_always, drop_root, etc...
+
/* forks a command and waits for it to finish -- terminate args with NULL */
+int run_command_as_shell(const char *title, int timeout_seconds, const char *command, ...);
int run_command(const char *title, int timeout_seconds, const char *command, ...);
/* forks a command and waits for it to finish
first element of args is the command, and last must be NULL.
command is always ran, even when _DUMPSTATE_DRY_RUN_ is defined. */
-int run_command_always(const char *title, int timeout_seconds, const char *args[]);
+int run_command_always(const char *title, bool drop_root, int timeout_seconds, const char *args[]);
+
+/* switch to non-root user and group */
+bool drop_root_user();
/* sends a broadcast using Activity Manager */
void send_broadcast(const std::string& action, const std::vector<std::string>& args);
@@ -171,8 +181,8 @@
/* dump eMMC Extended CSD data */
void dump_emmc_ecsd(const char *ext_csd_path);
-/** logs command-line arguments */
-void log_args(const std::string& message, int argc, const char *argv[]);
+/** gets command-line arguments */
+void format_args(int argc, const char *argv[], std::string *args);
/*
* Helper class used to report how long it takes for a section to finish.
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 884f250..89c9653 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -25,6 +25,7 @@
#include <stdlib.h>
#include <string>
#include <string.h>
+#include <sys/capability.h>
#include <sys/inotify.h>
#include <sys/stat.h>
#include <sys/sysconf.h>
@@ -394,7 +395,7 @@
sprintf(title, "SHOW MAP %d (%s)", pid, name);
sprintf(arg, "%d", pid);
- run_command(title, 10, SU_PATH, "root", "showmap", arg, NULL);
+ run_command(title, 10, SU_PATH, "root", "showmap", "-q", arg, NULL);
}
static int _dump_file_from_fd(const char *title, const char *path, int fd) {
@@ -474,6 +475,27 @@
return _dump_file_from_fd(title, path, fd);
}
+int read_file_as_long(const char *path, long int *output) {
+ int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
+ if (fd < 0) {
+ int err = errno;
+ MYLOGE("Error opening file descriptor for %s: %s\n", path, strerror(err));
+ return -1;
+ }
+ char buffer[50];
+ ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
+ if (bytes_read == -1) {
+ MYLOGE("Error reading file %s: %s\n", path, strerror(errno));
+ return -2;
+ }
+ if (bytes_read == 0) {
+ MYLOGE("File %s is empty\n", path);
+ return -3;
+ }
+ *output = atoi(buffer);
+ return 0;
+}
+
/* 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
@@ -607,6 +629,9 @@
return true;
}
+// TODO: refactor all those commands that convert args
+void format_args(const char* command, const char *args[], std::string *string);
+
int run_command(const char *title, int timeout_seconds, const char *command, ...) {
DurationReporter duration_reporter(title);
fflush(stdout);
@@ -616,23 +641,69 @@
va_list ap;
va_start(ap, command);
if (title) printf("------ %s (%s", title, command);
+ bool null_terminated = false;
for (arg = 1; arg < sizeof(args) / sizeof(args[0]); ++arg) {
args[arg] = va_arg(ap, const char *);
- if (args[arg] == NULL) break;
+ if (args[arg] == nullptr) {
+ null_terminated = true;
+ break;
+ }
if (title) printf(" %s", args[arg]);
}
if (title) printf(") ------\n");
fflush(stdout);
+ if (!null_terminated) {
+ // Fail now, otherwise execvp() call on run_command_always() might hang.
+ std::string cmd;
+ format_args(command, args, &cmd);
+ MYLOGE("skipping command %s because its args were not NULL-terminated", cmd.c_str());
+ return -1;
+ }
ON_DRY_RUN({ update_progress(timeout_seconds); va_end(ap); return 0; });
- int status = run_command_always(title, timeout_seconds, args);
+ int status = run_command_always(title, false, timeout_seconds, args);
+ va_end(ap);
+ return status;
+}
+
+int run_command_as_shell(const char *title, int timeout_seconds, const char *command, ...) {
+ DurationReporter duration_reporter(title);
+ fflush(stdout);
+
+ const char *args[1024] = {command};
+ size_t arg;
+ va_list ap;
+ va_start(ap, command);
+ if (title) printf("------ %s (%s", title, command);
+ bool null_terminated = false;
+ for (arg = 1; arg < sizeof(args) / sizeof(args[0]); ++arg) {
+ args[arg] = va_arg(ap, const char *);
+ if (args[arg] == nullptr) {
+ null_terminated = true;
+ break;
+ }
+ if (title) printf(" %s", args[arg]);
+ }
+ if (title) printf(") ------\n");
+ fflush(stdout);
+ if (!null_terminated) {
+ // Fail now, otherwise execvp() call on run_command_always() might hang.
+ std::string cmd;
+ format_args(command, args, &cmd);
+ MYLOGE("skipping command %s because its args were not NULL-terminated", cmd.c_str());
+ return -1;
+ }
+
+ ON_DRY_RUN({ update_progress(timeout_seconds); va_end(ap); return 0; });
+
+ int status = run_command_always(title, true, timeout_seconds, args);
va_end(ap);
return status;
}
/* forks a command and waits for it to finish */
-int run_command_always(const char *title, int timeout_seconds, const char *args[]) {
+int run_command_always(const char *title, bool drop_root, int timeout_seconds, const char *args[]) {
/* TODO: for now we're simplifying the progress calculation by using the timeout as the weight.
* It's a good approximation for most cases, except when calling dumpsys, where its weight
* should be much higher proportionally to its timeout. */
@@ -650,6 +721,10 @@
/* handle child case */
if (pid == 0) {
+ if (drop_root && !drop_root_user()) {
+ printf("*** could not drop root before running %s: %s\n", command, strerror(errno));
+ _exit(-1);
+ }
/* make sure the child dies when dumpstate dies */
prctl(PR_SET_PDEATHSIG, SIGKILL);
@@ -661,31 +736,42 @@
sigaction(SIGPIPE, &sigact, NULL);
execvp(command, (char**) args);
- printf("*** exec(%s): %s\n", command, strerror(errno));
- fflush(stdout);
- _exit(-1);
+ // execvp's result will be handled after waitpid_with_timeout() below...
}
/* handle parent case */
int status;
bool ret = waitpid_with_timeout(pid, timeout_seconds, &status);
uint64_t elapsed = DurationReporter::nanotime() - start;
+ std::string cmd; // used to log command and its args
if (!ret) {
if (errno == ETIMEDOUT) {
- printf("*** %s: Timed out after %.3fs (killing pid %d)\n", command,
+ format_args(command, args, &cmd);
+ printf("*** command '%s' timed out after %.3fs (killing pid %d)\n", cmd.c_str(),
+ (float) elapsed / NANOS_PER_SEC, pid);
+ MYLOGE("command '%s' timed out after %.3fs (killing pid %d)\n", cmd.c_str(),
(float) elapsed / NANOS_PER_SEC, pid);
} else {
- printf("*** %s: Error after %.4fs (killing pid %d)\n", command,
+ format_args(command, args, &cmd);
+ printf("*** command '%s': Error after %.4fs (killing pid %d)\n", cmd.c_str(),
+ (float) elapsed / NANOS_PER_SEC, pid);
+ MYLOGE("command '%s': Error after %.4fs (killing pid %d)\n", cmd.c_str(),
(float) elapsed / NANOS_PER_SEC, pid);
}
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);
+ printf("couldn not kill command '%s' (pid %d) even with SIGKILL.\n", command, pid);
+ MYLOGE("couldn not kill command '%s' (pid %d) even with SIGKILL.\n", command, pid);
}
}
return -1;
+ } else if (status) {
+ format_args(command, args, &cmd);
+ printf("*** command '%s' failed: %s\n", cmd.c_str(), strerror(errno));
+ MYLOGE("command '%s' failed: %s\n", cmd.c_str(), strerror(errno));
+ return -2;
}
if (WIFSIGNALED(status)) {
@@ -700,21 +786,69 @@
return status;
}
+bool drop_root_user() {
+ if (getgid() == AID_SHELL && getuid() == AID_SHELL) {
+ MYLOGD("drop_root_user(): already running as Shell");
+ return true;
+ }
+ /* ensure we will keep capabilities when we drop root */
+ if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
+ MYLOGE("prctl(PR_SET_KEEPCAPS) failed: %s\n", strerror(errno));
+ return false;
+ }
+
+ gid_t groups[] = { AID_LOG, AID_SDCARD_R, AID_SDCARD_RW,
+ AID_MOUNT, AID_INET, AID_NET_BW_STATS, AID_READPROC };
+ if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
+ MYLOGE("Unable to setgroups, aborting: %s\n", strerror(errno));
+ return false;
+ }
+ if (setgid(AID_SHELL) != 0) {
+ MYLOGE("Unable to setgid, aborting: %s\n", strerror(errno));
+ return false;
+ }
+ if (setuid(AID_SHELL) != 0) {
+ MYLOGE("Unable to setuid, aborting: %s\n", strerror(errno));
+ return false;
+ }
+
+ 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_SYSLOG)].permitted = CAP_TO_MASK(CAP_SYSLOG);
+ capdata[CAP_TO_INDEX(CAP_SYSLOG)].effective = CAP_TO_MASK(CAP_SYSLOG);
+ capdata[0].inheritable = 0;
+ capdata[1].inheritable = 0;
+
+ if (capset(&capheader, &capdata[0]) < 0) {
+ MYLOGE("capset failed: %s\n", strerror(errno));
+ return false;
+ }
+
+ return true;
+}
+
void send_broadcast(const std::string& action, const std::vector<std::string>& args) {
if (args.size() > 1000) {
MYLOGE("send_broadcast: too many arguments (%d)\n", (int) args.size());
return;
}
- const char *am_args[1024] = { SU_PATH, "shell", "/system/bin/am", "broadcast",
- "--user", "0", "-a", action.c_str() };
- size_t am_index = 7; // Starts at the index of last initial value above.
+ const char *am_args[1024] = { "/system/bin/am", "broadcast", "--user", "0", "-a",
+ action.c_str() };
+ size_t am_index = 5; // Starts at the index of last initial value above.
for (const std::string& arg : args) {
am_args[++am_index] = arg.c_str();
}
// Always terminate with NULL.
am_args[am_index + 1] = NULL;
- log_args("send_broadcast arguments", am_index, am_args);
- run_command_always(NULL, 5, am_args);
+ std::string args_string;
+ format_args(am_index + 1, am_args, &args_string);
+ MYLOGD("send_broadcast command: %s\n", args_string.c_str());
+ run_command_always(NULL, 5, true, am_args);
}
size_t num_props = 0;
@@ -1053,7 +1187,7 @@
void take_screenshot(const std::string& path) {
const char *args[] = { "/system/bin/screencap", "-p", path.c_str(), NULL };
- run_command_always(NULL, 10, args);
+ run_command_always(NULL, false, 10, args);
}
void vibrate(FILE* vibrator, int ms) {
@@ -1194,11 +1328,28 @@
printf("\n");
}
-void log_args(const std::string& message, int argc, const char *argv[]) {
- std::string args;
+// TODO: refactor all those commands that convert args
+void format_args(int argc, const char *argv[], std::string *args) {
+ LOG_ALWAYS_FATAL_IF(args == nullptr);
for (int i = 0; i < argc; i++) {
- args.append(argv[i]);
- args.append(" ");
+ args->append(argv[i]);
+ if (i < argc -1) {
+ args->append(" ");
+ }
}
- MYLOGD("%s: %s\n", message.c_str(), args.c_str());
+}
+void format_args(const char* command, const char *args[], std::string *string) {
+ LOG_ALWAYS_FATAL_IF(args == nullptr || command == nullptr);
+ string->append(command);
+ if (args[0] == nullptr) return;
+ string->append(" ");
+
+ for (int arg = 1; arg <= 1000; ++arg) {
+ if (args[arg] == nullptr) return;
+ string->append(args[arg]);
+ if (args[arg+1] != nullptr) {
+ string->append(" ");
+ }
+ }
+ MYLOGE("internal error: missing NULL entry on %s", string->c_str());
}
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index 003fcc3..db06e99 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -43,9 +43,10 @@
"usage: dumpsys\n"
" To dump all services.\n"
"or:\n"
- " dumpsys [--help | -l | --skip SERVICES | SERVICE [ARGS]]\n"
+ " dumpsys [-t TIMEOUT] [--help | -l | --skip SERVICES | SERVICE [ARGS]]\n"
" --help: shows this help\n"
" -l: only list services, do not dump them\n"
+ " -t TIMEOUT: TIMEOUT to use in seconds instead of default 10 seconds\n"
" --skip SERVICES: dumps all services but SERVICES (comma-separated list)\n"
" SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n");
}
@@ -74,44 +75,80 @@
Vector<String16> args;
Vector<String16> skippedServices;
bool showListOnly = false;
- if (argc == 2) {
- // 1 argument: check for special cases (-l or --help)
- if (strcmp(argv[1], "--help") == 0) {
- usage();
- return 0;
+ bool skipServices = false;
+ int timeoutArg = 10;
+ static struct option longOptions[] = {
+ {"skip", no_argument, 0, 0 },
+ {"help", no_argument, 0, 0 },
+ { 0, 0, 0, 0 }
+ };
+
+ while (1) {
+ int c;
+ int optionIndex = 0;
+
+ c = getopt_long(argc, argv, "+t:l", longOptions, &optionIndex);
+
+ if (c == -1) {
+ break;
}
- if (strcmp(argv[1], "-l") == 0) {
+
+ switch (c) {
+ case 0:
+ if (!strcmp(longOptions[optionIndex].name, "skip")) {
+ skipServices = true;
+ } else if (!strcmp(longOptions[optionIndex].name, "help")) {
+ usage();
+ return 0;
+ }
+ break;
+
+ case 't':
+ {
+ char *endptr;
+ timeoutArg = strtol(optarg, &endptr, 10);
+ if (*endptr != '\0' || timeoutArg <= 0) {
+ fprintf(stderr, "Error: invalid timeout number: '%s'\n", optarg);
+ return -1;
+ }
+ }
+ break;
+
+ case 'l':
showListOnly = true;
+ break;
+
+ default:
+ fprintf(stderr, "\n");
+ usage();
+ return -1;
}
}
- if (argc == 3) {
- // 2 arguments: check for special cases (--skip SERVICES)
- if (strcmp(argv[1], "--skip") == 0) {
- char* token = strtok(argv[2], ",");
- while (token != NULL) {
- skippedServices.add(String16(token));
- token = strtok(NULL, ",");
+
+ for (int i = optind; i < argc; i++) {
+ if (skipServices) {
+ skippedServices.add(String16(argv[i]));
+ } else {
+ if (i == optind) {
+ services.add(String16(argv[i]));
+ } else {
+ args.add(String16(argv[i]));
}
}
}
- bool dumpAll = argc == 1;
- if (dumpAll || !skippedServices.empty() || showListOnly) {
+
+ if ((skipServices && skippedServices.empty()) ||
+ (!skipServices && !showListOnly && services.empty()) ||
+ (showListOnly && (!services.empty() || !skippedServices.empty()))) {
+ usage();
+ return -1;
+ }
+
+ if (!skippedServices.empty() || showListOnly) {
// gets all services
services = sm->listServices();
services.sort(sort_func);
args.add(String16("-a"));
- } else {
- // gets a specific service:
- // first check if its name is not a special argument...
- if (strcmp(argv[1], "--skip") == 0 || strcmp(argv[1], "-l") == 0) {
- usage();
- return -1;
- }
- // ...then gets its arguments
- services.add(String16(argv[1]));
- for (int i=2; i<argc; i++) {
- args.add(String16(argv[i]));
- }
}
const size_t N = services.size();
@@ -173,8 +210,7 @@
}
});
- // TODO: Make this configurable at runtime.
- constexpr auto timeout = std::chrono::seconds(10);
+ auto timeout = std::chrono::seconds(timeoutArg);
auto end = std::chrono::steady_clock::now() + timeout;
struct pollfd pfd = {
diff --git a/cmds/installd/file_parsing.h b/cmds/installd/file_parsing.h
new file mode 100644
index 0000000..3e2f815
--- /dev/null
+++ b/cmds/installd/file_parsing.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OTAPREOPT_FILE_PARSING_H_
+#define OTAPREOPT_FILE_PARSING_H_
+
+#include <fstream>
+#include <functional>
+#include <string>
+
+namespace android {
+namespace installd {
+
+bool ParseFile(const std::string& strFile, std::function<bool (const std::string&)> parse) {
+ std::ifstream input_stream(strFile);
+
+ if (!input_stream.is_open()) {
+ return false;
+ }
+
+ while (!input_stream.eof()) {
+ // Read the next line.
+ std::string line;
+ getline(input_stream, line);
+
+ // Is the line empty? Simplifies the next check.
+ if (line.empty()) {
+ continue;
+ }
+
+ // Is this a comment (starts with pound)?
+ if (line[0] == '#') {
+ continue;
+ }
+
+ if (!parse(line)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // namespace installd
+} // namespace android
+
+#endif // OTAPREOPT_FILE_PARSING_H_
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index da454a7..89a4225 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -17,6 +17,7 @@
#include <algorithm>
#include <inttypes.h>
#include <random>
+#include <regex>
#include <selinux/android.h>
#include <selinux/avc.h>
#include <stdlib.h>
@@ -35,6 +36,7 @@
#include <private/android_filesystem_config.h>
#include <commands.h>
+#include <file_parsing.h>
#include <globals.h>
#include <installd_deps.h> // Need to fill in requirements of commands.
#include <string_helpers.h>
@@ -54,8 +56,8 @@
namespace android {
namespace installd {
-static constexpr const char* kBootClassPathPropertyName = "env.BOOTCLASSPATH";
-static constexpr const char* kAndroidRootPathPropertyName = "env.ANDROID_ROOT";
+static constexpr const char* kBootClassPathPropertyName = "BOOTCLASSPATH";
+static constexpr const char* kAndroidRootPathPropertyName = "ANDROID_ROOT";
static constexpr const char* kOTARootDirectory = "/system-b";
static constexpr size_t kISAIndex = 3;
@@ -131,41 +133,55 @@
private:
bool ReadSystemProperties() {
- // TODO(agampe): What to do about the things in default.prop? It's only heap sizes, so it's easy
- // to emulate for now, but has issues (e.g., vendors modifying the boot classpath
- // may require larger values here - revisit). That's why this goes first, so that
- // if those dummy values are overridden in build.prop, that's what we'll get.
- //
- // Note: It seems we'll get access to the B root partition, so we should read the default.prop
- // file.
- // if (!system_properties_.Load("/default.prop")) {
- // return false;
- // }
- system_properties_.SetProperty("dalvik.vm.image-dex2oat-Xms", "64m");
- system_properties_.SetProperty("dalvik.vm.image-dex2oat-Xmx", "64m");
- system_properties_.SetProperty("dalvik.vm.dex2oat-Xms", "64m");
- system_properties_.SetProperty("dalvik.vm.dex2oat-Xmx", "512m");
+ static constexpr const char* kPropertyFiles[] = {
+ "/default.prop", "/system/build.prop"
+ };
- // TODO(agampe): Do this properly/test.
- return system_properties_.Load("/system/build.prop");
+ for (size_t i = 0; i < arraysize(kPropertyFiles); ++i) {
+ if (!system_properties_.Load(kPropertyFiles[i])) {
+ return false;
+ }
+ }
+
+ return true;
}
bool ReadEnvironment() {
- // Read important environment variables. For simplicity, store them as
- // system properties.
- // TODO(agampe): We'll have to parse init.environ.rc for BOOTCLASSPATH.
- // For now, just the A version.
- const char* boot_classpath = getenv("BOOTCLASSPATH");
- if (boot_classpath == nullptr) {
- return false;
- }
- system_properties_.SetProperty(kBootClassPathPropertyName, boot_classpath);
+ // Parse the environment variables from init.environ.rc, which have the form
+ // export NAME VALUE
+ // For simplicity, don't respect string quotation. The values we are interested in can be
+ // encoded without them.
+ std::regex export_regex("\\s*export\\s+(\\S+)\\s+(\\S+)");
+ bool parse_result = ParseFile("/init.environ.rc", [&](const std::string& line) {
+ std::smatch export_match;
+ if (!std::regex_match(line, export_match, export_regex)) {
+ return true;
+ }
- const char* root_path = getenv("ANDROID_ROOT");
- if (root_path == nullptr) {
+ if (export_match.size() != 3) {
+ return true;
+ }
+
+ std::string name = export_match[1].str();
+ std::string value = export_match[2].str();
+
+ system_properties_.SetProperty(name, value);
+
+ return true;
+ });
+ if (!parse_result) {
return false;
}
- system_properties_.SetProperty(kAndroidRootPathPropertyName, root_path);
+
+ // Check that we found important properties.
+ constexpr const char* kRequiredProperties[] = {
+ kBootClassPathPropertyName, kAndroidRootPathPropertyName
+ };
+ for (size_t i = 0; i < arraysize(kRequiredProperties); ++i) {
+ if (system_properties_.GetProperty(kRequiredProperties[i]) == nullptr) {
+ return false;
+ }
+ }
return true;
}
diff --git a/cmds/installd/system_properties.h b/cmds/installd/system_properties.h
index 1b5fb3a..2d940a3 100644
--- a/cmds/installd/system_properties.h
+++ b/cmds/installd/system_properties.h
@@ -21,6 +21,8 @@
#include <string>
#include <unordered_map>
+#include <file_parsing.h>
+
namespace android {
namespace installd {
@@ -28,31 +30,11 @@
class SystemProperties {
public:
bool Load(const std::string& strFile) {
- std::ifstream input_stream(strFile);
-
- if (!input_stream.is_open()) {
- return false;
- }
-
- while (!input_stream.eof()) {
- // Read the next line.
- std::string line;
- getline(input_stream, line);
-
- // Is the line empty? Simplifies the next check.
- if (line.empty()) {
- continue;
- }
-
- // Is this a comment (starts with pound)?
- if (line[0] == '#') {
- continue;
- }
-
+ return ParseFile(strFile, [&](const std::string& line) {
size_t equals_pos = line.find('=');
if (equals_pos == std::string::npos || equals_pos == 0) {
// Did not find equals sign, or it's the first character - isn't a valid line.
- continue;
+ return true;
}
std::string key = line.substr(0, equals_pos);
@@ -60,9 +42,9 @@
line.length() - equals_pos + 1);
properties_.insert(std::make_pair(key, value));
- }
- return true;
+ return true;
+ });
}
// Look up the key in the map. Returns null if the key isn't mapped.
diff --git a/include/android/sensor.h b/include/android/sensor.h
index f2647be..5a61213 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -393,6 +393,13 @@
/*****************************************************************************/
/**
+ * Enable the selected sensor with a specified sampling period and max batch report latency.
+ * Returns a negative error code on failure.
+ */
+int ASensorEventQueue_registerSensor(ASensorEventQueue* queue, ASensor const* sensor,
+ int32_t samplingPeriodUs, int maxBatchReportLatencyUs);
+
+/**
* Enable the selected sensor. Returns a negative error code on failure.
*/
int ASensorEventQueue_enableSensor(ASensorEventQueue* queue, ASensor const* sensor);
diff --git a/include/binder/IMediaResourceMonitor.h b/include/binder/IMediaResourceMonitor.h
index b7b9c50..c671f7a 100644
--- a/include/binder/IMediaResourceMonitor.h
+++ b/include/binder/IMediaResourceMonitor.h
@@ -27,8 +27,13 @@
public:
DECLARE_META_INTERFACE(MediaResourceMonitor);
- virtual void notifyResourceGranted(/*in*/ int32_t pid, /*in*/ const String16& type,
- /*in*/ const String16& subType, /*in*/ int64_t value) = 0;
+ // Values should be in sync with Intent.EXTRA_MEDIA_RESOURCE_TYPE_XXX.
+ enum {
+ TYPE_VIDEO_CODEC = 0,
+ TYPE_AUDIO_CODEC = 1,
+ };
+
+ virtual void notifyResourceGranted(/*in*/ int32_t pid, /*in*/ const int32_t type) = 0;
enum {
NOTIFY_RESOURCE_GRANTED = IBinder::FIRST_CALL_TRANSACTION,
diff --git a/include/binder/MemoryDealer.h b/include/binder/MemoryDealer.h
index aa415d5..60a624c 100644
--- a/include/binder/MemoryDealer.h
+++ b/include/binder/MemoryDealer.h
@@ -41,6 +41,9 @@
virtual void deallocate(size_t offset);
virtual void dump(const char* what) const;
+ // allocations are aligned to some value. return that value so clients can account for it.
+ static size_t getAllocationAlignment();
+
sp<IMemoryHeap> getMemoryHeap() const { return heap(); }
protected:
diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
index acc8c4b..1b950ab 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -292,9 +292,6 @@
bool mAsyncMode;
// mSingleBufferMode indicates whether or not single buffer mode is enabled.
- // In single buffer mode, the last buffer that was dequeued is cached and
- // returned to all calls to dequeueBuffer and acquireBuffer. This allows the
- // consumer and producer to access the same buffer simultaneously.
bool mSingleBufferMode;
// When single buffer mode is enabled, this indicates whether the consumer
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index f6b4230..fee7c63 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -526,9 +526,10 @@
// Used to enable/disable single buffer mode.
//
- // In single buffer mode the last buffer that was dequeued will be cached
- // and returned to all calls to dequeueBuffer and acquireBuffer. This allows
- // the producer and consumer to simultaneously access the same buffer.
+ // When single buffer mode is enabled the first buffer that is queued or
+ // dequeued will be cached and returned to all subsequent calls to
+ // dequeueBuffer and acquireBuffer. This allows the producer and consumer to
+ // simultaneously access the same buffer.
virtual status_t setSingleBufferMode(bool singleBufferMode) = 0;
// Used to enable/disable auto-refresh.
diff --git a/include/hardware_properties/HardwarePropertiesManager.h b/include/hardware_properties/HardwarePropertiesManager.h
deleted file mode 100644
index 13f2b99..0000000
--- a/include/hardware_properties/HardwarePropertiesManager.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWAREPROPERTIESMANAGER_H
-#define ANDROID_HARDWAREPROPERTIESMANAGER_H
-
-namespace android {
-
-// must be kept in sync with definitions in HardwarePropertiesManager.java
-enum {
- DEVICE_TEMPERATURE_CPU = 0,
- DEVICE_TEMPERATURE_GPU = 1,
- DEVICE_TEMPERATURE_BATTERY = 2,
-};
-
-}; // namespace android
-
-#endif // ANDROID_HARDWAREPROPERTIESMANAGER_H
diff --git a/include/media/hardware/HardwareAPI.h b/include/media/hardware/HardwareAPI.h
index 654773d..2c50ad6 100644
--- a/include/media/hardware/HardwareAPI.h
+++ b/include/media/hardware/HardwareAPI.h
@@ -360,11 +360,11 @@
// VIDEO DECODERS: the framework uses OMX_SetConfig to specify the default color aspects to use
// for the video.
// This may happen:
-// f) before the component transitions to idle state
-// g) during execution, when the resolution or the default color aspects change.
+// a) before the component transitions to idle state
+// b) during execution, when the resolution or the default color aspects change.
//
// The framework also uses OMX_GetConfig to
-// h) get the final color aspects reported by the coded bitstream after taking the default values
+// c) get the final color aspects reported by the coded bitstream after taking the default values
// into account.
//
// 1. Decoders should maintain two color aspect states - the default state as reported by the
@@ -387,7 +387,7 @@
// or as Unspecified, if not defined.
//
// BOTH DECODERS AND ENCODERS: the framework uses OMX_GetConfig during idle and executing state to
-// i) (optional) get guidance for the dataspace to set for given color aspects, by setting
+// f) (optional) get guidance for the dataspace to set for given color aspects, by setting
// bRequestingDataSpace to OMX_TRUE. The component SHALL return OMX_ErrorUnsupportedSettings
// IF it does not support this request.
//
@@ -408,6 +408,8 @@
// to perform color-space extension by inline color-space conversion to facilitate a more optimal
// rendering pipeline.).
//
+// Note: the size of sAspects may increase in the future by additional fields.
+// Implementations SHOULD NOT require a certain size.
struct DescribeColorAspectsParams {
OMX_U32 nSize; // IN
OMX_VERSIONTYPE nVersion; // IN
@@ -419,6 +421,79 @@
ColorAspects sAspects; // IN/OUT
};
+// HDR color description parameters.
+// This is passed via OMX_SetConfig or OMX_GetConfig to video encoders and decoders when the
+// 'OMX.google.android.index.describeHDRColorInfo' extension is given and an HDR stream
+// is detected. Component SHALL behave as described below if it supports this extension.
+//
+// Currently, only Static Metadata Descriptor Type 1 support is required.
+//
+// VIDEO ENCODERS: the framework uses OMX_SetConfig to specify the HDR static information of the
+// coded video.
+// This may happen:
+// a) before the component transitions to idle state
+// b) before the input frame is sent via OMX_EmptyThisBuffer in executing state
+// c) during execution, just before an input frame with a different HDR static
+// information is sent.
+//
+// The framework also uses OMX_GetConfig to
+// d) verify the HDR static information that will be written to the stream.
+//
+// 1. Encoders SHOULD maintain an internal HDR static info data, initialized to Unspecified values.
+// This represents the values that will be written into the bitstream.
+// 2. Upon OMX_SetConfig, they SHOULD update their internal state to the info received
+// (including Unspecified values). For specific parameters that are not supported by the
+// codec standard, encoders SHOULD substitute Unspecified values. NOTE: no other substitution
+// is allowed.
+// 3. OMX_GetConfig SHALL return the internal state (values that will be written).
+// 4. OMX_SetConfig SHALL always succeed before receiving the first frame if the encoder is
+// configured into an HDR compatible profile. It MAY fail with OMX_ErrorUnsupportedSettings error
+// code if it is not configured into such a profile, OR if the configured values would change
+// AND the component does not support updating the HDR static information mid-stream. If the
+// component supports updating a portion of the information, those values should be updated in
+// the internal state, and OMX_SetConfig SHALL succeed. Otherwise, the internal state SHALL
+// remain intact.
+//
+// VIDEO DECODERS: the framework uses OMX_SetConfig to specify the default HDR static information
+// to use for the video.
+// a) This only happens if the client supplies this information, in which case it occurs before
+// the component transitions to idle state.
+// b) This may also happen subsequently if the default HDR static information changes.
+//
+// The framework also uses OMX_GetConfig to
+// c) get the final HDR static information reported by the coded bitstream after taking the
+// default values into account.
+//
+// 1. Decoders should maintain two HDR static information structures - the default values as
+// reported by the framework, and the coded values as reported by the bitstream - as each
+// structure can change independently from the other.
+// 2. Upon OMX_SetConfig, it SHALL update its default structure regardless of whether such static
+// parameters could be supplied by the component bitstream. (E.g. it should blindly support all
+// parameter values, even seemingly illegal ones). This SHALL always succeed.
+// Note: The descriptor ID used in sInfo may change in subsequent calls. (although for now only
+// Type 1 support is required.)
+// 3. Upon OMX_GetConfig, the component SHALL return the final HDR static information by replacing
+// Unspecified coded values with the default values. This SHALL always succeed. This may be
+// provided using any supported descriptor ID (currently only Type 1) with the goal of expressing
+// the most of the available static information.
+// 4. Whenever the component processes HDR static information in the bitstream even ones with
+// Unspecified parameters, it SHOULD update its internal coded structure with that information
+// just before the frame with the new information would be outputted, and the component SHALL
+// signal an OMX_EventPortSettingsChanged event with data2 set to the extension index.
+// NOTE: Component SHOULD NOT signal a separate event purely for HDR static info change, if it
+// occurs together with a port definition (e.g. size), color aspect or crop change.
+// 5. If certain parameters of the HDR static information encountered in the bitstream cannot be
+// represented using sInfo, the component SHALL use the closest representation.
+//
+// Note: the size of sInfo may increase in the future by supporting additional descriptor types.
+// Implementations SHOULD NOT require a certain size.
+struct DescribeHDRStaticInfoParams {
+ OMX_U32 nSize; // IN
+ OMX_VERSIONTYPE nVersion; // IN
+ OMX_U32 nPortIndex; // IN
+ HDRStaticInfo sInfo; // IN/OUT
+};
+
} // namespace android
extern android::OMXPluginBase *createOMXPlugin();
diff --git a/include/media/hardware/VideoAPI.h b/include/media/hardware/VideoAPI.h
index 481cc67..3667c4b 100644
--- a/include/media/hardware/VideoAPI.h
+++ b/include/media/hardware/VideoAPI.h
@@ -57,7 +57,7 @@
/**
* Structure describing a media image (frame)
*/
-struct MediaImage2 {
+struct __attribute__ ((__packed__)) MediaImage2 {
enum Type : uint32_t {
MEDIA_IMAGE_TYPE_UNKNOWN = 0,
MEDIA_IMAGE_TYPE_YUV,
@@ -85,7 +85,7 @@
uint32_t mBitDepth; // useable bit depth (always MSB)
uint32_t mBitDepthAllocated; // bits per component (must be 8 or 16)
- struct PlaneInfo {
+ struct __attribute__ ((__packed__)) PlaneInfo {
uint32_t mOffset; // offset of first pixel of the plane in bytes
// from buffer offset
int32_t mColInc; // column increment in bytes
@@ -98,6 +98,9 @@
void initFromV1(const MediaImage&); // for internal use only
};
+static_assert(sizeof(MediaImage2::PlaneInfo) == 20, "wrong struct size");
+static_assert(sizeof(MediaImage2) == 104, "wrong struct size");
+
/**
* Aspects of color.
*/
@@ -107,7 +110,7 @@
// though could verify that nSize is at least the size of the structure at the
// time of implementation. All new fields will be added at the end of the structure
// ensuring backward compatibility.
-struct ColorAspects {
+struct __attribute__ ((__packed__)) ColorAspects {
// this is in sync with the range values in graphics.h
enum Range : uint32_t {
RangeUnspecified,
@@ -179,6 +182,46 @@
MatrixCoeffs mMatrixCoeffs; // IN/OUT
};
+static_assert(sizeof(ColorAspects) == 16, "wrong struct size");
+
+/**
+ * HDR Metadata.
+ */
+
+// HDR Static Metadata Descriptor as defined by CTA-861-3.
+struct __attribute__ ((__packed__)) HDRStaticInfo {
+ // Static_Metadata_Descriptor_ID
+ enum ID : uint8_t {
+ kType1 = 0, // Static Metadata Type 1
+ } mID;
+
+ struct __attribute__ ((__packed__)) Primaries1 {
+ // values are in units of 0.00002
+ uint16_t x;
+ uint16_t y;
+ };
+
+ // Static Metadata Descriptor Type 1
+ struct __attribute__ ((__packed__)) Type1 {
+ Primaries1 mR; // display primary 0
+ Primaries1 mG; // display primary 1
+ Primaries1 mB; // display primary 2
+ Primaries1 mW; // white point
+ uint16_t mMaxDisplayLuminance; // in cd/m^2
+ uint16_t mMinDisplayLuminance; // in 0.0001 cd/m^2
+ uint16_t mMaxContentLightLevel; // in cd/m^2
+ uint16_t mMaxFrameAverageLightLevel; // in cd/m^2
+ };
+
+ union {
+ Type1 sType1;
+ };
+};
+
+static_assert(sizeof(HDRStaticInfo::Primaries1) == 4, "wrong struct size");
+static_assert(sizeof(HDRStaticInfo::Type1) == 24, "wrong struct size");
+static_assert(sizeof(HDRStaticInfo) == 25, "wrong struct size");
+
#ifdef STRINGIFY_ENUMS
inline static const char *asString(MediaImage::Type i, const char *def = "??") {
diff --git a/include/media/openmax/OMX_Audio.h b/include/media/openmax/OMX_Audio.h
index a0cbd3b..d8bee76 100644
--- a/include/media/openmax/OMX_Audio.h
+++ b/include/media/openmax/OMX_Audio.h
@@ -178,7 +178,7 @@
OMX_VERSIONTYPE nVersion; /**< OMX specification version information */
OMX_U32 nPortIndex; /**< port that this structure applies to */
OMX_U32 nChannels; /**< Number of channels (e.g. 2 for stereo) */
- OMX_NUMERICALDATATYPE eNumData; /**< indicates PCM data as signed or unsigned */
+ OMX_NUMERICALDATATYPE eNumData; /**< indicates PCM data as signed, unsigned or floating pt. */
OMX_ENDIANTYPE eEndian; /**< indicates PCM data as little or big endian */
OMX_BOOL bInterleaved; /**< True for normal interleaved data; false for
non-interleaved data (e.g. block data) */
diff --git a/include/media/openmax/OMX_Types.h b/include/media/openmax/OMX_Types.h
index 5afaba0..515e002 100644
--- a/include/media/openmax/OMX_Types.h
+++ b/include/media/openmax/OMX_Types.h
@@ -280,12 +280,18 @@
/** The OMX_NUMERICALDATATYPE enumeration is used to indicate if data
- is signed or unsigned
+ is signed, unsigned or floating point (Android extension).
+
+ Android floating point support policy:
+ If component does not support floating point raw audio, it can reset
+ configuration to signed 16-bit integer (support for which is required.)
+ nBitsPerSample will be set to 32 for float data.
*/
typedef enum OMX_NUMERICALDATATYPE
{
OMX_NumericalDataSigned, /**< signed data */
OMX_NumericalDataUnsigned, /**< unsigned data */
+ OMX_NumericalDataFloat = 0x7F000001, /**< floating point data */
OMX_NumercialDataMax = 0x7FFFFFFF
} OMX_NUMERICALDATATYPE;
diff --git a/include/powermanager/PowerManager.h b/include/powermanager/PowerManager.h
index cbddc11..3268b45 100644
--- a/include/powermanager/PowerManager.h
+++ b/include/powermanager/PowerManager.h
@@ -28,8 +28,9 @@
USER_ACTIVITY_EVENT_OTHER = 0,
USER_ACTIVITY_EVENT_BUTTON = 1,
USER_ACTIVITY_EVENT_TOUCH = 2,
+ USER_ACTIVITY_EVENT_ACCESSIBILITY = 3,
- USER_ACTIVITY_EVENT_LAST = USER_ACTIVITY_EVENT_TOUCH, // Last valid event code.
+ USER_ACTIVITY_EVENT_LAST = USER_ACTIVITY_EVENT_ACCESSIBILITY, // Last valid event code.
};
}; // namespace android
diff --git a/libs/binder/IMediaResourceMonitor.cpp b/libs/binder/IMediaResourceMonitor.cpp
index e8deb4a..4800f5b 100644
--- a/libs/binder/IMediaResourceMonitor.cpp
+++ b/libs/binder/IMediaResourceMonitor.cpp
@@ -28,15 +28,12 @@
BpMediaResourceMonitor(const sp<IBinder>& impl)
: BpInterface<IMediaResourceMonitor>(impl) {}
- virtual void notifyResourceGranted(/*in*/ int32_t pid, /*in*/ const String16& type,
- /*in*/ const String16& subType, /*in*/ int64_t value)
+ virtual void notifyResourceGranted(/*in*/ int32_t pid, /*in*/ const int32_t type)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaResourceMonitor::getInterfaceDescriptor());
data.writeInt32(pid);
- data.writeString16(type);
- data.writeString16(subType);
- data.writeInt64(value);
+ data.writeInt32(type);
remote()->transact(NOTIFY_RESOURCE_GRANTED, data, &reply, IBinder::FLAG_ONEWAY);
}
};
@@ -51,10 +48,8 @@
case NOTIFY_RESOURCE_GRANTED: {
CHECK_INTERFACE(IMediaResourceMonitor, data, reply);
int32_t pid = data.readInt32();
- const String16 type = data.readString16();
- const String16 subType = data.readString16();
- int64_t value = data.readInt64();
- notifyResourceGranted(/*in*/ pid, /*in*/ type, /*in*/ subType, /*in*/ value);
+ const int32_t type = data.readInt32();
+ notifyResourceGranted(/*in*/ pid, /*in*/ type);
return NO_ERROR;
} break;
default:
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 1f6bda2..1cbcfe4 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -1089,8 +1089,16 @@
<< reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl;
}
if (tr.target.ptr) {
- sp<BBinder> b((BBinder*)tr.cookie);
- error = b->transact(tr.code, buffer, &reply, tr.flags);
+ // We only have a weak reference on the target object, so we must first try to
+ // safely acquire a strong reference before doing anything else with it.
+ if (reinterpret_cast<RefBase::weakref_type*>(
+ tr.target.ptr)->attemptIncStrong(this)) {
+ error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,
+ &reply, tr.flags);
+ reinterpret_cast<BBinder*>(tr.cookie)->decStrong(this);
+ } else {
+ error = UNKNOWN_TRANSACTION;
+ }
} else {
error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
diff --git a/libs/binder/MemoryDealer.cpp b/libs/binder/MemoryDealer.cpp
index 8739625..51eac11 100644
--- a/libs/binder/MemoryDealer.cpp
+++ b/libs/binder/MemoryDealer.cpp
@@ -135,6 +135,8 @@
void dump(const char* what) const;
void dump(String8& res, const char* what) const;
+ static size_t getAllocationAlignment() { return kMemoryAlign; }
+
private:
struct chunk_t {
@@ -264,6 +266,12 @@
return mAllocator;
}
+// static
+size_t MemoryDealer::getAllocationAlignment()
+{
+ return SimpleBestFitAllocator::getAllocationAlignment();
+}
+
// ----------------------------------------------------------------------------
// align all the memory blocks on a cache-line boundary
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index e9d0654..4fd8b89 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -761,6 +761,14 @@
return BAD_VALUE;
}
+ // If single buffer mode has just been enabled, cache the slot of the
+ // first buffer that is queued and mark it as the shared buffer.
+ if (mCore->mSingleBufferMode && mCore->mSingleBufferSlot ==
+ BufferQueueCore::INVALID_BUFFER_SLOT) {
+ mCore->mSingleBufferSlot = slot;
+ mSlots[slot].mBufferState.mShared = true;
+ }
+
BQ_LOGV("queueBuffer: slot=%d/%" PRIu64 " time=%" PRIu64 " dataSpace=%d"
" crop=[%d,%d,%d,%d] transform=%#x scale=%s",
slot, mCore->mFrameCounter + 1, timestamp, dataSpace,
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 149f5bd..29d5268 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -393,6 +393,21 @@
return err;
}
+ // For investigating b/27674961
+ if (mEglSlots[slot].mEglImage == nullptr) {
+ ALOGE("If you see this message in a log please post the log to "
+ "b/27674961");
+ ALOGE("slot = %d, mCurrentTexture = %d, mCurrentTextureImage = %p",
+ slot, mCurrentTexture, mCurrentTextureImage.get());
+ for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+ ALOGE("mEglSlots[%d].mEglImage = %p", i,
+ mEglSlots[i].mEglImage.get());
+ }
+ String8 dump;
+ dumpLocked(dump, "");
+ ALOGE("%s", dump.string());
+ }
+
// Ensure we have a valid EglImageKHR for the slot, creating an EglImage
// if nessessary, for the gralloc buffer currently in the slot in
// ConsumerBase.
diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp
index a75569f..cb1ad35 100644
--- a/libs/gui/IGraphicBufferConsumer.cpp
+++ b/libs/gui/IGraphicBufferConsumer.cpp
@@ -338,7 +338,7 @@
}
case GET_RELEASED_BUFFERS: {
CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
- uint64_t slotMask;
+ uint64_t slotMask = 0;
status_t result = getReleasedBuffers(&slotMask);
reply->writeInt64(static_cast<int64_t>(slotMask));
reply->writeInt32(result);
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index c66694d..3101f3a 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -513,6 +513,7 @@
QueueBufferOutput* const output =
reinterpret_cast<QueueBufferOutput *>(
reply->writeInplace(sizeof(QueueBufferOutput)));
+ memset(output, 0, sizeof(QueueBufferOutput));
status_t res = connect(listener, api, producerControlledByApp, output);
reply->writeInt32(res);
return NO_ERROR;
diff --git a/libs/gui/SensorEventQueue.cpp b/libs/gui/SensorEventQueue.cpp
index 4b7986e..5983a6c 100644
--- a/libs/gui/SensorEventQueue.cpp
+++ b/libs/gui/SensorEventQueue.cpp
@@ -125,7 +125,7 @@
}
status_t SensorEventQueue::enableSensor(Sensor const* sensor) const {
- return mSensorEventConnection->enableDisable(sensor->getHandle(), true, 0, 0, false);
+ return mSensorEventConnection->enableDisable(sensor->getHandle(), true, us2ns(200000), 0, false);
}
status_t SensorEventQueue::disableSensor(Sensor const* sensor) const {
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index b6af166..7790762 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -661,6 +661,57 @@
}
}
+TEST_F(BufferQueueTest, TestSingleBufferModeUsingAlreadyDequeuedBuffer) {
+ 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));
+
+ // Dequeue a buffer
+ int singleSlot;
+ sp<Fence> fence;
+ sp<GraphicBuffer> buffer;
+ ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
+ mProducer->dequeueBuffer(&singleSlot, &fence, 0, 0, 0, 0));
+ ASSERT_EQ(OK, mProducer->requestBuffer(singleSlot, &buffer));
+
+ // Enable single buffer mode
+ ASSERT_EQ(OK, mProducer->setSingleBufferMode(true));
+
+ // Queue the buffer
+ IGraphicBufferProducer::QueueBufferInput input(0, false,
+ HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1),
+ NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
+ ASSERT_EQ(OK, mProducer->queueBuffer(singleSlot, input, &output));
+
+ // Repeatedly queue and dequeue a buffer from the producer side, it should
+ // always return the same one. And we won't run out of buffers because it's
+ // always the same one and because async mode gets enabled.
+ int slot;
+ for (int i = 0; i < 5; i++) {
+ ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0));
+ ASSERT_EQ(singleSlot, slot);
+ ASSERT_EQ(OK, mProducer->queueBuffer(singleSlot, input, &output));
+ }
+
+ // acquire the buffer
+ BufferItem item;
+ ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
+ ASSERT_EQ(singleSlot, item.mSlot);
+ testBufferItem(input, item);
+ ASSERT_EQ(true, item.mQueuedBuffer);
+ ASSERT_EQ(false, item.mAutoRefresh);
+
+ ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
+ EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
+
+ // attempt to acquire a second time should return no buffer available
+ ASSERT_EQ(IGraphicBufferConsumer::NO_BUFFER_AVAILABLE,
+ mConsumer->acquireBuffer(&item, 0));
+}
+
TEST_F(BufferQueueTest, TestTimeouts) {
createBufferQueue();
sp<DummyConsumer> dc(new DummyConsumer);
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 794a7e5..e7703d8 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -1196,8 +1196,10 @@
egl_surface_t const * const s = get_surface(surface);
if (attribute == EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID) {
- return (native_window_set_auto_refresh(s->win.get(),
- value ? true : false)) ? EGL_TRUE : EGL_FALSE;
+ int err = native_window_set_auto_refresh(s->win.get(),
+ value ? true : false);
+ return (err == NO_ERROR) ? EGL_TRUE :
+ setError(EGL_BAD_SURFACE, EGL_FALSE);
}
if (s->cnx->egl.eglSurfaceAttrib) {
diff --git a/services/sensorservice/Android.mk b/services/sensorservice/Android.mk
index ef17630..57c56a6 100644
--- a/services/sensorservice/Android.mk
+++ b/services/sensorservice/Android.mk
@@ -20,7 +20,7 @@
LOCAL_CFLAGS:= -DLOG_TAG=\"SensorService\"
-LOCAL_CFLAGS += -Wall -Werror
+LOCAL_CFLAGS += -Wall -Werror -Wextra
LOCAL_CFLAGS += -fvisibility=hidden
@@ -50,6 +50,8 @@
libbinder \
libutils
+LOCAL_CFLAGS := -Wall -Werror -Wextra
+
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE:= sensorservice
diff --git a/vulkan/libvulkan/loader.cpp b/vulkan/libvulkan/loader.cpp
index d5cc280..6531968 100644
--- a/vulkan/libvulkan/loader.cpp
+++ b/vulkan/libvulkan/loader.cpp
@@ -252,6 +252,7 @@
message(VK_NULL_HANDLE) {
memset(&dispatch, 0, sizeof(dispatch));
memset(physical_devices, 0, sizeof(physical_devices));
+ enabled_extensions.reset();
drv.instance = VK_NULL_HANDLE;
memset(&drv.dispatch, 0, sizeof(drv.dispatch));
drv.num_physical_devices = 0;
@@ -265,12 +266,14 @@
const VkAllocationCallbacks* alloc;
uint32_t num_physical_devices;
+ VkPhysicalDevice physical_devices_top[kMaxPhysicalDevices];
VkPhysicalDevice physical_devices[kMaxPhysicalDevices];
DeviceExtensionSet physical_device_driver_extensions[kMaxPhysicalDevices];
Vector<LayerRef> active_layers;
VkDebugReportCallbackEXT message;
DebugReportCallbackList debug_report_callbacks;
+ InstanceExtensionSet enabled_extensions;
struct {
VkInstance instance;
@@ -284,11 +287,13 @@
: instance(instance_),
active_layers(CallbackAllocator<LayerRef>(instance->alloc)) {
memset(&dispatch, 0, sizeof(dispatch));
+ enabled_extensions.reset();
}
DeviceDispatchTable dispatch;
Instance* instance;
PFN_vkGetDeviceProcAddr get_device_proc_addr;
Vector<LayerRef> active_layers;
+ DeviceExtensionSet enabled_extensions;
};
template <typename THandle>
@@ -621,7 +626,6 @@
static_cast<VkInstance>(chain_info->u.instanceInfo.instance_info));
// Check that all enabled extensions are supported
- InstanceExtensionSet enabled_extensions;
uint32_t num_driver_extensions = 0;
for (uint32_t i = 0; i < create_info->enabledExtensionCount; i++) {
const char* name = create_info->ppEnabledExtensionNames[i];
@@ -629,11 +633,11 @@
if (id != kInstanceExtensionCount) {
if (g_driver_instance_extensions[id]) {
num_driver_extensions++;
- enabled_extensions.set(id);
+ instance.enabled_extensions.set(id);
continue;
}
if (id == kKHR_surface || id == kKHR_android_surface) {
- enabled_extensions.set(id);
+ instance.enabled_extensions.set(id);
continue;
}
// The loader natively supports debug report.
@@ -700,9 +704,9 @@
// Skip setting drv_dispatch->vtbl, since we never call through it;
// we go through instance.drv.dispatch instead.
- if (!LoadDriverDispatchTable(instance.drv.instance,
- g_hwdevice->GetInstanceProcAddr,
- enabled_extensions, instance.drv.dispatch)) {
+ if (!LoadDriverDispatchTable(
+ instance.drv.instance, g_hwdevice->GetInstanceProcAddr,
+ instance.enabled_extensions, instance.drv.dispatch)) {
DestroyInstance_Bottom(instance.handle, allocator);
return VK_ERROR_INITIALIZATION_FAILED;
}
@@ -782,8 +786,106 @@
return VK_SUCCESS;
}
-PFN_vkVoidFunction GetInstanceProcAddr_Bottom(VkInstance, const char* name) {
+VkResult CreateAndroidSurfaceKHR_Disabled(VkInstance,
+ const VkAndroidSurfaceCreateInfoKHR*,
+ const VkAllocationCallbacks*,
+ VkSurfaceKHR*) {
+ ALOGE(
+ "VK_KHR_android_surface not enabled. vkCreateAndroidSurfaceKHR not "
+ "executed.");
+
+ return VK_SUCCESS;
+}
+
+void DestroySurfaceKHR_Disabled(VkInstance,
+ VkSurfaceKHR,
+ const VkAllocationCallbacks*) {
+ ALOGE("VK_KHR_surface not enabled. vkDestroySurfaceKHR not executed.");
+}
+
+VkResult GetPhysicalDeviceSurfaceSupportKHR_Disabled(VkPhysicalDevice,
+ uint32_t,
+ VkSurfaceKHR,
+ VkBool32*) {
+ ALOGE(
+ "VK_KHR_surface not enabled. vkGetPhysicalDeviceSurfaceSupportKHR not "
+ "executed.");
+
+ return VK_SUCCESS;
+}
+
+VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR_Disabled(
+ VkPhysicalDevice,
+ VkSurfaceKHR,
+ VkSurfaceCapabilitiesKHR*) {
+ ALOGE(
+ "VK_KHR_surface not enabled. vkGetPhysicalDeviceSurfaceapabilitiesKHR "
+ "not executed.");
+
+ return VK_SUCCESS;
+}
+
+VkResult GetPhysicalDeviceSurfaceFormatsKHR_Disabled(VkPhysicalDevice,
+ VkSurfaceKHR,
+ uint32_t*,
+ VkSurfaceFormatKHR*) {
+ ALOGE(
+ "VK_KHR_surface not enabled. vkGetPhysicalDeviceSurfaceFormatsKHR not "
+ "executed.");
+
+ return VK_SUCCESS;
+}
+
+VkResult GetPhysicalDeviceSurfacePresentModesKHR_Disabled(VkPhysicalDevice,
+ VkSurfaceKHR,
+ uint32_t*,
+ VkPresentModeKHR*) {
+ ALOGE(
+ "VK_KHR_surface not enabled. vkGetPhysicalDeviceSurfacePresentModesKHR "
+ "not executed.");
+
+ return VK_SUCCESS;
+}
+
+PFN_vkVoidFunction GetInstanceProcAddr_Bottom(VkInstance vkinstance,
+ const char* name) {
PFN_vkVoidFunction pfn;
+
+ if (vkinstance) {
+ Instance& instance = GetDispatchParent(vkinstance);
+ if (!instance.enabled_extensions[kKHR_android_surface]) {
+ // KHR_android_surface is not enabled, use error stubs instead
+ if (strcmp(name, "vkCreateAndroidSurfaceKHR") == 0) {
+ return reinterpret_cast<PFN_vkVoidFunction>(
+ CreateAndroidSurfaceKHR_Disabled);
+ }
+ }
+ if (!instance.enabled_extensions[kKHR_surface]) {
+ // KHR_surface is not enabled, use error stubs instead
+ if (strcmp(name, "vkDestroySurfaceKHR") == 0) {
+ return reinterpret_cast<PFN_vkVoidFunction>(
+ DestroySurfaceKHR_Disabled);
+ }
+ if (strcmp(name, "vkGetPhysicalDeviceSurfaceSupportKHR") == 0) {
+ return reinterpret_cast<PFN_vkVoidFunction>(
+ GetPhysicalDeviceSurfaceSupportKHR_Disabled);
+ }
+ if (strcmp(name, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR") ==
+ 0) {
+ return reinterpret_cast<PFN_vkVoidFunction>(
+ GetPhysicalDeviceSurfaceCapabilitiesKHR_Disabled);
+ }
+ if (strcmp(name, "vkGetPhysicalDeviceSurfaceFormatsKHR") == 0) {
+ return reinterpret_cast<PFN_vkVoidFunction>(
+ GetPhysicalDeviceSurfaceFormatsKHR_Disabled);
+ }
+ if (strcmp(name, "vkGetPhysicalDeviceSurfacePresentModesKHR") ==
+ 0) {
+ return reinterpret_cast<PFN_vkVoidFunction>(
+ GetPhysicalDeviceSurfacePresentModesKHR_Disabled);
+ }
+ }
+ }
if ((pfn = GetLoaderBottomProcAddr(name)))
return pfn;
return nullptr;
@@ -924,6 +1026,7 @@
if (id != kDeviceExtensionCount) {
if (instance.physical_device_driver_extensions[gpu_idx][id]) {
driver_extensions[num_driver_extensions++] = name;
+ device->enabled_extensions.set(id);
continue;
}
// Add the VK_ANDROID_native_buffer extension to the list iff
@@ -933,6 +1036,7 @@
[gpu_idx][kANDROID_native_buffer]) {
driver_extensions[num_driver_extensions++] =
VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME;
+ device->enabled_extensions.set(id);
continue;
}
}
@@ -996,12 +1100,78 @@
}
}
+VkResult CreateSwapchainKHR_Disabled(VkDevice,
+ const VkSwapchainCreateInfoKHR*,
+ const VkAllocationCallbacks*,
+ VkSwapchainKHR*) {
+ ALOGE("VK_KHR_swapchain not enabled. vkCreateSwapchainKHR not executed.");
+
+ return VK_SUCCESS;
+}
+
+void DestroySwapchainKHR_Disabled(VkDevice,
+ VkSwapchainKHR,
+ const VkAllocationCallbacks*) {
+ ALOGE("VK_KHR_swapchain not enabled. vkDestroySwapchainKHR not executed.");
+}
+
+VkResult GetSwapchainImagesKHR_Disabled(VkDevice,
+ VkSwapchainKHR,
+ uint32_t*,
+ VkImage*) {
+ ALOGE(
+ "VK_KHR_swapchain not enabled. vkGetSwapchainImagesKHR not executed.");
+
+ return VK_SUCCESS;
+}
+
+VkResult AcquireNextImageKHR_Disabled(VkDevice,
+ VkSwapchainKHR,
+ uint64_t,
+ VkSemaphore,
+ VkFence,
+ uint32_t*) {
+ ALOGE("VK_KHR_swapchain not enabled. vkAcquireNextImageKHR not executed.");
+
+ return VK_SUCCESS;
+}
+
+VkResult QueuePresentKHR_Disabled(VkQueue, const VkPresentInfoKHR*) {
+ ALOGE("VK_KHR_swapchain not enabled. vkQueuePresentKHR not executed.");
+
+ return VK_SUCCESS;
+}
+
PFN_vkVoidFunction GetDeviceProcAddr_Bottom(VkDevice vkdevice,
const char* name) {
if (strcmp(name, "vkCreateDevice") == 0) {
return reinterpret_cast<PFN_vkVoidFunction>(CreateDevice_Bottom);
}
+ Device& device = GetDispatchParent(vkdevice);
+ if (!device.enabled_extensions[kKHR_swapchain]) {
+ if (strcmp(name, "vkCreateSwapchainKHR") == 0) {
+ return reinterpret_cast<PFN_vkVoidFunction>(
+ CreateSwapchainKHR_Disabled);
+ }
+ if (strcmp(name, "vkDestroySwapchainKHR") == 0) {
+ return reinterpret_cast<PFN_vkVoidFunction>(
+ DestroySwapchainKHR_Disabled);
+ }
+ if (strcmp(name, "vkGetSwapchainImagesKHR") == 0) {
+ return reinterpret_cast<PFN_vkVoidFunction>(
+ GetSwapchainImagesKHR_Disabled);
+ }
+ if (strcmp(name, "vkAcquireNextSwapchainImageKHR") == 0) {
+ return reinterpret_cast<PFN_vkVoidFunction>(
+ AcquireNextImageKHR_Disabled);
+ }
+ if (strcmp(name, "vkQueuePresentKHR") == 0) {
+ return reinterpret_cast<PFN_vkVoidFunction>(
+ QueuePresentKHR_Disabled);
+ }
+ }
+
// VK_ANDROID_native_buffer should be hidden from applications and layers.
// TODO(jessehall): Generate this as part of GetLoaderBottomProcAddr.
PFN_vkVoidFunction pfn;
@@ -1086,7 +1256,7 @@
ALOGV(" no layer");
Instance& instance = GetDispatchParent(gpu);
size_t gpu_idx = 0;
- while (instance.physical_devices[gpu_idx] != gpu)
+ while (instance.physical_devices_top[gpu_idx] != gpu)
gpu_idx++;
const DeviceExtensionSet driver_extensions =
instance.physical_device_driver_extensions[gpu_idx];
@@ -1253,6 +1423,24 @@
DestroyInstance(instance, allocator);
return VK_ERROR_INITIALIZATION_FAILED;
}
+
+ // Capture the physical devices from the top of the
+ // chain in case it has been wrapped by a layer.
+ uint32_t num_physical_devices = 0;
+ result = instance_dispatch.EnumeratePhysicalDevices(
+ local_instance, &num_physical_devices, nullptr);
+ if (result != VK_SUCCESS) {
+ DestroyInstance(instance, allocator);
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+ num_physical_devices = std::min(num_physical_devices, kMaxPhysicalDevices);
+ result = instance_dispatch.EnumeratePhysicalDevices(
+ local_instance, &num_physical_devices,
+ instance->physical_devices_top);
+ if (result != VK_SUCCESS) {
+ DestroyInstance(instance, allocator);
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
*instance_out = local_instance;
if (enable_callback) {
@@ -1342,10 +1530,6 @@
return result;
}
- size_t gpu_idx = 0;
- while (instance.physical_devices[gpu_idx] != gpu)
- gpu_idx++;
-
uint32_t activated_layers = 0;
VkLayerDeviceCreateInfo chain_info;
VkLayerDeviceLink* layer_device_link_info = nullptr;
diff --git a/vulkan/libvulkan/loader.h b/vulkan/libvulkan/loader.h
index cec0ff6..ada66f1 100644
--- a/vulkan/libvulkan/loader.h
+++ b/vulkan/libvulkan/loader.h
@@ -139,6 +139,18 @@
VKAPI_ATTR VkResult GetSwapchainImagesKHR_Bottom(VkDevice device, VkSwapchainKHR swapchain_handle, uint32_t* count, VkImage* images);
VKAPI_ATTR VkResult AcquireNextImageKHR_Bottom(VkDevice device, VkSwapchainKHR swapchain_handle, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* image_index);
VKAPI_ATTR VkResult QueuePresentKHR_Bottom(VkQueue queue, const VkPresentInfoKHR* present_info);
+
+VKAPI_ATTR VkResult CreateAndroidSurfaceKHR_Disabled(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface);
+VKAPI_ATTR void DestroySurfaceKHR_Disabled(VkInstance, VkSurfaceKHR, const VkAllocationCallbacks*);
+VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceSupportKHR_Disabled(VkPhysicalDevice, uint32_t, VkSurfaceKHR, VkBool32*);
+VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR_Disabled(VkPhysicalDevice, VkSurfaceKHR, VkSurfaceCapabilitiesKHR*);
+VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceFormatsKHR_Disabled(VkPhysicalDevice, VkSurfaceKHR, uint32_t*, VkSurfaceFormatKHR*);
+VKAPI_ATTR VkResult GetPhysicalDeviceSurfacePresentModesKHR_Disabled(VkPhysicalDevice, VkSurfaceKHR, uint32_t*, VkPresentModeKHR*);
+VKAPI_ATTR VkResult CreateSwapchainKHR_Disabled(VkDevice device, const VkSwapchainCreateInfoKHR* create_info, const VkAllocationCallbacks* allocator, VkSwapchainKHR* swapchain_handle);
+VKAPI_ATTR void DestroySwapchainKHR_Disabled(VkDevice device, VkSwapchainKHR swapchain_handle, const VkAllocationCallbacks* allocator);
+VKAPI_ATTR VkResult GetSwapchainImagesKHR_Disabled(VkDevice device, VkSwapchainKHR swapchain_handle, uint32_t* count, VkImage* images);
+VKAPI_ATTR VkResult AcquireNextImageKHR_Disabled(VkDevice device, VkSwapchainKHR swapchain_handle, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* image_index);
+VKAPI_ATTR VkResult QueuePresentKHR_Disabled(VkQueue queue, const VkPresentInfoKHR* present_info);
// clang-format on
// -----------------------------------------------------------------------------