Merge "Do not clean profiles unconditonally during app data clean up" 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..78da143 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,45 @@
     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);
+        // execl should never return, but if it did, we need to exit.
+        MYLOGD("execl on '/system/bin/atrace --async_dump' failed: %s", strerror(errno));
+        exit(EXIT_FAILURE);
+    } 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 +884,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 +1003,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 +1051,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 +1245,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 +1261,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..8129852 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,75 @@
     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;
+        }
+        // TODO: null_terminated check is not really working; line below would crash dumpstate if
+        // nullptr is missing
         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;
+        }
+        // TODO: null_terminated check is not really working; line below would crash dumpstate if
+        // nullptr is missing
+        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: 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.
      * 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 +727,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));
+            return -1;
+        }
 
         /* make sure the child dies when dumpstate dies */
         prctl(PR_SET_PDEATHSIG, SIGKILL);
@@ -661,31 +742,46 @@
         sigaction(SIGPIPE, &sigact, NULL);
 
         execvp(command, (char**) args);
-        printf("*** exec(%s): %s\n", command, strerror(errno));
+        // execvp's result will be handled after waitpid_with_timeout() below, but if it failed,
+        // it's safer to exit dumpstate.
+        MYLOGD("execvp on command '%s' failed (error: %s)", command, strerror(errno));
         fflush(stdout);
-        _exit(-1);
+        exit(EXIT_FAILURE);
     }
 
     /* 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 +796,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, true, 20, am_args);
 }
 
 size_t num_props = 0;
@@ -1053,7 +1197,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 +1338,29 @@
     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(" ");
+        }
+    }
+    // TODO: not really working: if NULL is missing, it will crash dumpstate.
+    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..7e5bbc5 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,79 @@
     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()) ||
+            (showListOnly && (!services.empty() || !skippedServices.empty()))) {
+        usage();
+        return -1;
+    }
+
+    if (services.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 +209,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/commands.cpp b/cmds/installd/commands.cpp
index 53ff2d4..8350da7 100644
--- a/cmds/installd/commands.cpp
+++ b/cmds/installd/commands.cpp
@@ -732,7 +732,7 @@
 
 static void run_dex2oat(int zip_fd, int oat_fd, int image_fd, const char* input_file_name,
         const char* output_file_name, int swap_fd, const char *instruction_set,
-        bool vm_safe_mode, bool debuggable, bool post_bootcomplete, bool extract_only,
+        const char* compiler_filter, bool vm_safe_mode, bool debuggable, bool post_bootcomplete,
         int profile_fd) {
     static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
 
@@ -748,10 +748,6 @@
     char dex2oat_Xmx_flag[kPropertyValueMax];
     bool have_dex2oat_Xmx_flag = get_property("dalvik.vm.dex2oat-Xmx", dex2oat_Xmx_flag, NULL) > 0;
 
-    char dex2oat_compiler_filter_flag[kPropertyValueMax];
-    bool have_dex2oat_compiler_filter_flag = get_property("dalvik.vm.dex2oat-filter",
-                                                          dex2oat_compiler_filter_flag, NULL) > 0;
-
     char dex2oat_threads_buf[kPropertyValueMax];
     bool have_dex2oat_threads_flag = get_property(post_bootcomplete
                                                       ? "dalvik.vm.dex2oat-threads"
@@ -843,6 +839,10 @@
     if (have_dex2oat_Xmx_flag) {
         sprintf(dex2oat_Xmx_arg, "-Xmx%s", dex2oat_Xmx_flag);
     }
+
+    // Compute compiler filter.
+
+    bool have_dex2oat_compiler_filter_flag;
     if (skip_compilation) {
         strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=verify-none");
         have_dex2oat_compiler_filter_flag = true;
@@ -850,13 +850,20 @@
     } else if (vm_safe_mode) {
         strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=interpret-only");
         have_dex2oat_compiler_filter_flag = true;
-    } else if (extract_only) {
-        // Temporarily make extract-only mean interpret-only, so extracted files will be verified.
-        // b/26833007
-        strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=interpret-only");
+    } else if (compiler_filter != nullptr &&
+            strlen(compiler_filter) + strlen("--compiler-filter=") <
+                    arraysize(dex2oat_compiler_filter_arg)) {
+        sprintf(dex2oat_compiler_filter_arg, "--compiler-filter=%s", compiler_filter);
         have_dex2oat_compiler_filter_flag = true;
-    } else if (have_dex2oat_compiler_filter_flag) {
-        sprintf(dex2oat_compiler_filter_arg, "--compiler-filter=%s", dex2oat_compiler_filter_flag);
+    } else {
+        char dex2oat_compiler_filter_flag[kPropertyValueMax];
+        have_dex2oat_compiler_filter_flag = get_property("dalvik.vm.dex2oat-filter",
+                                                         dex2oat_compiler_filter_flag, NULL) > 0;
+        if (have_dex2oat_compiler_filter_flag) {
+            sprintf(dex2oat_compiler_filter_arg,
+                    "--compiler-filter=%s",
+                    dex2oat_compiler_filter_flag);
+        }
     }
 
     // Check whether all apps should be compiled debuggable.
@@ -1301,9 +1308,14 @@
     return true;
 }
 
+// TODO: Consider returning error codes.
+bool merge_profiles(uid_t uid, const char *pkgname) {
+    return analyse_profiles(uid, pkgname);
+}
+
 int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* instruction_set,
-           int dexopt_needed, const char* oat_dir, int dexopt_flags,
-           const char* volume_uuid ATTRIBUTE_UNUSED, bool use_profiles)
+           int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
+           const char* volume_uuid ATTRIBUTE_UNUSED)
 {
     struct utimbuf ut;
     struct stat input_stat;
@@ -1318,29 +1330,18 @@
     bool vm_safe_mode = (dexopt_flags & DEXOPT_SAFEMODE) != 0;
     bool debuggable = (dexopt_flags & DEXOPT_DEBUGGABLE) != 0;
     bool boot_complete = (dexopt_flags & DEXOPT_BOOTCOMPLETE) != 0;
-    bool extract_only = (dexopt_flags & DEXOPT_EXTRACTONLY) != 0;
+    bool profile_guided = (dexopt_flags & DEXOPT_PROFILE_GUIDED) != 0;
+
+    CHECK(pkgname != nullptr);
+    CHECK(pkgname[0] != 0);
+
     fd_t reference_profile_fd = -1;
-
-    if (is_public && use_profiles) {
-        // We should not give public access to apks compiled with profile information.
-        // Log an error and return early if are asked to do so.
-        ALOGE("use_profiles should not be used with is_public.");
-        return -1;
-    }
-
-    if (use_profiles) {
-        if (analyse_profiles(uid, pkgname)) {
-            // Open again reference profile in read only mode as dex2oat does not get write
-            // permissions.
-            reference_profile_fd = open_reference_profile(uid, pkgname, /*read_write*/ false);
-            if (reference_profile_fd == -1) {
-                PLOG(WARNING) << "Couldn't open reference profile in read only mode " << pkgname;
-                exit(72);
-            }
-        } else {
-            // No need to (re)compile. Return early.
-            return 0;
-        }
+    // Public apps should not be compiled with profile information ever. Same goes for the special
+    // package '*' used for the system server.
+    if (!is_public && pkgname[0] != '*') {
+        // Open reference profile in read only mode as dex2oat does not get write permissions.
+        reference_profile_fd = open_reference_profile(uid, pkgname, /*read_write*/ false);
+        // Note: it's OK to not find a profile here.
     }
 
     if ((dexopt_flags & ~DEXOPT_MASK) != 0) {
@@ -1415,7 +1416,9 @@
       char app_image_format[kPropertyValueMax];
       bool have_app_image_format =
               get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
-      if (!extract_only && have_app_image_format) {
+      // 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);
@@ -1458,7 +1461,7 @@
                 input_file_name++;
             }
             run_dex2oat(input_fd, out_fd, image_fd, input_file_name, out_path, swap_fd,
-                        instruction_set, vm_safe_mode, debuggable, boot_complete, extract_only,
+                        instruction_set, compiler_filter, vm_safe_mode, debuggable, boot_complete,
                         reference_profile_fd);
         } else {
             ALOGE("Invalid dexopt needed: %d\n", dexopt_needed);
diff --git a/cmds/installd/commands.h b/cmds/installd/commands.h
index 4e39664..13143c5 100644
--- a/cmds/installd/commands.h
+++ b/cmds/installd/commands.h
@@ -48,9 +48,12 @@
 int delete_user(const char *uuid, userid_t userid);
 int rm_dex(const char *path, const char *instruction_set);
 int free_cache(const char *uuid, int64_t free_size);
+
+bool merge_profiles(uid_t uid, const char *pkgname);
+
 int dexopt(const char *apk_path, uid_t uid, const char *pkgName, const char *instruction_set,
-           int dexopt_needed, const char* oat_dir, int dexopt_flags,
-           const char* volume_uuid, bool use_profiles);
+           int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
+           const char* volume_uuid);
 int mark_boot_complete(const char *instruction_set);
 int linklib(const char* uuid, const char* pkgname, const char* asecLibDir, int userId);
 int idmap(const char *target_path, const char *overlay_path, uid_t uid);
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/installd.cpp b/cmds/installd/installd.cpp
index 0bb0c3c..de3f54a 100644
--- a/cmds/installd/installd.cpp
+++ b/cmds/installd/installd.cpp
@@ -258,10 +258,27 @@
     if ((dexopt_flags & DEXOPT_OTA) != 0) {
       return do_ota_dexopt(arg, reply);
     }
