Merge "vulkan: rewrite top of loader" into nyc-dev
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 03980c3..61b8f6b 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+ #define LOG_TAG "atrace"
+
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
@@ -42,8 +44,6 @@
using namespace android;
-#define LOG_TAG "atrace"
-
#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
enum { MAX_SYS_FILES = 10 };
@@ -175,6 +175,7 @@
static const char* g_categoriesFile = NULL;
static const char* g_kernelTraceFuncs = NULL;
static const char* g_debugAppCmdLine = "";
+static const char* g_outputFile = nullptr;
/* Global state */
static bool g_traceAborted = false;
@@ -769,7 +770,7 @@
}
// Read the current kernel trace and write it to stdout.
-static void dumpTrace()
+static void dumpTrace(int outFd)
{
ALOGI("Dumping trace");
int traceFD = open(k_tracePath, O_RDWR);
@@ -820,7 +821,7 @@
if (zs.avail_out == 0) {
// Need to write the output.
- result = write(STDOUT_FILENO, out, bufSize);
+ result = write(outFd, out, bufSize);
if ((size_t)result < bufSize) {
fprintf(stderr, "error writing deflated trace: %s (%d)\n",
strerror(errno), errno);
@@ -840,7 +841,7 @@
if (zs.avail_out < bufSize) {
size_t bytes = bufSize - zs.avail_out;
- result = write(STDOUT_FILENO, out, bytes);
+ result = write(outFd, out, bytes);
if ((size_t)result < bytes) {
fprintf(stderr, "error writing deflated trace: %s (%d)\n",
strerror(errno), errno);
@@ -856,7 +857,7 @@
free(out);
} else {
ssize_t sent = 0;
- while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0);
+ while ((sent = sendfile(outFd, traceFD, NULL, 64*1024*1024)) > 0);
if (sent == -1) {
fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
errno);
@@ -921,6 +922,8 @@
" CPU performance, like pagecache usage.\n"
" --list_categories\n"
" list the available tracing categories\n"
+ " -o filename write the trace to the specified file instead\n"
+ " of stdout.\n"
);
}
@@ -949,7 +952,7 @@
{ 0, 0, 0, 0 }
};
- ret = getopt_long(argc, argv, "a:b:cf:k:ns:t:z",
+ ret = getopt_long(argc, argv, "a:b:cf:k:ns:t:zo:",
long_options, &option_index);
if (ret < 0) {
@@ -999,6 +1002,10 @@
g_compress = true;
break;
+ case 'o':
+ g_outputFile = optarg;
+ break;
+
case 0:
if (!strcmp(long_options[option_index].name, "async_start")) {
async = true;
@@ -1076,9 +1083,21 @@
if (ok && traceDump) {
if (!g_traceAborted) {
- printf(" done\nTRACE:\n");
+ printf(" done\n");
fflush(stdout);
- dumpTrace();
+ int outFd = STDOUT_FILENO;
+ if (g_outputFile) {
+ outFd = open(g_outputFile, O_WRONLY | O_CREAT);
+ }
+ if (outFd == -1) {
+ printf("Failed to open '%s', err=%d", g_outputFile, errno);
+ } else {
+ dprintf(outFd, "TRACE:\n");
+ dumpTrace(outFd);
+ if (g_outputFile) {
+ close(outFd);
+ }
+ }
} else {
printf("\ntrace aborted.\n");
fflush(stdout);
diff --git a/cmds/dumpstate/bugreport-format.md b/cmds/dumpstate/bugreport-format.md
index 484f97f..d7837ae 100644
--- a/cmds/dumpstate/bugreport-format.md
+++ b/cmds/dumpstate/bugreport-format.md
@@ -26,16 +26,16 @@
is a failure, in which case it reverts to the flat file that is zipped by
**Shell** and hence the end result is the _v0_ format).
-The zip file is by default called _bugreport-DATE.zip_ and it contains a
-_bugreport-DATE.txt_ entry, although the end user can change the name (through
-**Shell**), in which case they would be called _bugreport-NEW_NAME.zip_ and
-_bugreport-NEW_NAME.txt_ respectively.
+The zip file is by default called _bugreport-BUILD_ID-DATE.zip_ and it contains a
+_bugreport-BUILD_ID-DATE.txt_ entry, although the end user can change the name (through
+**Shell**), in which case they would be called _bugreport-BUILD_ID-NEW_NAME.zip_ and
+_bugreport-BUILD_ID-NEW_NAME.txt_ respectively.
The zip file also contains 2 metadata entries generated by `dumpstate`:
- `version.txt`: whose value is **v1**.
- `main-entry.txt`: whose value is the name of the flat text entry (i.e.,
- _bugreport-DATE.txt_ or _bugreport-NEW_NAME.txt_).
+ _bugreport-BUILD_ID-DATE.txt_ or _bugreport-NEW_NAME.txt_).
`dumpstate` can also copy files from the device’s filesystem into the zip file
under the `FS` folder. For example, a `/dirA/dirB/fileC` file in the device
@@ -62,9 +62,9 @@
For example, the initial version during _Android N_ development was
**v1-dev1**. When `dumpsys` was split in 2 sections but not all tools were
-ready to parse that format, the version was named **v1-dev1-dumpsys-split**,
+ready to parse that format, the version was named **v1-dev2**,
which had to be passed do `dumpsys` explicitly (i.e., trhough a
-`-V v1-dev1-dumpsys-split` argument). Once that format became stable and tools
+`-V v1-dev2` argument). Once that format became stable and tools
knew how to parse it, the default version became **v1-dev2**.
Similarly, if changes in the file format are made after the initial release of
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 30ddec3..f486e08 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -69,6 +69,7 @@
#define RAFT_DIR "/data/misc/raft/"
#define RECOVERY_DIR "/cache/recovery"
#define RECOVERY_DATA_DIR "/data/misc/recovery"
+#define LOGPERSIST_DATA_DIR "/data/misc/logd"
#define TOMBSTONE_DIR "/data/tombstones"
#define TOMBSTONE_FILE_PREFIX TOMBSTONE_DIR "/tombstone_"
/* Can accomodate a tombstone number up to 9999. */
@@ -92,6 +93,7 @@
*/
// TODO: change to "v1" before final N build
static std::string VERSION_DEFAULT = "v1-dev3";
+static std::string VERSION_BUILD_ON_NAME = "v1-dev4";
/* 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. */
@@ -169,11 +171,15 @@
closedir(d);
}
-static void dump_systrace() {
+static void dump_systrace(const std::string& systrace_path) {
if (!zip_writer) {
MYLOGD("Not dumping systrace because zip_writer is not set\n");
return;
}
+ if (systrace_path.empty()) {
+ MYLOGE("Not dumping systrace because path is empty\n");
+ return;
+ }
const char* path = "/sys/kernel/debug/tracing/tracing_on";
long int is_tracing;
if (read_file_as_long(path, &is_tracing)) {
@@ -184,28 +190,24 @@
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);
- // execl should never return, but if it did, we need to exit.
- MYLOGD("execl on '/system/bin/atrace --async_dump' failed: %s", strerror(errno));
- // Must call _exit (instead of exit), otherwise it will corrupt the zip file.
- _exit(EXIT_FAILURE);
+ MYLOGD("Running '/system/bin/atrace --async_dump -o %s', which can take several minutes",
+ systrace_path.c_str());
+ if (run_command("SYSTRACE", 120, "/system/bin/atrace", "--async_dump", "-o",
+ systrace_path.c_str(), NULL)) {
+ MYLOGE("systrace timed out, its zip entry will be incomplete\n");
+ // TODO: run_command tries to kill the process, but atrace doesn't die peacefully; ideally,
+ // we should call strace to stop itself, but there is no such option yet (just a
+ // --async_stop, which stops and dump
+ // if (run_command("SYSTRACE", 10, "/system/bin/atrace", "--kill", NULL)) {
+ // MYLOGE("could not stop systrace ");
+ // }
+ }
+ if (!add_zip_entry("systrace.txt", systrace_path)) {
+ MYLOGE("Unable to add systrace file %s to zip file\n", systrace_path.c_str());
} 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
+ if (remove(systrace_path.c_str())) {
+ MYLOGE("Error removing systrace file %s: %s", systrace_path.c_str(), strerror(errno));
+ }
}
}
@@ -939,8 +941,8 @@
" -B: send broadcast when finished (requires -o)\n"
" -P: send broadcast when started and update system properties on progress (requires -o and -B)\n"
" -R: take bugreport in remote mode (requires -o, -z, -d and -B, shouldn't be used with -P)\n"
- " -V: sets the bugreport format version (valid values: %s)\n",
- VERSION_DEFAULT.c_str());
+ " -V: sets the bugreport format version (valid values: %s, %s)\n",
+ VERSION_DEFAULT.c_str(), VERSION_BUILD_ON_NAME.c_str());
}
static void sigpipe_handler(int n) {
@@ -1092,7 +1094,7 @@
exit(1);
}
- if (version != VERSION_DEFAULT) {
+ if (version != VERSION_DEFAULT && version != VERSION_BUILD_ON_NAME) {
usage();
exit(1);
}
@@ -1116,6 +1118,9 @@
/* full path of the file containing the dumpstate logs*/
std::string log_path;
+ /* full path of the systrace file, when enabled */
+ std::string systrace_path;
+
/* full path of the temporary file containing the screenshot (when requested) */
std::string screenshot_path;
@@ -1145,6 +1150,11 @@
} else {
suffix = "undated";
}
+ if (version == VERSION_BUILD_ON_NAME) {
+ char build_id[PROPERTY_VALUE_MAX];
+ property_get("ro.build.id", build_id, "UNKNOWN_BUILD");
+ base_name = base_name + "-" + build_id;
+ }
if (do_fb) {
// TODO: if dumpstate was an object, the paths could be internal variables and then
// we could have a function to calculate the derived values, such as:
@@ -1154,6 +1164,7 @@
tmp_path = bugreport_dir + "/" + base_name + "-" + suffix + ".tmp";
log_path = bugreport_dir + "/dumpstate_log-" + suffix + "-"
+ std::to_string(getpid()) + ".txt";
+ systrace_path = bugreport_dir + "/systrace-" + suffix + ".txt";
MYLOGD("Bugreport dir: %s\n"
"Base name: %s\n"
@@ -1248,7 +1259,7 @@
print_header(version);
// Dumps systrace right away, otherwise it will be filled with unnecessary events.
- dump_systrace();
+ dump_systrace(systrace_path);
// Invoking the following dumpsys calls before dump_traces() to try and
// keep the system stats as close to its initial state as possible.
@@ -1262,6 +1273,7 @@
get_tombstone_fds(tombstone_data);
add_dir(RECOVERY_DIR, true);
add_dir(RECOVERY_DATA_DIR, true);
+ add_dir(LOGPERSIST_DATA_DIR, false);
add_mountinfo();
if (!drop_root_user()) {
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 943f38e..baba0f9 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -109,10 +109,14 @@
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, ...);
+enum RootMode { DROP_ROOT, DONT_DROP_ROOT };
+enum StdoutMode { NORMAL_STDOUT, REDIRECT_TO_STDERR };
+
/* 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, bool drop_root, int timeout_seconds, const char *args[]);
+int run_command_always(const char *title, RootMode root_mode, StdoutMode stdout_mode,
+ int timeout_seconds, const char *args[]);
/* switch to non-root user and group */
bool drop_root_user();
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 8c0e840..d9738bb 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -664,7 +664,7 @@
ON_DRY_RUN({ update_progress(timeout_seconds); va_end(ap); return 0; });
- int status = run_command_always(title, false, timeout_seconds, args);
+ int status = run_command_always(title, DONT_DROP_ROOT, NORMAL_STDOUT, timeout_seconds, args);
va_end(ap);
return status;
}
@@ -701,13 +701,15 @@
ON_DRY_RUN({ update_progress(timeout_seconds); va_end(ap); return 0; });
- int status = run_command_always(title, true, timeout_seconds, args);
+ int status = run_command_always(title, DROP_ROOT, NORMAL_STDOUT, timeout_seconds, args);
va_end(ap);
return status;
}
/* forks a command and waits for it to finish */
-int run_command_always(const char *title, bool drop_root, int timeout_seconds, const char *args[]) {
+int run_command_always(const char *title, RootMode root_mode, StdoutMode stdout_mode,
+ int timeout_seconds, const char *args[]) {
+ bool silent = (stdout_mode == REDIRECT_TO_STDERR);
// TODO: need to check if args is null-terminated, otherwise execvp will crash dumpstate
/* TODO: for now we're simplifying the progress calculation by using the timeout as the weight.
@@ -721,17 +723,25 @@
/* handle error case */
if (pid < 0) {
- printf("*** fork: %s\n", strerror(errno));
+ if (!silent) printf("*** fork: %s\n", strerror(errno));
+ MYLOGE("*** fork: %s\n", strerror(errno));
return pid;
}
/* 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));
+ if (root_mode == DROP_ROOT && !drop_root_user()) {
+ if (!silent) printf("*** fail todrop root before running %s: %s\n", command,
+ strerror(errno));
+ MYLOGE("*** could not drop root before running %s: %s\n", command, strerror(errno));
return -1;
}
+ if (silent) {
+ // Redirect stderr to stdout
+ dup2(STDERR_FILENO, STDOUT_FILENO);
+ }
+
/* make sure the child dies when dumpstate dies */
prctl(PR_SET_PDEATHSIG, SIGKILL);
@@ -758,14 +768,14 @@
if (!ret) {
if (errno == ETIMEDOUT) {
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);
+ if (!silent) 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 {
format_args(command, args, &cmd);
- printf("*** command '%s': Error after %.4fs (killing pid %d)\n", cmd.c_str(),
- (float) elapsed / NANOS_PER_SEC, pid);
+ if (!silent) 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);
}
@@ -773,22 +783,25 @@
if (!waitpid_with_timeout(pid, 5, NULL)) {
kill(pid, SIGKILL);
if (!waitpid_with_timeout(pid, 5, NULL)) {
- 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);
+ if (!silent) printf("could not kill command '%s' (pid %d) even with SIGKILL.\n",
+ command, pid);
+ MYLOGE("could 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));
+ if (!silent) 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)) {
- printf("*** %s: Killed by signal %d\n", command, WTERMSIG(status));
+ if (!silent) printf("*** %s: Killed by signal %d\n", command, WTERMSIG(status));
+ MYLOGE("*** %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 (!silent) printf("*** %s: Exit code %d\n", command, WEXITSTATUS(status));
+ MYLOGE("*** %s: Exit code %d\n", command, WEXITSTATUS(status));
}
if (weight > 0) {
@@ -859,7 +872,7 @@
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, true, 20, am_args);
+ run_command_always(NULL, DROP_ROOT, REDIRECT_TO_STDERR, 20, am_args);
}
size_t num_props = 0;
@@ -1198,7 +1211,7 @@
void take_screenshot(const std::string& path) {
const char *args[] = { "/system/bin/screencap", "-p", path.c_str(), NULL };
- run_command_always(NULL, false, 10, args);
+ run_command_always(NULL, DONT_DROP_ROOT, REDIRECT_TO_STDERR, 10, args);
}
void vibrate(FILE* vibrator, int ms) {
diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp
index ff5a3b8..95bc4b9 100644
--- a/cmds/installd/commands.cpp
+++ b/cmds/installd/commands.cpp
@@ -161,43 +161,75 @@
return StringPrintf("%s/%s", profile_dir.c_str(), PRIMARY_PROFILE_NAME);
}
-static bool unlink_reference_profile(const char* pkgname) {
+static bool clear_profile(const std::string& profile) {
+ fd_t fd = open(profile.c_str(), O_WRONLY | O_NOFOLLOW);
+ if (fd < 0) {
+ if (errno != ENOENT) {
+ PLOG(WARNING) << "Could not open profile " << profile;
+ return false;
+ } else {
+ // Nothing to clear. That's ok.
+ return true;
+ }
+ }
+
+ if (flock(fd, LOCK_EX | LOCK_NB) != 0) {
+ if (errno != EWOULDBLOCK) {
+ PLOG(WARNING) << "Error locking profile " << profile;
+ }
+ // This implies that the app owning this profile is running
+ // (and has acquired the lock).
+ //
+ // If we can't acquire the lock bail out since clearing is useless anyway
+ // (the app will write again to the profile).
+ //
+ // Note:
+ // This does not impact the this is not an issue for the profiling correctness.
+ // In case this is needed because of an app upgrade, profiles will still be
+ // eventually cleared by the app itself due to checksum mismatch.
+ // If this is needed because profman advised, then keeping the data around
+ // until the next run is again not an issue.
+ //
+ // If the app attempts to acquire a lock while we've held one here,
+ // it will simply skip the current write cycle.
+ return false;
+ }
+
+ bool truncated = ftruncate(fd, 0) == 0;
+ if (!truncated) {
+ PLOG(WARNING) << "Could not truncate " << profile;
+ }
+ if (flock(fd, LOCK_UN) != 0) {
+ PLOG(WARNING) << "Error unlocking profile " << profile;
+ }
+ return truncated;
+}
+
+static bool clear_reference_profile(const char* pkgname) {
std::string reference_profile_dir = create_data_ref_profile_package_path(pkgname);
std::string reference_profile = create_primary_profile(reference_profile_dir);
- if (unlink(reference_profile.c_str()) != 0) {
- if (errno != ENOENT) {
- PLOG(WARNING) << "Could not unlink " << reference_profile;
- return false;
- }
- }
- return true;
+ return clear_profile(reference_profile);
}
-static bool unlink_current_profile(const char* pkgname, userid_t user) {
+static bool clear_current_profile(const char* pkgname, userid_t user) {
std::string profile_dir = create_data_user_profile_package_path(user, pkgname);
std::string profile = create_primary_profile(profile_dir);
- if (unlink(profile.c_str()) != 0) {
- if (errno != ENOENT) {
- PLOG(WARNING) << "Could not unlink " << profile;
- return false;
- }
- }
- return true;
+ return clear_profile(profile);
}
-static bool unlink_current_profiles(const char* pkgname) {
+static bool clear_current_profiles(const char* pkgname) {
bool success = true;
std::vector<userid_t> users = get_known_users(/*volume_uuid*/ nullptr);
for (auto user : users) {
- success &= unlink_current_profile(pkgname, user);
+ success &= clear_current_profile(pkgname, user);
}
return success;
}
int clear_app_profiles(const char* pkgname) {
bool success = true;
- success &= unlink_reference_profile(pkgname);
- success &= unlink_current_profiles(pkgname);
+ success &= clear_reference_profile(pkgname);
+ success &= clear_current_profiles(pkgname);
return success ? 0 : -1;
}
@@ -226,7 +258,7 @@
delete_dir_contents(path);
}
if (!only_cache) {
- if (!unlink_current_profile(pkgname, userid)) {
+ if (!clear_current_profile(pkgname, userid)) {
res |= -1;
}
}
@@ -234,6 +266,12 @@
return res;
}
+static int destroy_app_reference_profile(const char *pkgname) {
+ return delete_dir_contents_and_dir(
+ create_data_ref_profile_package_path(pkgname),
+ /*ignore_if_missing*/ true);
+}
+
static int destroy_app_current_profiles(const char *pkgname, userid_t userid) {
return delete_dir_contents_and_dir(
create_data_user_profile_package_path(userid, pkgname),
@@ -246,9 +284,7 @@
for (auto user : users) {
result |= destroy_app_current_profiles(pkgname, user);
}
- result |= delete_dir_contents_and_dir(
- create_data_ref_profile_package_path(pkgname),
- /*ignore_if_missing*/ true);
+ result |= destroy_app_reference_profile(pkgname);
return result;
}
@@ -262,6 +298,10 @@
res |= delete_dir_contents_and_dir(
create_data_user_de_package_path(uuid, userid, pkgname));
destroy_app_current_profiles(pkgname, userid);
+ // TODO(calin): If the package is still installed by other users it's probably
+ // beneficial to keep the reference profile around.
+ // Verify if it's ok to do that.
+ destroy_app_reference_profile(pkgname);
}
return res;
}
@@ -1192,8 +1232,8 @@
/* parent */
int return_code = wait_child(pid);
bool need_to_compile = false;
- bool delete_current_profiles = false;
- bool delete_reference_profile = false;
+ bool should_clear_current_profiles = false;
+ bool should_clear_reference_profile = false;
if (!WIFEXITED(return_code)) {
LOG(WARNING) << "profman failed for package " << pkgname << ": " << return_code;
} else {
@@ -1201,35 +1241,35 @@
switch (return_code) {
case PROFMAN_BIN_RETURN_CODE_COMPILE:
need_to_compile = true;
- delete_current_profiles = true;
- delete_reference_profile = false;
+ should_clear_current_profiles = true;
+ should_clear_reference_profile = false;
break;
case PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION:
need_to_compile = false;
- delete_current_profiles = false;
- delete_reference_profile = false;
+ should_clear_current_profiles = false;
+ should_clear_reference_profile = false;
break;
case PROFMAN_BIN_RETURN_CODE_BAD_PROFILES:
LOG(WARNING) << "Bad profiles for package " << pkgname;
need_to_compile = false;
- delete_current_profiles = true;
- delete_reference_profile = true;
+ should_clear_current_profiles = true;
+ should_clear_reference_profile = true;
break;
case PROFMAN_BIN_RETURN_CODE_ERROR_IO: // fall-through
case PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING:
// Temporary IO problem (e.g. locking). Ignore but log a warning.
LOG(WARNING) << "IO error while reading profiles for package " << pkgname;
need_to_compile = false;
- delete_current_profiles = false;
- delete_reference_profile = false;
+ should_clear_current_profiles = false;
+ should_clear_reference_profile = false;
break;
default:
// Unknown return code or error. Unlink profiles.
LOG(WARNING) << "Unknown error code while processing profiles for package " << pkgname
<< ": " << return_code;
need_to_compile = false;
- delete_current_profiles = true;
- delete_reference_profile = true;
+ should_clear_current_profiles = true;
+ should_clear_reference_profile = true;
break;
}
}
@@ -1237,11 +1277,11 @@
if (close(reference_profile_fd) != 0) {
PLOG(WARNING) << "Failed to close fd for reference profile";
}
- if (delete_current_profiles) {
- unlink_current_profiles(pkgname);
+ if (should_clear_current_profiles) {
+ clear_current_profiles(pkgname);
}
- if (delete_reference_profile) {
- unlink_reference_profile(pkgname);
+ if (should_clear_reference_profile) {
+ clear_reference_profile(pkgname);
}
return need_to_compile;
}
@@ -1423,9 +1463,9 @@
// Use app images only if it is enabled (by a set image format) and we are compiling
// profile-guided (so the app image doesn't conservatively contain all classes).
if (profile_guided && have_app_image_format) {
- // Recreate is false since we want to avoid deleting the image in case dex2oat decides to
- // not compile anything.
- image_fd = open_output_file(image_path, /*recreate*/false);
+ // Recreate is true since we do not want to modify a mapped image. If the app is already
+ // running and we modify the image file, it can cause crashes (b/27493510).
+ image_fd = open_output_file(image_path, /*recreate*/true);
if (image_fd < 0) {
// Could not create application image file. Go on since we can compile without it.
ALOGE("installd could not create '%s' for image file during dexopt\n", image_path);
@@ -1511,7 +1551,7 @@
close(reference_profile_fd);
// We failed to compile. Unlink the reference profile. Current profiles are already unlinked
// when profmoan advises compilation.
- unlink_reference_profile(pkgname);
+ clear_reference_profile(pkgname);
}
if (swap_fd >= 0) {
close(swap_fd);
diff --git a/include/media/openmax/OMX_VideoExt.h b/include/media/openmax/OMX_VideoExt.h
index 1a2f0b5..e11f569 100644
--- a/include/media/openmax/OMX_VideoExt.h
+++ b/include/media/openmax/OMX_VideoExt.h
@@ -252,12 +252,13 @@
/** Dolby Vision Profile enum type */
typedef enum OMX_VIDEO_DOLBYVISIONPROFILETYPE {
OMX_VIDEO_DolbyVisionProfileUnknown = 0x0,
- OMX_VIDEO_DolbyVisionProfileDvavDer = 0x1,
- OMX_VIDEO_DolbyVisionProfileDvavDen = 0x2,
- OMX_VIDEO_DolbyVisionProfileDvheDer = 0x3,
- OMX_VIDEO_DolbyVisionProfileDvheDen = 0x4,
- OMX_VIDEO_DolbyVisionProfileDvheDtr = 0x5,
- OMX_VIDEO_DolbyVisionProfileDvheStn = 0x6,
+ OMX_VIDEO_DolbyVisionProfileDvavPer = 0x1,
+ OMX_VIDEO_DolbyVisionProfileDvavPen = 0x2,
+ OMX_VIDEO_DolbyVisionProfileDvheDer = 0x4,
+ OMX_VIDEO_DolbyVisionProfileDvheDen = 0x8,
+ OMX_VIDEO_DolbyVisionProfileDvheDtr = 0x10,
+ OMX_VIDEO_DolbyVisionProfileDvheStn = 0x20,
+ OMX_VIDEO_DolbyVisionProfileDvheDth = 0x40,
OMX_VIDEO_DolbyVisionProfileMax = 0x7FFFFFFF
} OMX_VIDEO_DOLBYVISIONPROFILETYPE;
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 66ef4eb..fb1ebcf 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -65,12 +65,10 @@
SensorService::SensorService()
: mInitCheck(NO_INIT), mSocketBufferSize(SOCKET_BUFFER_SIZE_NON_BATCHED),
- mWakeLockAcquired(false)
-{
+ mWakeLockAcquired(false) {
}
-void SensorService::onFirstRef()
-{
+void SensorService::onFirstRef() {
ALOGD("nuSensorService starting...");
SensorDevice& dev(SensorDevice::getInstance());
@@ -78,6 +76,10 @@
sensor_t const* list;
ssize_t count = dev.getSensorList(&list);
if (count > 0) {
+ // this is the only place besides the dynamic sensor register and unregister functions
+ // where write operation to various sensor lists has to be locked.
+ Mutex::Autolock _l(mSensorsLock);
+
ssize_t orientationIndex = -1;
bool hasGyro = false, hasAccel = false, hasMag = false;
uint32_t virtualSensorsNeeds =
@@ -244,9 +246,14 @@
}
}
-Sensor SensorService::registerSensor(SensorInterface* s)
-{
+Sensor SensorService::registerSensor(SensorInterface* s) {
+ //caller of this function has to make sure mSensorsLock is locked
+ assert(mSensorsLock.tryLock() != 0);
+
const Sensor sensor(s->getSensor());
+
+ // add handle to used handle list
+ mUsedHandleList.add(sensor.getHandle());
// add to the sensor list (returned to clients)
mSensorList.add(sensor);
// add to our handle->SensorInterface mapping
@@ -257,17 +264,25 @@
return sensor;
}
-Sensor SensorService::registerDynamicSensor(SensorInterface* s)
-{
+Sensor SensorService::registerDynamicSensor(SensorInterface* s) {
+ Mutex::Autolock _l(mSensorsLock);
+
Sensor sensor = registerSensor(s);
mDynamicSensorList.add(sensor);
+
+ auto compareSensorHandle = [] (const Sensor* lhs, const Sensor* rhs) {
+ return lhs->getHandle() - rhs->getHandle();
+ };
+ mDynamicSensorList.sort(compareSensorHandle);
return sensor;
}
bool SensorService::unregisterDynamicSensor(int handle) {
+ Mutex::Autolock _l(mSensorsLock);
+
bool found = false;
- for (size_t i=0 ; i<mSensorList.size() ; i++) {
+ for (size_t i = 0 ; i < mSensorList.size() ; i++) {
if (mSensorList[i].getHandle() == handle) {
mSensorList.removeAt(i);
found = true;
@@ -276,7 +291,7 @@
}
if (found) {
- for (size_t i=0 ; i<mDynamicSensorList.size() ; i++) {
+ for (size_t i = 0 ; i < mDynamicSensorList.size() ; i++) {
if (mDynamicSensorList[i].getHandle() == handle) {
mDynamicSensorList.removeAt(i);
}
@@ -288,21 +303,30 @@
return found;
}
-Sensor SensorService::registerVirtualSensor(SensorInterface* s)
-{
+Sensor SensorService::registerVirtualSensor(SensorInterface* s) {
Sensor sensor = registerSensor(s);
mVirtualSensorList.add( s );
return sensor;
}
-SensorService::~SensorService()
-{
- for (size_t i=0 ; i<mSensorMap.size() ; i++)
- delete mSensorMap.valueAt(i);
+bool SensorService::isNewHandle(int handle) {
+ Mutex::Autolock _l(mSensorsLock);
+ for (int h : mUsedHandleList) {
+ if (h == handle) {
+ return false;
+ }
+ }
+ return true;
}
-status_t SensorService::dump(int fd, const Vector<String16>& args)
-{
+SensorService::~SensorService() {
+ Mutex::Autolock _l(mSensorsLock);
+ for (size_t i=0 ; i<mSensorMap.size() ; i++) {
+ delete mSensorMap.valueAt(i);
+ }
+}
+
+status_t SensorService::dump(int fd, const Vector<String16>& args) {
String8 result;
if (!PermissionCache::checkCallingPermission(sDump)) {
result.appendFormat("Permission Denial: can't dump SensorService from pid=%d, uid=%d\n",
@@ -368,6 +392,7 @@
} else {
// Default dump the sensor list and debugging information.
result.append("Sensor List:\n");
+ Mutex::Autolock _l(mSensorsLock);
for (size_t i=0 ; i<mSensorList.size() ; i++) {
const Sensor& s(mSensorList[i]);
result.appendFormat(
@@ -505,7 +530,7 @@
handle = buffer[i].meta_data.sensor;
}
if (connection->hasSensor(handle)) {
- SensorInterface* sensor = mSensorMap.valueFor(handle);
+ SensorInterface* sensor = getSensorInterfaceFromHandle(handle);
// If this buffer has an event from a one_shot sensor and this connection is registered
// for this particular one_shot sensor, try cleaning up the connection.
if (sensor != NULL &&
@@ -518,8 +543,7 @@
}
}
-bool SensorService::threadLoop()
-{
+bool SensorService::threadLoop() {
ALOGD("nuSensorService thread starting...");
// each virtual sensor could generate an event per "real" event, that's why we need to size
@@ -646,9 +670,21 @@
ALOGI("Dynamic sensor handle 0x%x connected, type %d, name %s",
handle, dynamicSensor.type, dynamicSensor.name);
- device.handleDynamicSensorConnection(handle, true /*connected*/);
- registerDynamicSensor(new HardwareSensor(dynamicSensor));
+ if (isNewHandle(handle)) {
+ sensor_t s = dynamicSensor;
+ // make sure the dynamic sensor flag is set
+ s.flags |= DYNAMIC_SENSOR_MASK;
+ // force the handle to be consistent
+ s.handle = handle;
+ SensorInterface *si = new HardwareSensor(s);
+ // This will release hold on dynamic sensor meta, so it should be called after
+ // Sensor object is created.
+ device.handleDynamicSensorConnection(handle, true /*connected*/);
+ registerDynamicSensor(si);
+ } else {
+ ALOGE("Handle %d has been used, cannot use again before reboot.", handle);
+ }
} else {
int handle = mSensorEventBuffer[i].dynamic_sensor_meta.handle;
ALOGI("Dynamic sensor handle 0x%x disconnected", handle);
@@ -768,8 +804,7 @@
}
}
-void SensorService::sortEventBuffer(sensors_event_t* buffer, size_t count)
-{
+void SensorService::sortEventBuffer(sensors_event_t* buffer, size_t count) {
struct compar {
static int cmp(void const* lhs, void const* rhs) {
sensors_event_t const* l = static_cast<sensors_event_t const*>(lhs);
@@ -781,6 +816,7 @@
}
String8 SensorService::getSensorName(int handle) const {
+ Mutex::Autolock _l(mSensorsLock);
size_t count = mUserSensorList.size();
for (size_t i=0 ; i<count ; i++) {
const Sensor& sensor(mUserSensorList[i]);
@@ -788,12 +824,11 @@
return sensor.getName();
}
}
- String8 result("unknown");
- return result;
+ return String8("unknown");
}
bool SensorService::isVirtualSensor(int handle) const {
- SensorInterface* sensor = mSensorMap.valueFor(handle);
+ SensorInterface* sensor = getSensorInterfaceFromHandle(handle);
return sensor != NULL && sensor->isVirtual();
}
@@ -802,7 +837,7 @@
if (event.type == SENSOR_TYPE_META_DATA) {
handle = event.meta_data.sensor;
}
- SensorInterface* sensor = mSensorMap.valueFor(handle);
+ SensorInterface* sensor = getSensorInterfaceFromHandle(handle);
return sensor != NULL && sensor->getSensor().isWakeUpSensor();
}
@@ -810,8 +845,9 @@
return mActiveSensors.valueFor(handle);
}
-Vector<Sensor> SensorService::getSensorList(const String16& opPackageName)
-{
+Vector<Sensor> SensorService::getSensorList(const String16& opPackageName) {
+ Mutex::Autolock _l(mSensorsLock);
+
char value[PROPERTY_VALUE_MAX];
property_get("debug.sensors", value, "0");
const Vector<Sensor>& initialSensorList = (atoi(value)) ?
@@ -831,8 +867,9 @@
return accessibleSensorList;
}
-Vector<Sensor> SensorService::getDynamicSensorList(const String16& opPackageName)
-{
+Vector<Sensor> SensorService::getDynamicSensorList(const String16& opPackageName) {
+ Mutex::Autolock _l(mSensorsLock);
+
Vector<Sensor> accessibleSensorList;
for (size_t i = 0; i < mDynamicSensorList.size(); i++) {
Sensor sensor = mDynamicSensorList[i];
@@ -895,8 +932,7 @@
return err;
}
-void SensorService::cleanupConnection(SensorEventConnection* c)
-{
+void SensorService::cleanupConnection(SensorEventConnection* c) {
Mutex::Autolock _l(mLock);
const wp<SensorEventConnection> connection(c);
size_t size = mActiveSensors.size();
@@ -905,7 +941,7 @@
int handle = mActiveSensors.keyAt(i);
if (c->hasSensor(handle)) {
ALOGD_IF(DEBUG_CONNECTIONS, "%zu: disabling handle=0x%08x", i, handle);
- SensorInterface* sensor = mSensorMap.valueFor( handle );
+ SensorInterface* sensor = getSensorInterfaceFromHandle(handle);
ALOGE_IF(!sensor, "mSensorMap[handle=0x%08x] is null!", handle);
if (sensor) {
sensor->activate(c, false);
@@ -936,18 +972,24 @@
}
}
+SensorInterface* SensorService::getSensorInterfaceFromHandle(int handle) const {
+ Mutex::Autolock _l(mSensorsLock);
+ ssize_t index = mSensorMap.indexOfKey(handle);
+ return index < 0 ? nullptr : mSensorMap.valueAt(index);
+}
+
Sensor SensorService::getSensorFromHandle(int handle) const {
- return mSensorMap.valueFor(handle)->getSensor();
+ SensorInterface* si = getSensorInterfaceFromHandle(handle);
+ return si ? si->getSensor() : Sensor();
}
status_t SensorService::enable(const sp<SensorEventConnection>& connection,
int handle, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags,
- const String16& opPackageName)
-{
+ const String16& opPackageName) {
if (mInitCheck != NO_ERROR)
return mInitCheck;
- SensorInterface* sensor = mSensorMap.valueFor(handle);
+ SensorInterface* sensor = getSensorInterfaceFromHandle(handle);
if (sensor == NULL) {
return BAD_VALUE;
}
@@ -1073,16 +1115,14 @@
return err;
}
-status_t SensorService::disable(const sp<SensorEventConnection>& connection,
- int handle)
-{
+status_t SensorService::disable(const sp<SensorEventConnection>& connection, int handle) {
if (mInitCheck != NO_ERROR)
return mInitCheck;
Mutex::Autolock _l(mLock);
status_t err = cleanupWithoutDisableLocked(connection, handle);
if (err == NO_ERROR) {
- SensorInterface* sensor = mSensorMap.valueFor(handle);
+ SensorInterface* sensor = getSensorInterfaceFromHandle(handle);
err = sensor ? sensor->activate(connection.get(), false) : status_t(BAD_VALUE);
}
@@ -1132,12 +1172,11 @@
}
status_t SensorService::setEventRate(const sp<SensorEventConnection>& connection,
- int handle, nsecs_t ns, const String16& opPackageName)
-{
+ int handle, nsecs_t ns, const String16& opPackageName) {
if (mInitCheck != NO_ERROR)
return mInitCheck;
- SensorInterface* sensor = mSensorMap.valueFor(handle);
+ SensorInterface* sensor = getSensorInterfaceFromHandle(handle);
if (!sensor)
return BAD_VALUE;
@@ -1166,7 +1205,7 @@
// Loop through all sensors for this connection and call flush on each of them.
for (size_t i = 0; i < connection->mSensorInfo.size(); ++i) {
const int handle = connection->mSensorInfo.keyAt(i);
- SensorInterface* sensor = mSensorMap.valueFor(handle);
+ SensorInterface* sensor = getSensorInterfaceFromHandle(handle);
if (sensor->getSensor().getReportingMode() == AREPORTING_MODE_ONE_SHOT) {
ALOGE("flush called on a one-shot sensor");
err = INVALID_OPERATION;
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index ef4516b..35f6f3d 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -160,6 +160,7 @@
static int getNumEventsForSensorType(int sensor_event_type);
String8 getSensorName(int handle) const;
bool isVirtualSensor(int handle) const;
+ SensorInterface* getSensorInterfaceFromHandle(int handle) const;
Sensor getSensorFromHandle(int handle) const;
bool isWakeUpSensor(int type) const;
void recordLastValueLocked(sensors_event_t const* buffer, size_t count);
@@ -181,6 +182,7 @@
void checkWakeLockStateLocked();
bool isWakeLockAcquired();
bool isWakeUpSensorEvent(const sensors_event_t& event) const;
+ bool isNewHandle(int handle);
SensorRecord * getSensorRecord(int handle);
@@ -211,13 +213,15 @@
status_t resetToNormalMode();
status_t resetToNormalModeLocked();
- // constants
+ // lists and maps
+ mutable Mutex mSensorsLock;
Vector<Sensor> mSensorList;
Vector<Sensor> mUserSensorListDebug;
Vector<Sensor> mUserSensorList;
Vector<Sensor> mDynamicSensorList;
DefaultKeyedVector<int, SensorInterface*> mSensorMap;
Vector<SensorInterface *> mVirtualSensorList;
+ Vector<int> mUsedHandleList;
status_t mInitCheck;
// Socket buffersize used to initialize BitTube. This size depends on whether batching is
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index d0a0401..44a3334 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -40,7 +40,7 @@
LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\"
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-
+#LOCAL_CFLAGS += -DENABLE_FENCE_TRACKING
USE_HWC2 := false
ifeq ($(USE_HWC2),true)
diff --git a/services/surfaceflinger/FenceTracker.cpp b/services/surfaceflinger/FenceTracker.cpp
index 7da1d93..885d712 100644
--- a/services/surfaceflinger/FenceTracker.cpp
+++ b/services/surfaceflinger/FenceTracker.cpp
@@ -14,9 +14,12 @@
* limitations under the License.
*/
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include <inttypes.h>
#include "FenceTracker.h"
#include "Layer.h"
+#include <utils/Trace.h>
namespace android {
@@ -78,6 +81,7 @@
}
void FenceTracker::checkFencesForCompletion() {
+ ATRACE_CALL();
for (auto& frame : mFrames) {
if (frame.retireFence != Fence::NO_FENCE) {
nsecs_t time = frame.retireFence->getSignalTime();
@@ -115,6 +119,7 @@
void FenceTracker::addFrame(nsecs_t refreshStartTime, sp<Fence> retireFence,
const Vector<sp<Layer>>& layers, sp<Fence> glDoneFence) {
+ ATRACE_CALL();
Mutex::Autolock lock(mMutex);
FrameRecord& frame = mFrames[mOffset];
FrameRecord& prevFrame = mFrames[(mOffset + MAX_FRAME_HISTORY - 1) %
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 9b43849..ea9fe21 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -910,7 +910,11 @@
void SurfaceFlinger::handleMessageRefresh() {
ATRACE_CALL();
+#ifdef ENABLE_FENCE_TRACKING
nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+#else
+ nsecs_t refreshStartTime = 0;
+#endif
static nsecs_t previousExpectedPresent = 0;
nsecs_t expectedPresent = mPrimaryDispSync.computeNextRefresh(0);
static bool previousFrameMissed = false;
@@ -1000,7 +1004,11 @@
}
}
+#ifdef ENABLE_FENCE_TRACKING
void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
+#else
+void SurfaceFlinger::postComposition(nsecs_t /*refreshStartTime*/)
+#endif
{
ATRACE_CALL();
ALOGV("postComposition");
@@ -1028,8 +1036,10 @@
}
}
+#ifdef ENABLE_FENCE_TRACKING
mFenceTracker.addFrame(refreshStartTime, presentFence,
hw->getVisibleLayersSortedByZ(), hw->getClientTargetAcquireFence());
+#endif
if (mAnimCompositionPending) {
mAnimCompositionPending = false;
@@ -2548,12 +2558,14 @@
dumpAll = false;
}
+#ifdef ENABLE_FENCE_TRACKING
if ((index < numArgs) &&
(args[index] == String16("--fences"))) {
index++;
mFenceTracker.dump(&result);
dumpAll = false;
}
+#endif
}
if (dumpAll) {
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 11f19d0..a63ec50 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -927,7 +927,11 @@
void SurfaceFlinger::handleMessageRefresh() {
ATRACE_CALL();
+#ifdef ENABLE_FENCE_TRACKING
nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+#else
+ nsecs_t refreshStartTime = 0;
+#endif
static nsecs_t previousExpectedPresent = 0;
nsecs_t expectedPresent = mPrimaryDispSync.computeNextRefresh(0);
static bool previousFrameMissed = false;
@@ -1009,7 +1013,11 @@
}
}
+#ifdef ENABLE_FENCE_TRACKING
void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
+#else
+void SurfaceFlinger::postComposition(nsecs_t /*refreshStartTime*/)
+#endif
{
const LayerVector& layers(mDrawingState.layersSortedByZ);
const size_t count = layers.size();
@@ -1035,8 +1043,10 @@
}
}
+#ifdef ENABLE_FENCE_TRACKING
mFenceTracker.addFrame(refreshStartTime, presentFence,
hw->getVisibleLayersSortedByZ(), hw->getClientTargetAcquireFence());
+#endif
if (mAnimCompositionPending) {
mAnimCompositionPending = false;
@@ -2586,12 +2596,14 @@
dumpAll = false;
}
+#ifdef ENABLE_FENCE_TRACKING
if ((index < numArgs) &&
(args[index] == String16("--fences"))) {
index++;
mFenceTracker.dump(&result);
dumpAll = false;
}
+#endif
}
if (dumpAll) {