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) {