-    /* apk_path, uid, pkgname, instruction_set, dexopt_needed, oat_dir, dexopt_flags, volume_uuid,
-            use_profiles */
-    return dexopt(arg[0], atoi(arg[1]), arg[2], arg[3], atoi(arg[4]),
-                  arg[5], dexopt_flags, parse_null(arg[7]), (atoi(arg[8]) == 0 ? false : true));
+    return dexopt(arg[0],                      // apk_path
+                  atoi(arg[1]),                // uid
+                  arg[2],                      // pkgname
+                  arg[3],                      // instruction_set
+                  atoi(arg[4]),                // dexopt_needed
+                  arg[5],                      // oat_dir
+                  dexopt_flags,
+                  arg[7],                      // compiler_filter
+                  parse_null(arg[8]));         // volume_uuid
+}
+
+static int do_merge_profiles(char **arg, char reply[REPLY_MAX])
+{
+    uid_t uid = static_cast<uid_t>(atoi(arg[0]));
+    const char* pkgname = arg[1];
+    if (merge_profiles(uid, pkgname)) {
+        strncpy(reply, "true", REPLY_MAX);
+    } else {
+        strncpy(reply, "false", REPLY_MAX);
+    }
+    return 0;
 }
 
 static int do_mark_boot_complete(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED)
@@ -395,6 +412,7 @@
     { "destroy_app_profiles", 1, do_destroy_app_profiles },
     { "linkfile",             3, do_link_file },
     { "move_ab",              3, do_move_ab },
+    { "merge_profiles",       2, do_merge_profiles },
 };
 
 static int readx(int s, void *_buf, int count)
diff --git a/cmds/installd/installd_constants.h b/cmds/installd/installd_constants.h
index 8f6e928..8513695 100644
--- a/cmds/installd/installd_constants.h
+++ b/cmds/installd/installd_constants.h
@@ -75,12 +75,12 @@
  * IMPORTANT: These values are passed from Java code. Keep them in sync with
  * frameworks/base/services/core/java/com/android/server/pm/Installer.java
  ***************************************************************************/
-constexpr int DEXOPT_PUBLIC       = 1 << 1;
-constexpr int DEXOPT_SAFEMODE     = 1 << 2;
-constexpr int DEXOPT_DEBUGGABLE   = 1 << 3;
-constexpr int DEXOPT_BOOTCOMPLETE = 1 << 4;
-constexpr int DEXOPT_EXTRACTONLY  = 1 << 5;
-constexpr int DEXOPT_OTA          = 1 << 6;
+constexpr int DEXOPT_PUBLIC         = 1 << 1;
+constexpr int DEXOPT_SAFEMODE       = 1 << 2;
+constexpr int DEXOPT_DEBUGGABLE     = 1 << 3;
+constexpr int DEXOPT_BOOTCOMPLETE   = 1 << 4;
+constexpr int DEXOPT_PROFILE_GUIDED = 1 << 5;
+constexpr int DEXOPT_OTA            = 1 << 6;
 
 /* all known values for dexopt flags */
 constexpr int DEXOPT_MASK =
@@ -88,7 +88,7 @@
     | DEXOPT_SAFEMODE
     | DEXOPT_DEBUGGABLE
     | DEXOPT_BOOTCOMPLETE
-    | DEXOPT_EXTRACTONLY
+    | DEXOPT_PROFILE_GUIDED
     | DEXOPT_OTA;
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index da454a7..245694a 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;
     }
@@ -341,17 +357,15 @@
     }
 
     int RunPreopt() {
-        /* apk_path, uid, pkgname, instruction_set, dexopt_needed, oat_dir, dexopt_flags,
-           volume_uuid, use_profiles */
-        int ret = dexopt(package_parameters_[0],
-                atoi(package_parameters_[1]),
-                package_parameters_[2],
-                package_parameters_[3],
-                atoi(package_parameters_[4]),
-                package_parameters_[5],
-                atoi(package_parameters_[6]),
-                ParseNull(package_parameters_[7]),
-                (atoi(package_parameters_[8]) == 0 ? false : true));
+        int ret = dexopt(package_parameters_[0],          // apk_path
+                atoi(package_parameters_[1]),             // uid
+                package_parameters_[2],                   // pkgname
+                package_parameters_[3],                   // instruction_set
+                atoi(package_parameters_[4]),             // dexopt_needed
+                package_parameters_[5],                   // oat_dir
+                atoi(package_parameters_[6]),             // dexopt_flags
+                package_parameters_[7],                   // compiler_filter
+                ParseNull(package_parameters_[8]));       // volume_uuid
         return ret;
     }
 
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/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h
index aa48718..794fe4c 100644
--- a/include/gui/SurfaceComposerClient.h
+++ b/include/gui/SurfaceComposerClient.h
@@ -133,6 +133,7 @@
     status_t    setPosition(const sp<IBinder>& id, float x, float y);
     status_t    setSize(const sp<IBinder>& id, uint32_t w, uint32_t h);
     status_t    setCrop(const sp<IBinder>& id, const Rect& crop);
+    status_t    setFinalCrop(const sp<IBinder>& id, const Rect& crop);
     status_t    setLayerStack(const sp<IBinder>& id, uint32_t layerStack);
     status_t    deferTransactionUntil(const sp<IBinder>& id,
             const sp<IBinder>& handle, uint64_t frameNumber);
diff --git a/include/gui/SurfaceControl.h b/include/gui/SurfaceControl.h
index 76ce68d..35644db 100644
--- a/include/gui/SurfaceControl.h
+++ b/include/gui/SurfaceControl.h
@@ -71,6 +71,7 @@
     status_t    setAlpha(float alpha=1.0f);
     status_t    setMatrix(float dsdx, float dtdx, float dsdy, float dtdy);
     status_t    setCrop(const Rect& crop);
+    status_t    setFinalCrop(const Rect& crop);
 
     // Defers applying any changes made in this transaction until the Layer
     // identified by handle reaches the given frameNumber
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/include/private/gui/LayerState.h b/include/private/gui/LayerState.h
index 5cf316f..078720a 100644
--- a/include/private/gui/LayerState.h
+++ b/include/private/gui/LayerState.h
@@ -52,14 +52,16 @@
         eFlagsChanged               = 0x00000040,
         eLayerStackChanged          = 0x00000080,
         eCropChanged                = 0x00000100,
-        eDeferTransaction           = 0x00000200
+        eDeferTransaction           = 0x00000200,
+        eFinalCropChanged           = 0x00000400
     };
 
     layer_state_t()
         :   what(0),
             x(0), y(0), z(0), w(0), h(0), layerStack(0),
             alpha(0), flags(0), mask(0),
-            reserved(0), crop(Rect::INVALID_RECT), frameNumber(0)
+            reserved(0), crop(Rect::INVALID_RECT),
+            finalCrop(Rect::INVALID_RECT), frameNumber(0)
     {
         matrix.dsdx = matrix.dtdy = 1.0f;
         matrix.dsdy = matrix.dtdx = 0.0f;
@@ -88,6 +90,7 @@
             uint8_t         reserved;
             matrix22_t      matrix;
             Rect            crop;
+            Rect            finalCrop;
             sp<IBinder>     handle;
             uint64_t        frameNumber;
             // non POD must be last. see write/read
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/LayerState.cpp b/libs/gui/LayerState.cpp
index 06f13e8..e43342e 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -38,6 +38,7 @@
     *reinterpret_cast<layer_state_t::matrix22_t *>(
             output.writeInplace(sizeof(layer_state_t::matrix22_t))) = matrix;
     output.write(crop);
+    output.write(finalCrop);
     output.writeStrongBinder(handle);
     output.writeUint64(frameNumber);
     output.write(transparentRegion);
@@ -64,6 +65,7 @@
         return BAD_VALUE;
     }
     input.read(crop);
+    input.read(finalCrop);
     handle = input.readStrongBinder();
     frameNumber = input.readUint64();
     input.read(transparentRegion);
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/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 3242f55..04b5446 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -156,6 +156,8 @@
     status_t setOrientation(int orientation);
     status_t setCrop(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
             const Rect& crop);
+    status_t setFinalCrop(const sp<SurfaceComposerClient>& client,
+            const sp<IBinder>& id, const Rect& crop);
     status_t setLayerStack(const sp<SurfaceComposerClient>& client,
             const sp<IBinder>& id, uint32_t layerStack);
     status_t deferTransactionUntil(const sp<SurfaceComposerClient>& client,
@@ -386,6 +388,18 @@
     return NO_ERROR;
 }
 
+status_t Composer::setFinalCrop(const sp<SurfaceComposerClient>& client,
+        const sp<IBinder>& id, const Rect& crop) {
+    Mutex::Autolock _l(mLock);
+    layer_state_t* s = getLayerStateLocked(client, id);
+    if (!s) {
+        return BAD_INDEX;
+    }
+    s->what |= layer_state_t::eFinalCropChanged;
+    s->finalCrop = crop;
+    return NO_ERROR;
+}
+
 status_t Composer::deferTransactionUntil(
         const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
         const sp<IBinder>& handle, uint64_t frameNumber) {
@@ -579,6 +593,11 @@
     return getComposer().setCrop(this, id, crop);
 }
 
+status_t SurfaceComposerClient::setFinalCrop(const sp<IBinder>& id,
+        const Rect& crop) {
+    return getComposer().setFinalCrop(this, id, crop);
+}
+
 status_t SurfaceComposerClient::setPosition(const sp<IBinder>& id, float x, float y) {
     return getComposer().setPosition(this, id, x, y);
 }
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index e1a951c..184de71 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -152,6 +152,11 @@
     if (err < 0) return err;
     return mClient->setCrop(mHandle, crop);
 }
+status_t SurfaceControl::setFinalCrop(const Rect& crop) {
+    status_t err = validate();
+    if (err < 0) return err;
+    return mClient->setFinalCrop(mHandle, crop);
+}
 
 status_t SurfaceControl::deferTransactionUntil(sp<IBinder> handle,
         uint64_t frameNumber) {
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/include/GLES2/gl2.h b/opengl/include/GLES2/gl2.h
index e29a789..f64ec00 100644
--- a/opengl/include/GLES2/gl2.h
+++ b/opengl/include/GLES2/gl2.h
@@ -42,6 +42,10 @@
 #define GL_APIENTRYP GL_APIENTRY*
 #endif
 
+#if !defined(GL_GLES_PROTOTYPES)
+#define GL_GLES_PROTOTYPES 1
+#endif
+
 /* Generated on date 20151015 */
 
 /* Generated C header for:
@@ -520,7 +524,7 @@
 typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v);
 typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
 typedef void (GL_APIENTRYP PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
-#ifdef GL_GLEXT_PROTOTYPES
+#if GL_GLES_PROTOTYPES
 GL_APICALL void GL_APIENTRY glActiveTexture (GLenum texture);
 GL_APICALL void GL_APIENTRY glAttachShader (GLuint program, GLuint shader);
 GL_APICALL void GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar *name);
diff --git a/opengl/include/GLES3/gl3.h b/opengl/include/GLES3/gl3.h
index 383230f..d51d2e6 100644
--- a/opengl/include/GLES3/gl3.h
+++ b/opengl/include/GLES3/gl3.h
@@ -42,6 +42,10 @@
 #define GL_APIENTRYP GL_APIENTRY*
 #endif
 
+#if !defined(GL_GLES_PROTOTYPES)
+#define GL_GLES_PROTOTYPES 1
+#endif
+
 /* Generated on date 20151015 */
 
 /* Generated C header for:
@@ -520,7 +524,7 @@
 typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v);
 typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
 typedef void (GL_APIENTRYP PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
-#ifdef GL_GLEXT_PROTOTYPES
+#if GL_GLES_PROTOTYPES
 GL_APICALL void GL_APIENTRY glActiveTexture (GLenum texture);
 GL_APICALL void GL_APIENTRY glAttachShader (GLuint program, GLuint shader);
 GL_APICALL void GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar *name);
@@ -1094,7 +1098,7 @@
 typedef void (GL_APIENTRYP PFNGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
 typedef void (GL_APIENTRYP PFNGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
 typedef void (GL_APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params);
-#ifdef GL_GLEXT_PROTOTYPES
+#if GL_GLES_PROTOTYPES
 GL_APICALL void GL_APIENTRY glReadBuffer (GLenum src);
 GL_APICALL void GL_APIENTRY glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices);
 GL_APICALL void GL_APIENTRY glTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
diff --git a/opengl/include/GLES3/gl31.h b/opengl/include/GLES3/gl31.h
index 922a20a..9b89a0a 100644
--- a/opengl/include/GLES3/gl31.h
+++ b/opengl/include/GLES3/gl31.h
@@ -42,6 +42,10 @@
 #define GL_APIENTRYP GL_APIENTRY*
 #endif
 
+#if !defined(GL_GLES_PROTOTYPES)
+#define GL_GLES_PROTOTYPES 1
+#endif
+
 /* Generated on date 20151015 */
 
 /* Generated C header for:
@@ -520,7 +524,7 @@
 typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v);
 typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
 typedef void (GL_APIENTRYP PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
-#ifdef GL_GLEXT_PROTOTYPES
+#if GL_GLES_PROTOTYPES
 GL_APICALL void GL_APIENTRY glActiveTexture (GLenum texture);
 GL_APICALL void GL_APIENTRY glAttachShader (GLuint program, GLuint shader);
 GL_APICALL void GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar *name);
@@ -1094,7 +1098,7 @@
 typedef void (GL_APIENTRYP PFNGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
 typedef void (GL_APIENTRYP PFNGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
 typedef void (GL_APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params);
-#ifdef GL_GLEXT_PROTOTYPES
+#if GL_GLES_PROTOTYPES
 GL_APICALL void GL_APIENTRY glReadBuffer (GLenum src);
 GL_APICALL void GL_APIENTRY glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices);
 GL_APICALL void GL_APIENTRY glTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
@@ -1445,7 +1449,7 @@
 typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBIFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
 typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBBINDINGPROC) (GLuint attribindex, GLuint bindingindex);
 typedef void (GL_APIENTRYP PFNGLVERTEXBINDINGDIVISORPROC) (GLuint bindingindex, GLuint divisor);
-#ifdef GL_GLEXT_PROTOTYPES
+#if GL_GLES_PROTOTYPES
 GL_APICALL void GL_APIENTRY glDispatchCompute (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z);
 GL_APICALL void GL_APIENTRY glDispatchComputeIndirect (GLintptr indirect);
 GL_APICALL void GL_APIENTRY glDrawArraysIndirect (GLenum mode, const void *indirect);
diff --git a/opengl/include/GLES3/gl32.h b/opengl/include/GLES3/gl32.h
index 21bded5..a2c3611 100644
--- a/opengl/include/GLES3/gl32.h
+++ b/opengl/include/GLES3/gl32.h
@@ -42,6 +42,10 @@
 #define GL_APIENTRYP GL_APIENTRY*
 #endif
 
+#if !defined(GL_GLES_PROTOTYPES)
+#define GL_GLES_PROTOTYPES 1
+#endif
+
 /* Generated on date 20151015 */
 
 /* Generated C header for:
@@ -520,7 +524,7 @@
 typedef void (GL_APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v);
 typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
 typedef void (GL_APIENTRYP PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
-#ifdef GL_GLEXT_PROTOTYPES
+#if GL_GLES_PROTOTYPES
 GL_APICALL void GL_APIENTRY glActiveTexture (GLenum texture);
 GL_APICALL void GL_APIENTRY glAttachShader (GLuint program, GLuint shader);
 GL_APICALL void GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar *name);
@@ -1094,7 +1098,7 @@
 typedef void (GL_APIENTRYP PFNGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
 typedef void (GL_APIENTRYP PFNGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
 typedef void (GL_APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params);
-#ifdef GL_GLEXT_PROTOTYPES
+#if GL_GLES_PROTOTYPES
 GL_APICALL void GL_APIENTRY glReadBuffer (GLenum src);
 GL_APICALL void GL_APIENTRY glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices);
 GL_APICALL void GL_APIENTRY glTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
@@ -1445,7 +1449,7 @@
 typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBIFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
 typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBBINDINGPROC) (GLuint attribindex, GLuint bindingindex);
 typedef void (GL_APIENTRYP PFNGLVERTEXBINDINGDIVISORPROC) (GLuint bindingindex, GLuint divisor);
-#ifdef GL_GLEXT_PROTOTYPES
+#if GL_GLES_PROTOTYPES
 GL_APICALL void GL_APIENTRY glDispatchCompute (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z);
 GL_APICALL void GL_APIENTRY glDispatchComputeIndirect (GLintptr indirect);
 GL_APICALL void GL_APIENTRY glDrawArraysIndirect (GLenum mode, const void *indirect);
@@ -1770,7 +1774,7 @@
 typedef void (GL_APIENTRYP PFNGLTEXBUFFERPROC) (GLenum target, GLenum internalformat, GLuint buffer);
 typedef void (GL_APIENTRYP PFNGLTEXBUFFERRANGEPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
 typedef void (GL_APIENTRYP PFNGLTEXSTORAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
-#ifdef GL_GLEXT_PROTOTYPES
+#if GL_GLES_PROTOTYPES
 GL_APICALL void GL_APIENTRY glBlendBarrier (void);
 GL_APICALL void GL_APIENTRY glCopyImageSubData (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
 GL_APICALL void GL_APIENTRY glDebugMessageControl (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
diff --git a/opengl/include/KHR/khrplatform.h b/opengl/include/KHR/khrplatform.h
index a570d6c..153bbbd 100644
--- a/opengl/include/KHR/khrplatform.h
+++ b/opengl/include/KHR/khrplatform.h
@@ -92,8 +92,6 @@
  *                                  int arg2) KHRONOS_APIATTRIBUTES;
  */
 
-#define GL_GLEXT_PROTOTYPES
-
 /*-------------------------------------------------------------------------
  * Definition of KHRONOS_APICALL
  *-------------------------------------------------------------------------
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/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 8cc9fc1..d0a0401 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -10,6 +10,7 @@
     DispSync.cpp \
     EventControlThread.cpp \
     EventThread.cpp \
+    FenceTracker.cpp \
     FrameTracker.cpp \
     Layer.cpp \
     LayerDim.cpp \
@@ -103,7 +104,7 @@
 endif
 
 LOCAL_CFLAGS += -fvisibility=hidden -Werror=format
-LOCAL_CFLAGS += -std=c++11
+LOCAL_CFLAGS += -std=c++14
 
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
@@ -133,7 +134,7 @@
 
 LOCAL_LDFLAGS := -Wl,--version-script,art/sigchainlib/version-script.txt -Wl,--export-dynamic
 LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\"
-LOCAL_CPPFLAGS := -std=c++11
+LOCAL_CPPFLAGS := -std=c++14
 
 LOCAL_INIT_RC := surfaceflinger.rc
 
@@ -172,7 +173,7 @@
 LOCAL_CLANG := true
 
 LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\"
-LOCAL_CPPFLAGS := -std=c++11
+LOCAL_CPPFLAGS := -std=c++14
 
 LOCAL_SRC_FILES := \
     DdmConnection.cpp
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 8d8e40d..f7c8473 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -364,11 +364,9 @@
         false, Transform::ROT_0);
 }
 
-#ifdef USE_HWC2
 const sp<Fence>& DisplayDevice::getClientTargetAcquireFence() const {
     return mDisplaySurface->getClientTargetAcquireFence();
 }
-#endif
 
 // ----------------------------------------------------------------------------
 
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 38241d9..9ac8a97 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -49,9 +49,7 @@
 
 struct DisplayInfo;
 class DisplaySurface;
-#ifdef USE_HWC2
 class Fence;
-#endif
 class IGraphicBufferProducer;
 class Layer;
 class SurfaceFlinger;
@@ -174,9 +172,7 @@
     EGLBoolean makeCurrent(EGLDisplay dpy, EGLContext ctx) const;
     void setViewportAndProjection() const;
 
-#ifdef USE_HWC2
     const sp<Fence>& getClientTargetAcquireFence() const;
-#endif
 
     /* ------------------------------------------------------------------------
      * Display power mode management.
diff --git a/services/surfaceflinger/DisplayHardware/DisplaySurface.h b/services/surfaceflinger/DisplayHardware/DisplaySurface.h
index d819f83..d801bb3 100644
--- a/services/surfaceflinger/DisplayHardware/DisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/DisplaySurface.h
@@ -76,9 +76,7 @@
 
     virtual void resizeBuffers(const uint32_t w, const uint32_t h) = 0;
 
-#ifdef USE_HWC2
     virtual const sp<Fence>& getClientTargetAcquireFence() const = 0;
-#endif
 
 protected:
     DisplaySurface() {}
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 29e0766..7368d77 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -60,15 +60,14 @@
     ConsumerBase(consumer),
     mDisplayType(disp),
     mCurrentBufferSlot(-1),
-#ifdef USE_HWC2
     mCurrentBuffer(),
     mCurrentFence(Fence::NO_FENCE),
+#ifdef USE_HWC2
     mHwc(hwc),
     mHasPendingRelease(false),
     mPreviousBufferSlot(BufferQueue::INVALID_BUFFER_SLOT),
     mPreviousBuffer()
 #else
-    mCurrentBuffer(0),
     mHwc(hwc)
 #endif
 {
@@ -168,9 +167,7 @@
     }
     mCurrentBufferSlot = item.mSlot;
     mCurrentBuffer = mSlots[mCurrentBufferSlot].mGraphicBuffer;
-#ifdef USE_HWC2
     mCurrentFence = item.mFence;
-#endif
 
     outFence = item.mFence;
     outBuffer = mCurrentBuffer;
@@ -254,11 +251,9 @@
     ConsumerBase::dumpLocked(result, prefix);
 }
 
-#ifdef USE_HWC2
 const sp<Fence>& FramebufferSurface::getClientTargetAcquireFence() const {
     return mCurrentFence;
 }
-#endif
 
 // ----------------------------------------------------------------------------
 }; // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index 0605602..439435a 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -52,9 +52,7 @@
     // displays.
     virtual void resizeBuffers(const uint32_t /*w*/, const uint32_t /*h*/) { };
 
-#ifdef USE_HWC2
     virtual const sp<Fence>& getClientTargetAcquireFence() const override;
-#endif
 
 private:
     virtual ~FramebufferSurface() { }; // this class cannot be overloaded
@@ -88,10 +86,8 @@
     // no current buffer.
     sp<GraphicBuffer> mCurrentBuffer;
 
-#ifdef USE_HWC2
     // mCurrentFence is the current buffer's acquire fence
     sp<Fence> mCurrentFence;
-#endif
 
     // Hardware composer, owned by SurfaceFlinger.
     HWComposer& mHwc;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 1afed36..ee4bf02 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -311,11 +311,9 @@
     mSinkBufferHeight = h;
 }
 
-#ifdef USE_HWC2
 const sp<Fence>& VirtualDisplaySurface::getClientTargetAcquireFence() const {
     return mFbFence;
 }
-#endif
 
 status_t VirtualDisplaySurface::requestBuffer(int pslot,
         sp<GraphicBuffer>* outBuf) {
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index fe187c2..cfa4e4c 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -90,9 +90,7 @@
     virtual void onFrameCommitted();
     virtual void dumpAsString(String8& result) const;
     virtual void resizeBuffers(const uint32_t w, const uint32_t h);
-#ifdef USE_HWC2
     virtual const sp<Fence>& getClientTargetAcquireFence() const override;
-#endif
 
 private:
     enum Source {SOURCE_SINK = 0, SOURCE_SCRATCH = 1};
diff --git a/services/surfaceflinger/FenceTracker.cpp b/services/surfaceflinger/FenceTracker.cpp
new file mode 100644
index 0000000..7da1d93
--- /dev/null
+++ b/services/surfaceflinger/FenceTracker.cpp
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+#include "FenceTracker.h"
+#include "Layer.h"
+
+namespace android {
+
+FenceTracker::FenceTracker() :
+        mFrameCounter(0),
+        mOffset(0),
+        mFrames() {}
+
+void FenceTracker::dump(String8* outString) {
+    Mutex::Autolock lock(mMutex);
+    checkFencesForCompletion();
+
+    for (size_t i = 0; i < MAX_FRAME_HISTORY; i++) {
+        int index = (mOffset + i) % MAX_FRAME_HISTORY;
+        const FrameRecord& frame = mFrames[index];
+
+        outString->appendFormat("Frame %" PRIu64 "\n", frame.frameId);
+        outString->appendFormat("- Refresh start\t%" PRId64 "\n",
+                frame.refreshStartTime);
+
+        if (frame.glesCompositionDoneTime) {
+            outString->appendFormat("- GLES done\t%" PRId64 "\n",
+                    frame.glesCompositionDoneTime);
+        } else if (frame.glesCompositionDoneFence != Fence::NO_FENCE) {
+            outString->append("- GLES done\tNot signaled\n");
+        }
+        if (frame.retireTime) {
+            outString->appendFormat("- Retire\t%" PRId64 "\n",
+                    frame.retireTime);
+        } else {
+            outString->append("- Retire\tNot signaled\n");
+        }
+        for (const auto& kv : frame.layers) {
+            const LayerRecord& layer = kv.second;
+            outString->appendFormat("-- %s\n", layer.name.string());
+            outString->appendFormat("---- Frame # %" PRIu64 " (%s)\n",
+                    layer.frameNumber,
+                    layer.isGlesComposition ? "GLES" : "HWC");
+            outString->appendFormat("---- Posted\t%" PRId64 "\n",
+                    layer.postedTime);
+            if (layer.acquireTime) {
+                outString->appendFormat("---- Acquire\t%" PRId64 "\n",
+                        layer.acquireTime);
+            } else {
+                outString->append("---- Acquire\tNot signaled\n");
+            }
+            if (layer.releaseTime) {
+                outString->appendFormat("---- Release\t%" PRId64 "\n",
+                        layer.releaseTime);
+            } else {
+                outString->append("---- Release\tNot signaled\n");
+            }
+        }
+    }
+}
+
+static inline bool isValidTimestamp(nsecs_t time) {
+    return time > 0 && time < INT64_MAX;
+}
+
+void FenceTracker::checkFencesForCompletion() {
+    for (auto& frame : mFrames) {
+        if (frame.retireFence != Fence::NO_FENCE) {
+            nsecs_t time = frame.retireFence->getSignalTime();
+            if (isValidTimestamp(time)) {
+                frame.retireTime = time;
+                frame.retireFence = Fence::NO_FENCE;
+            }
+        }
+        if (frame.glesCompositionDoneFence != Fence::NO_FENCE) {
+            nsecs_t time = frame.glesCompositionDoneFence->getSignalTime();
+            if (isValidTimestamp(time)) {
+                frame.glesCompositionDoneTime = time;
+                frame.glesCompositionDoneFence = Fence::NO_FENCE;
+            }
+        }
+        for (auto& kv : frame.layers) {
+            LayerRecord& layer = kv.second;
+            if (layer.acquireFence != Fence::NO_FENCE) {
+                nsecs_t time = layer.acquireFence->getSignalTime();
+                if (isValidTimestamp(time)) {
+                    layer.acquireTime = time;
+                    layer.acquireFence = Fence::NO_FENCE;
+                }
+            }
+            if (layer.releaseFence != Fence::NO_FENCE) {
+                nsecs_t time = layer.releaseFence->getSignalTime();
+                if (isValidTimestamp(time)) {
+                    layer.releaseTime = time;
+                    layer.releaseFence = Fence::NO_FENCE;
+                }
+            }
+        }
+    }
+}
+
+void FenceTracker::addFrame(nsecs_t refreshStartTime, sp<Fence> retireFence,
+        const Vector<sp<Layer>>& layers, sp<Fence> glDoneFence) {
+    Mutex::Autolock lock(mMutex);
+    FrameRecord& frame = mFrames[mOffset];
+    FrameRecord& prevFrame = mFrames[(mOffset + MAX_FRAME_HISTORY - 1) %
+                                     MAX_FRAME_HISTORY];
+    frame.layers.clear();
+
+    bool wasGlesCompositionDone = false;
+    const size_t count = layers.size();
+    for (size_t i = 0; i < count; i++) {
+        String8 name;
+        uint64_t frameNumber;
+        bool glesComposition;
+        nsecs_t postedTime;
+        sp<Fence> acquireFence;
+        sp<Fence> prevReleaseFence;
+        int32_t key = layers[i]->getSequence();
+
+        layers[i]->getFenceData(&name, &frameNumber, &glesComposition,
+                &postedTime, &acquireFence, &prevReleaseFence);
+#ifdef USE_HWC2
+        if (glesComposition) {
+            frame.layers.emplace(std::piecewise_construct,
+                    std::forward_as_tuple(key),
+                    std::forward_as_tuple(name, frameNumber, glesComposition,
+                    postedTime, 0, 0, acquireFence, prevReleaseFence));
+            wasGlesCompositionDone = true;
+        } else {
+            frame.layers.emplace(std::piecewise_construct,
+                    std::forward_as_tuple(key),
+                    std::forward_as_tuple(name, frameNumber, glesComposition,
+                    postedTime, 0, 0, acquireFence, Fence::NO_FENCE));
+
+            auto prevLayer = prevFrame.layers.find(key);
+            if (prevLayer != prevFrame.layers.end()) {
+                prevLayer->second.releaseFence = prevReleaseFence;
+            }
+        }
+#else
+        frame.layers.emplace(std::piecewise_construct,
+                std::forward_as_tuple(key),
+                std::forward_as_tuple(name, frameNumber, glesComposition,
+                postedTime, 0, 0, acquireFence,
+                glesComposition ? Fence::NO_FENCE : prevReleaseFence));
+        if (glesComposition) {
+            wasGlesCompositionDone = true;
+        }
+#endif
+        frame.layers.emplace(std::piecewise_construct,
+                std::forward_as_tuple(key),
+                std::forward_as_tuple(name, frameNumber, glesComposition,
+                postedTime, 0, 0, acquireFence, prevReleaseFence));
+    }
+
+    frame.frameId = mFrameCounter;
+    frame.refreshStartTime = refreshStartTime;
+    frame.retireTime = 0;
+    frame.glesCompositionDoneTime = 0;
+    prevFrame.retireFence = retireFence;
+    frame.retireFence = Fence::NO_FENCE;
+    frame.glesCompositionDoneFence = wasGlesCompositionDone ? glDoneFence :
+            Fence::NO_FENCE;
+
+    mOffset = (mOffset + 1) % MAX_FRAME_HISTORY;
+    mFrameCounter++;
+
+    checkFencesForCompletion();
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/FenceTracker.h b/services/surfaceflinger/FenceTracker.h
new file mode 100644
index 0000000..de99820
--- /dev/null
+++ b/services/surfaceflinger/FenceTracker.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_FENCETRACKER_H
+#define ANDROID_FENCETRACKER_H
+
+#include <ui/Fence.h>
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/Timers.h>
+#include <utils/Vector.h>
+
+#include <unordered_map>
+
+namespace android {
+
+class Layer;
+
+/*
+ * Keeps a circular buffer of fence/timestamp data for the last N frames in
+ * SurfaceFlinger. Gets timestamps for fences after they have signaled.
+ */
+class FenceTracker {
+public:
+     FenceTracker();
+     void dump(String8* outString);
+     void addFrame(nsecs_t refreshStartTime, sp<Fence> retireFence,
+             const Vector<sp<Layer>>& layers, sp<Fence> glDoneFence);
+
+protected:
+     static constexpr size_t MAX_FRAME_HISTORY = 128;
+
+     struct LayerRecord {
+         String8 name; // layer name
+         uint64_t frameNumber; // frame number for this layer
+         bool isGlesComposition; // was GLES composition used for this layer?
+         nsecs_t postedTime; // time when buffer was queued
+         nsecs_t acquireTime; // timestamp from the acquire fence
+         nsecs_t releaseTime; // timestamp from the release fence
+         sp<Fence> acquireFence; // acquire fence
+         sp<Fence> releaseFence; // release fence
+
+         LayerRecord(const String8& name, uint64_t frameNumber,
+                 bool isGlesComposition, nsecs_t postedTime,
+                 nsecs_t acquireTime, nsecs_t releaseTime,
+                 sp<Fence> acquireFence, sp<Fence> releaseFence) :
+                 name(name), frameNumber(frameNumber),
+                 isGlesComposition(isGlesComposition), postedTime(postedTime),
+                 acquireTime(acquireTime), releaseTime(releaseTime),
+                 acquireFence(acquireFence), releaseFence(releaseFence) {};
+         LayerRecord() : name("uninitialized"), frameNumber(0),
+                 isGlesComposition(false), postedTime(0), acquireTime(0),
+                 releaseTime(0), acquireFence(Fence::NO_FENCE),
+                 releaseFence(Fence::NO_FENCE) {};
+     };
+
+     struct FrameRecord {
+         // global SurfaceFlinger frame counter
+         uint64_t frameId;
+         // layer data for this frame
+         std::unordered_map<int32_t, LayerRecord> layers;
+         // timestamp for when SurfaceFlinger::handleMessageRefresh() was called
+         nsecs_t refreshStartTime;
+         // timestamp from the retire fence
+         nsecs_t retireTime;
+         // timestamp from the GLES composition completion fence
+         nsecs_t glesCompositionDoneTime;
+         // primary display retire fence for this frame
+         sp<Fence> retireFence;
+         // if GLES composition was done, the fence for its completion
+         sp<Fence> glesCompositionDoneFence;
+
+         FrameRecord() : frameId(0), layers(), refreshStartTime(0),
+                 retireTime(0), glesCompositionDoneTime(0),
+                 retireFence(Fence::NO_FENCE),
+                 glesCompositionDoneFence(Fence::NO_FENCE) {}
+     };
+
+     uint64_t mFrameCounter;
+     uint32_t mOffset;
+     FrameRecord mFrames[MAX_FRAME_HISTORY];
+     Mutex mMutex;
+
+     void checkFencesForCompletion();
+};
+
+}
+
+#endif // ANDROID_FRAMETRACKER_H
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 42d0810..80012a6 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -82,6 +82,9 @@
         mFiltering(false),
         mNeedsFiltering(false),
         mMesh(Mesh::TRIANGLE_FAN, 4, 2, 2),
+#ifndef USE_HWC2
+        mIsGlesComposition(false),
+#endif
         mProtectedByApp(false),
         mHasSurface(false),
         mClientRef(client),
@@ -118,6 +121,7 @@
     mCurrentState.active.h = h;
     mCurrentState.active.transform.set(0, 0);
     mCurrentState.active.crop.makeInvalid();
+    mCurrentState.active.finalCrop.makeInvalid();
     mCurrentState.z = 0;
 #ifdef USE_HWC2
     mCurrentState.alpha = 1.0f;
@@ -401,7 +405,14 @@
     }
 
     activeCrop = s.active.transform.transform(activeCrop);
-    activeCrop.intersect(hw->getViewport(), &activeCrop);
+    if (!activeCrop.intersect(hw->getViewport(), &activeCrop)) {
+        activeCrop.clear();
+    }
+    if (!s.active.finalCrop.isEmpty()) {
+        if(!activeCrop.intersect(s.active.finalCrop, &activeCrop)) {
+            activeCrop.clear();
+        }
+    }
     activeCrop = s.active.transform.inverse().transform(activeCrop);
 
     // This needs to be here as transform.transform(Rect) computes the
@@ -410,72 +421,73 @@
     // transform.inverse().transform(transform.transform(Rect)) != Rect
     // in which case we need to make sure the final rect is clipped to the
     // display bounds.
-    activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop);
+    if (!activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop)) {
+        activeCrop.clear();
+    }
 
     // subtract the transparent region and snap to the bounds
     activeCrop = reduce(activeCrop, s.activeTransparentRegion);
 
-    if (!activeCrop.isEmpty()) {
-        // Transform the window crop to match the buffer coordinate system,
-        // which means using the inverse of the current transform set on the
-        // SurfaceFlingerConsumer.
-        uint32_t invTransform = mCurrentTransform;
-        if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) {
-            /*
-             * the code below applies the display's inverse transform to the buffer
-             */
-            uint32_t invTransformOrient = hw->getOrientationTransform();
-            // calculate the inverse transform
-            if (invTransformOrient & NATIVE_WINDOW_TRANSFORM_ROT_90) {
-                invTransformOrient ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
-                        NATIVE_WINDOW_TRANSFORM_FLIP_H;
-                // If the transform has been rotated the axis of flip has been swapped
-                // so we need to swap which flip operations we are performing
-                bool is_h_flipped = (invTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) != 0;
-                bool is_v_flipped = (invTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) != 0;
-                if (is_h_flipped != is_v_flipped) {
-                    invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
-                            NATIVE_WINDOW_TRANSFORM_FLIP_H;
-                }
-            }
-            // and apply to the current transform
-            invTransform = (Transform(invTransform) * Transform(invTransformOrient)).getOrientation();
-        }
-
-        int winWidth = s.active.w;
-        int winHeight = s.active.h;
-        if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
-            // If the activeCrop has been rotate the ends are rotated but not
-            // the space itself so when transforming ends back we can't rely on
-            // a modification of the axes of rotation. To account for this we
-            // need to reorient the inverse rotation in terms of the current
-            // axes of rotation.
+    // Transform the window crop to match the buffer coordinate system,
+    // which means using the inverse of the current transform set on the
+    // SurfaceFlingerConsumer.
+    uint32_t invTransform = mCurrentTransform;
+    if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) {
+        /*
+         * the code below applies the display's inverse transform to the buffer
+         */
+        uint32_t invTransformOrient = hw->getOrientationTransform();
+        // calculate the inverse transform
+        if (invTransformOrient & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+            invTransformOrient ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
+                    NATIVE_WINDOW_TRANSFORM_FLIP_H;
+            // If the transform has been rotated the axis of flip has been swapped
+            // so we need to swap which flip operations we are performing
             bool is_h_flipped = (invTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) != 0;
             bool is_v_flipped = (invTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) != 0;
-            if (is_h_flipped == is_v_flipped) {
+            if (is_h_flipped != is_v_flipped) {
                 invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
                         NATIVE_WINDOW_TRANSFORM_FLIP_H;
             }
-            winWidth = s.active.h;
-            winHeight = s.active.w;
         }
-        const Rect winCrop = activeCrop.transform(
-                invTransform, s.active.w, s.active.h);
-
-        // below, crop is intersected with winCrop expressed in crop's coordinate space
-        float xScale = crop.getWidth()  / float(winWidth);
-        float yScale = crop.getHeight() / float(winHeight);
-
-        float insetL = winCrop.left                 * xScale;
-        float insetT = winCrop.top                  * yScale;
-        float insetR = (winWidth - winCrop.right )  * xScale;
-        float insetB = (winHeight - winCrop.bottom) * yScale;
-
-        crop.left   += insetL;
-        crop.top    += insetT;
-        crop.right  -= insetR;
-        crop.bottom -= insetB;
+        // and apply to the current transform
+        invTransform = (Transform(invTransform) * Transform(invTransformOrient)).getOrientation();
     }
+
+    int winWidth = s.active.w;
+    int winHeight = s.active.h;
+    if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+        // If the activeCrop has been rotate the ends are rotated but not
+        // the space itself so when transforming ends back we can't rely on
+        // a modification of the axes of rotation. To account for this we
+        // need to reorient the inverse rotation in terms of the current
+        // axes of rotation.
+        bool is_h_flipped = (invTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) != 0;
+        bool is_v_flipped = (invTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) != 0;
+        if (is_h_flipped == is_v_flipped) {
+            invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
+                    NATIVE_WINDOW_TRANSFORM_FLIP_H;
+        }
+        winWidth = s.active.h;
+        winHeight = s.active.w;
+    }
+    const Rect winCrop = activeCrop.transform(
+            invTransform, s.active.w, s.active.h);
+
+    // below, crop is intersected with winCrop expressed in crop's coordinate space
+    float xScale = crop.getWidth()  / float(winWidth);
+    float yScale = crop.getHeight() / float(winHeight);
+
+    float insetL = winCrop.left                 * xScale;
+    float insetT = winCrop.top                  * yScale;
+    float insetR = (winWidth - winCrop.right )  * xScale;
+    float insetB = (winHeight - winCrop.bottom) * yScale;
+
+    crop.left   += insetL;
+    crop.top    += insetT;
+    crop.right  -= insetR;
+    crop.bottom -= insetB;
+
     return crop;
 }
 
@@ -537,10 +549,12 @@
         Rect activeCrop(s.active.crop);
         activeCrop = s.active.transform.transform(activeCrop);
 #ifdef USE_HWC2
-        activeCrop.intersect(displayDevice->getViewport(), &activeCrop);
+        if(!activeCrop.intersect(displayDevice->getViewport(), &activeCrop)) {
 #else
-        activeCrop.intersect(hw->getViewport(), &activeCrop);
+        if(!activeCrop.intersect(hw->getViewport(), &activeCrop)) {
 #endif
+            activeCrop.clear();
+        }
         activeCrop = s.active.transform.inverse().transform(activeCrop);
         // This needs to be here as transform.transform(Rect) computes the
         // transformed rect and then takes the bounding box of the result before
@@ -548,7 +562,9 @@
         // transform.inverse().transform(transform.transform(Rect)) != Rect
         // in which case we need to make sure the final rect is clipped to the
         // display bounds.
-        activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop);
+        if(!activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop)) {
+            activeCrop.clear();
+        }
         // mark regions outside the crop as transparent
         activeTransparentRegion.orSelf(Rect(0, 0, s.active.w, activeCrop.top));
         activeTransparentRegion.orSelf(Rect(0, activeCrop.bottom,
@@ -559,8 +575,15 @@
                 s.active.w, activeCrop.bottom));
     }
     Rect frame(s.active.transform.transform(computeBounds(activeTransparentRegion)));
+    if (!s.active.finalCrop.isEmpty()) {
+        if(!frame.intersect(s.active.finalCrop, &frame)) {
+            frame.clear();
+        }
+    }
 #ifdef USE_HWC2
-    frame.intersect(displayDevice->getViewport(), &frame);
+    if (!frame.intersect(displayDevice->getViewport(), &frame)) {
+        frame.clear();
+    }
     const Transform& tr(displayDevice->getTransform());
     Rect transformedFrame = tr.transform(frame);
     auto error = hwcLayer->setDisplayFrame(transformedFrame);
@@ -588,7 +611,9 @@
             mName.string(), s.z, to_string(error).c_str(),
             static_cast<int32_t>(error));
 #else
-    frame.intersect(hw->getViewport(), &frame);
+    if (!frame.intersect(hw->getViewport(), &frame)) {
+        frame.clear();
+    }
     const Transform& tr(hw->getTransform());
     layer.setFrame(tr.transform(frame));
     layer.setCrop(computeCrop(hw));
@@ -750,6 +775,7 @@
     Region visible = tr.transform(visibleRegion.intersect(hw->getViewport()));
     layer.setVisibleRegionScreen(visible);
     layer.setSurfaceDamage(surfaceDamageRegion);
+    mIsGlesComposition = (layer.getCompositionType() == HWC_FRAMEBUFFER);
 
     if (mSidebandStream.get()) {
         layer.setSidebandStream(mSidebandStream);
@@ -782,6 +808,9 @@
     Rect bounds = reduce(win, s.activeTransparentRegion);
     Rect frame(s.active.transform.transform(bounds));
     frame.intersect(displayDevice->getViewport(), &frame);
+    if (!s.active.finalCrop.isEmpty()) {
+        frame.intersect(s.active.finalCrop, &frame);
+    }
     auto& displayTransform(displayDevice->getTransform());
     auto position = displayTransform.transform(frame);
 
@@ -828,6 +857,9 @@
     Rect bounds = reduce(win, s.activeTransparentRegion);
     Rect frame(s.active.transform.transform(bounds));
     frame.intersect(hw->getViewport(), &frame);
+    if (!s.active.finalCrop.isEmpty()) {
+        frame.intersect(s.active.finalCrop, &frame);
+    }
     const Transform& tr(hw->getTransform());
     return Rect(tr.transform(frame));
 }
@@ -982,7 +1014,18 @@
      * minimal value)? Or, we could make GL behave like HWC -- but this feel
      * like more of a hack.
      */
-    const Rect win(computeBounds());
+    Rect win(computeBounds());
+
+    if (!s.active.finalCrop.isEmpty()) {
+        win = s.active.transform.transform(win);
+        if (!win.intersect(s.active.finalCrop, &win)) {
+            win.clear();
+        }
+        win = s.active.transform.inverse().transform(win);
+        if (!win.intersect(computeBounds(), &win)) {
+            win.clear();
+        }
+    }
 
     float left   = float(win.left)   / float(s.active.w);
     float top    = float(win.top)    / float(s.active.h);
@@ -1116,12 +1159,26 @@
 // local state
 // ----------------------------------------------------------------------------
 
+static void boundPoint(vec2* point, const Rect& crop) {
+    if (point->x < crop.left) {
+        point->x = crop.left;
+    }
+    if (point->x > crop.right) {
+        point->x = crop.right;
+    }
+    if (point->y < crop.top) {
+        point->y = crop.top;
+    }
+    if (point->y > crop.bottom) {
+        point->y = crop.bottom;
+    }
+}
+
 void Layer::computeGeometry(const sp<const DisplayDevice>& hw, Mesh& mesh,
         bool useIdentityTransform) const
 {
     const Layer::State& s(getDrawingState());
-    const Transform tr(useIdentityTransform ?
-            hw->getTransform() : hw->getTransform() * s.active.transform);
+    const Transform tr(hw->getTransform());
     const uint32_t hw_h = hw->getHeight();
     Rect win(s.active.w, s.active.h);
     if (!s.active.crop.isEmpty()) {
@@ -1130,11 +1187,30 @@
     // subtract the transparent region and snap to the bounds
     win = reduce(win, s.activeTransparentRegion);
 
+    vec2 lt = vec2(win.left, win.top);
+    vec2 lb = vec2(win.left, win.bottom);
+    vec2 rb = vec2(win.right, win.bottom);
+    vec2 rt = vec2(win.right, win.top);
+
+    if (!useIdentityTransform) {
+        lt = s.active.transform.transform(lt);
+        lb = s.active.transform.transform(lb);
+        rb = s.active.transform.transform(rb);
+        rt = s.active.transform.transform(rt);
+    }
+
+    if (!s.active.finalCrop.isEmpty()) {
+        boundPoint(&lt, s.active.finalCrop);
+        boundPoint(&lb, s.active.finalCrop);
+        boundPoint(&rb, s.active.finalCrop);
+        boundPoint(&rt, s.active.finalCrop);
+    }
+
     Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
-    position[0] = tr.transform(win.left,  win.top);
-    position[1] = tr.transform(win.left,  win.bottom);
-    position[2] = tr.transform(win.right, win.bottom);
-    position[3] = tr.transform(win.right, win.top);
+    position[0] = tr.transform(lt);
+    position[1] = tr.transform(lb);
+    position[2] = tr.transform(rb);
+    position[3] = tr.transform(rt);
     for (size_t i=0 ; i<4 ; i++) {
         position[i].y = hw_h - position[i].y;
     }
@@ -1500,6 +1576,15 @@
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
+bool Layer::setFinalCrop(const Rect& crop) {
+    if (mCurrentState.requested.finalCrop == crop)
+        return false;
+    mCurrentState.sequence++;
+    mCurrentState.requested.finalCrop = crop;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
 
 bool Layer::setLayerStack(uint32_t layerStack) {
     if (mCurrentState.layerStack == layerStack)
@@ -1993,7 +2078,8 @@
     sp<Client> client(mClientRef.promote());
 
     result.appendFormat(            "      "
-            "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), crop=(%4d,%4d,%4d,%4d), "
+            "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), "
+            "crop=(%4d,%4d,%4d,%4d), finalCrop=(%4d,%4d,%4d,%4d), "
             "isOpaque=%1d, invalidate=%1d, "
 #ifdef USE_HWC2
             "alpha=%.3f, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n"
@@ -2004,6 +2090,8 @@
             s.layerStack, s.z, s.active.transform.tx(), s.active.transform.ty(), s.active.w, s.active.h,
             s.active.crop.left, s.active.crop.top,
             s.active.crop.right, s.active.crop.bottom,
+            s.active.finalCrop.left, s.active.finalCrop.top,
+            s.active.finalCrop.right, s.active.finalCrop.bottom,
             isOpaque(s), contentDirty,
             s.alpha, s.flags,
             s.active.transform[0][0], s.active.transform[0][1],
@@ -2046,6 +2134,23 @@
     mFrameTracker.getStats(outStats);
 }
 
+void Layer::getFenceData(String8* outName, uint64_t* outFrameNumber,
+        bool* outIsGlesComposition, nsecs_t* outPostedTime,
+        sp<Fence>* outAcquireFence, sp<Fence>* outPrevReleaseFence) const {
+    *outName = mName;
+    *outFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
+
+#ifdef USE_HWC2
+    *outIsGlesComposition = mHwcLayers.count(HWC_DISPLAY_PRIMARY) ?
+            mHwcLayers.at(HWC_DISPLAY_PRIMARY).compositionType ==
+            HWC2::Composition::Client : true;
+#else
+    *outIsGlesComposition = mIsGlesComposition;
+#endif
+    *outPostedTime = mSurfaceFlingerConsumer->getTimestamp();
+    *outAcquireFence = mSurfaceFlingerConsumer->getCurrentFence();
+    *outPrevReleaseFence = mSurfaceFlingerConsumer->getPrevReleaseFence();
+}
 // ---------------------------------------------------------------------------
 
 Layer::LayerCleaner::LayerCleaner(const sp<SurfaceFlinger>& flinger,
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index b0088e6..34857c2 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -94,6 +94,7 @@
         uint32_t w;
         uint32_t h;
         Rect crop;
+        Rect finalCrop;
         Transform transform;
 
         inline bool operator ==(const Geometry& rhs) const {
@@ -155,6 +156,7 @@
     bool setTransparentRegionHint(const Region& transparent);
     bool setFlags(uint8_t flags, uint8_t mask);
     bool setCrop(const Rect& crop);
+    bool setFinalCrop(const Rect& crop);
     bool setLayerStack(uint32_t layerStack);
     void deferTransactionUntil(const sp<IBinder>& handle, uint64_t frameNumber);
 
@@ -177,6 +179,8 @@
     sp<IGraphicBufferProducer> getProducer() const;
     const String8& getName() const;
 
+    int32_t getSequence() const { return sequence; }
+
     // -----------------------------------------------------------------------
     // Virtuals
 
@@ -396,6 +400,10 @@
     void logFrameStats();
     void getFrameStats(FrameStats* outStats) const;
 
+    void getFenceData(String8* outName, uint64_t* outFrameNumber,
+            bool* outIsGlesComposition, nsecs_t* outPostedTime,
+            sp<Fence>* outAcquireFence, sp<Fence>* outPrevReleaseFence) const;
+
 protected:
     // constant
     sp<SurfaceFlinger> mFlinger;
@@ -555,6 +563,8 @@
         bool clearClientTarget;
     };
     std::unordered_map<int32_t, HWCInfo> mHwcLayers;
+#else
+    bool mIsGlesComposition;
 #endif
 
     // page-flip thread (currently main thread)
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 3a0e21f..9b43849 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -910,6 +910,7 @@
 void SurfaceFlinger::handleMessageRefresh() {
     ATRACE_CALL();
 
+    nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
     static nsecs_t previousExpectedPresent = 0;
     nsecs_t expectedPresent = mPrimaryDispSync.computeNextRefresh(0);
     static bool previousFrameMissed = false;
@@ -930,7 +931,7 @@
         setUpHWComposer();
         doDebugFlashRegions();
         doComposition();
-        postComposition();
+        postComposition(refreshStartTime);
     }
 
     // Release any buffers which were replaced this frame
@@ -999,7 +1000,7 @@
     }
 }
 
-void SurfaceFlinger::postComposition()
+void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
 {
     ATRACE_CALL();
     ALOGV("postComposition");
@@ -1027,6 +1028,9 @@
         }
     }
 
+    mFenceTracker.addFrame(refreshStartTime, presentFence,
+            hw->getVisibleLayersSortedByZ(), hw->getClientTargetAcquireFence());
+
     if (mAnimCompositionPending) {
         mAnimCompositionPending = false;
 
@@ -2236,6 +2240,10 @@
             if (layer->setCrop(s.crop))
                 flags |= eTraversalNeeded;
         }
+        if (what & layer_state_t::eFinalCropChanged) {
+            if (layer->setFinalCrop(s.finalCrop))
+                flags |= eTraversalNeeded;
+        }
         if (what & layer_state_t::eLayerStackChanged) {
             // NOTE: index needs to be calculated before we update the state
             ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
@@ -2539,6 +2547,13 @@
                 dumpStaticScreenStats(result);
                 dumpAll = false;
             }
+
+            if ((index < numArgs) &&
+                    (args[index] == String16("--fences"))) {
+                index++;
+                mFenceTracker.dump(&result);
+                dumpAll = false;
+            }
         }
 
         if (dumpAll) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 7d6f139..37110b9 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -50,6 +50,7 @@
 #include "Barrier.h"
 #include "DisplayDevice.h"
 #include "DispSync.h"
+#include "FenceTracker.h"
 #include "FrameTracker.h"
 #include "MessageQueue.h"
 
@@ -384,7 +385,7 @@
             Region& dirtyRegion, Region& opaqueRegion);
 
     void preComposition();
-    void postComposition();
+    void postComposition(nsecs_t refreshStartTime);
     void rebuildLayerStacks();
     void setUpHWComposer();
     void doComposition();
@@ -488,6 +489,7 @@
     nsecs_t mLastTransactionTime;
     bool mBootFinished;
     bool mForceFullDamage;
+    FenceTracker mFenceTracker;
 
     // these are thread safe
     mutable MessageQueue mEventQueue;
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index 4c80fa0..c71b3bc 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -190,6 +190,7 @@
 #ifdef USE_HWC2
 void SurfaceFlingerConsumer::setReleaseFence(const sp<Fence>& fence)
 {
+    mPrevReleaseFence = fence;
     if (!mPendingRelease.isPending) {
         GLConsumer::setReleaseFence(fence);
         return;
@@ -219,8 +220,17 @@
             strerror(-result), result);
     mPendingRelease = PendingRelease();
 }
+#else
+void SurfaceFlingerConsumer::setReleaseFence(const sp<Fence>& fence) {
+    mPrevReleaseFence = fence;
+    GLConsumer::setReleaseFence(fence);
+}
 #endif
 
+sp<Fence> SurfaceFlingerConsumer::getPrevReleaseFence() const {
+    return mPrevReleaseFence;
+}
+
 void SurfaceFlingerConsumer::setContentsChangedListener(
         const wp<ContentsChangedListener>& listener) {
     setFrameAvailableListener(listener);
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index f40d53e..51b002f 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -37,7 +37,8 @@
     SurfaceFlingerConsumer(const sp<IGraphicBufferConsumer>& consumer,
             uint32_t tex)
         : GLConsumer(consumer, tex, GLConsumer::TEXTURE_EXTERNAL, false, false),
-          mTransformToDisplayInverse(false), mSurfaceDamage()
+          mTransformToDisplayInverse(false), mSurfaceDamage(),
+          mPrevReleaseFence(Fence::NO_FENCE)
     {}
 
     class BufferRejecter {
@@ -75,8 +76,9 @@
 
     nsecs_t computeExpectedPresent(const DispSync& dispSync);
 
-#ifdef USE_HWC2
     virtual void setReleaseFence(const sp<Fence>& fence) override;
+    sp<Fence> getPrevReleaseFence() const;
+#ifdef USE_HWC2
     void releasePendingBuffer();
 #endif
 
@@ -98,6 +100,9 @@
     // presentDisplay
     PendingRelease mPendingRelease;
 #endif
+
+    // The release fence of the already displayed buffer (previous frame).
+    sp<Fence> mPrevReleaseFence;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index d864874..11f19d0 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -927,6 +927,7 @@
 void SurfaceFlinger::handleMessageRefresh() {
     ATRACE_CALL();
 
+    nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
     static nsecs_t previousExpectedPresent = 0;
     nsecs_t expectedPresent = mPrimaryDispSync.computeNextRefresh(0);
     static bool previousFrameMissed = false;
@@ -947,7 +948,7 @@
         setUpHWComposer();
         doDebugFlashRegions();
         doComposition();
-        postComposition();
+        postComposition(refreshStartTime);
     }
 
     previousExpectedPresent = mPrimaryDispSync.computeNextRefresh(0);
@@ -1008,7 +1009,7 @@
     }
 }
 
-void SurfaceFlinger::postComposition()
+void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
 {
     const LayerVector& layers(mDrawingState.layersSortedByZ);
     const size_t count = layers.size();
@@ -1034,6 +1035,9 @@
         }
     }
 
+    mFenceTracker.addFrame(refreshStartTime, presentFence,
+            hw->getVisibleLayersSortedByZ(), hw->getClientTargetAcquireFence());
+
     if (mAnimCompositionPending) {
         mAnimCompositionPending = false;
 
@@ -2274,6 +2278,10 @@
             if (layer->setCrop(s.crop))
                 flags |= eTraversalNeeded;
         }
+        if (what & layer_state_t::eFinalCropChanged) {
+            if (layer->setFinalCrop(s.finalCrop))
+                flags |= eTraversalNeeded;
+        }
         if (what & layer_state_t::eLayerStackChanged) {
             // NOTE: index needs to be calculated before we update the state
             ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
@@ -2577,6 +2585,13 @@
                 dumpStaticScreenStats(result);
                 dumpAll = false;
             }
+
+            if ((index < numArgs) &&
+                    (args[index] == String16("--fences"))) {
+                index++;
+                mFenceTracker.dump(&result);
+                dumpAll = false;
+            }
         }
 
         if (dumpAll) {
diff --git a/services/surfaceflinger/Transform.h b/services/surfaceflinger/Transform.h
index c2f0010..9efeb9e 100644
--- a/services/surfaceflinger/Transform.h
+++ b/services/surfaceflinger/Transform.h
@@ -81,6 +81,9 @@
             Region  transform(const Region& reg) const;
             Rect    transform(const Rect& bounds) const;
             Transform operator * (const Transform& rhs) const;
+            // assumes the last row is < 0 , 0 , 1 >
+            vec2 transform(const vec2& v) const;
+            vec3 transform(const vec3& v) const;
 
             Transform inverse() const;
 
@@ -96,9 +99,6 @@
 
     enum { UNKNOWN_TYPE = 0x80000000 };
 
-    // assumes the last row is < 0 , 0 , 1 >
-    vec2 transform(const vec2& v) const;
-    vec3 transform(const vec3& v) const;
     uint32_t type() const;
     static bool absIsOne(float f);
     static bool isZero(float f);
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index ee4ad4e..d7cb899 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -280,6 +280,31 @@
     }
 }
 
+TEST_F(LayerUpdateTest, LayerFinalCropWorks) {
+    sp<ScreenCapture> sc;
+    {
+        SCOPED_TRACE("before crop");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel( 24,  24,  63,  63, 195);
+        sc->checkPixel( 75,  75, 195,  63,  63);
+        sc->checkPixel(145, 145,  63,  63, 195);
+    }
+    SurfaceComposerClient::openGlobalTransaction();
+    Rect cropRect(16, 16, 32, 32);
+    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setFinalCrop(cropRect));
+    SurfaceComposerClient::closeGlobalTransaction(true);
+    {
+        // This should crop the foreground surface.
+        SCOPED_TRACE("after crop");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel( 24,  24,  63,  63, 195);
+        sc->checkPixel( 75,  75,  63,  63, 195);
+        sc->checkPixel( 95,  80,  63,  63, 195);
+        sc->checkPixel( 80,  95,  63,  63, 195);
+        sc->checkPixel( 96,  96,  63,  63, 195);
+    }
+}
+
 TEST_F(LayerUpdateTest, LayerSetLayerWorks) {
     sp<ScreenCapture> sc;
     {
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
 
 // -----------------------------------------------------------------------------