Merge "Manually fix GLES headers" 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 5898b41..9507ac6 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 it doesn't hurt to handle that scenario
+        MYLOGD("execl on '/system/bin/atrace --async_dump' returned control");
+        return;
+    } 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;
@@ -1252,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();
@@ -1265,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 288fe39..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);
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index d21ef7b..975cd27 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>
@@ -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
@@ -640,13 +662,48 @@
 
     ON_DRY_RUN({ update_progress(timeout_seconds); va_end(ap); return 0; });
 
-    int status = run_command_always(title, timeout_seconds, args);
+    int status = run_command_always(title, false, timeout_seconds, args);
+    va_end(ap);
+    return status;
+}
+
+int run_command_as_shell(const char *title, int timeout_seconds, const char *command, ...) {
+    DurationReporter duration_reporter(title);
+    fflush(stdout);
+
+    const char *args[1024] = {command};
+    size_t arg;
+    va_list ap;
+    va_start(ap, command);
+    if (title) printf("------ %s (%s", title, command);
+    bool null_terminated = false;
+    for (arg = 1; arg < sizeof(args) / sizeof(args[0]); ++arg) {
+        args[arg] = va_arg(ap, const char *);
+        if (args[arg] == nullptr) {
+            null_terminated = true;
+            break;
+        }
+        if (title) printf(" %s", args[arg]);
+    }
+    if (title) printf(") ------\n");
+    fflush(stdout);
+    if (!null_terminated) {
+        // Fail now, otherwise execvp() call on run_command_always() might hang.
+        std::string cmd;
+        format_args(command, args, &cmd);
+        MYLOGE("skipping command %s because its args were not NULL-terminated", cmd.c_str());
+        return -1;
+    }
+
+    ON_DRY_RUN({ update_progress(timeout_seconds); va_end(ap); return 0; });
+
+    int status = run_command_always(title, true, timeout_seconds, args);
     va_end(ap);
     return status;
 }
 
 /* forks a command and waits for it to finish */
-int run_command_always(const char *title, int timeout_seconds, const char *args[]) {
+int run_command_always(const char *title, bool drop_root, int timeout_seconds, const char *args[]) {
     /* TODO: for now we're simplifying the progress calculation by using the timeout as the weight.
      * It's a good approximation for most cases, except when calling dumpsys, where its weight
      * should be much higher proportionally to its timeout. */
@@ -664,6 +721,10 @@
 
     /* handle child case */
     if (pid == 0) {
+        if (drop_root && !drop_root_user()) {
+            printf("*** could not drop root before running %s: %s\n", command, strerror(errno));
+            return -1;
+        }
 
         /* make sure the child dies when dumpstate dies */
         prctl(PR_SET_PDEATHSIG, SIGKILL);
@@ -676,7 +737,9 @@
 
         execvp(command, (char**) args);
         // execvp's result will be handled after waitpid_with_timeout() below...
-        _exit(-1); // ...but it doesn't hurt to force exit, just in case
+        MYLOGD("execvp on command %s returned control (error: %s)", command, strerror(errno));
+        fflush(stdout);
+        return -1; // ...but it doesn't hurt to force exit, just in case
     }
 
     /* handle parent case */
@@ -726,14 +789,60 @@
     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();
     }
@@ -742,7 +851,7 @@
     std::string args_string;
     format_args(am_index + 1, am_args, &args_string);
     MYLOGD("send_broadcast command: %s\n", args_string.c_str());
-    run_command_always(NULL, 5, am_args);
+    run_command_always(NULL, true, 20, am_args);
 }
 
 size_t num_props = 0;
@@ -1081,7 +1190,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) {
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 77bcfc2..c0e0214 100644
--- a/cmds/installd/commands.cpp
+++ b/cmds/installd/commands.cpp
@@ -222,6 +222,14 @@
     return res;
 }
 
+static int destroy_app_profiles(const char *pkgname, userid_t userid) {
+    // TODO: this doesn't destroy the marks for foreign dex use yet.
+    int res = 0;
+    res |= delete_dir_contents_and_dir(create_data_user_profile_package_path( userid, pkgname));
+    res |= delete_dir_contents_and_dir(create_data_ref_profile_package_path(pkgname));
+    return res;
+}
+
 int destroy_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags) {
     int res = 0;
     if (flags & FLAG_STORAGE_CE) {
@@ -229,10 +237,9 @@
                 create_data_user_package_path(uuid, userid, pkgname));
     }
     if (flags & FLAG_STORAGE_DE) {
-        // TODO: include result once 25796509 is fixed
-        delete_dir_contents_and_dir(
+        res |= delete_dir_contents_and_dir(
                 create_data_user_de_package_path(uuid, userid, pkgname));
-        unlink_all_profiles(pkgname);
+        res |= destroy_app_profiles(pkgname, userid);
     }
     return res;
 }
@@ -707,7 +714,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;
 
@@ -723,10 +730,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"
@@ -818,6 +821,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;
@@ -825,13 +832,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.
@@ -1276,9 +1290,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;
@@ -1293,29 +1312,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) {
@@ -1390,7 +1398,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);
@@ -1433,7 +1443,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 b473e3e..70cb410 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/installd.cpp b/cmds/installd/installd.cpp
index 2bf27a2..dc3418a 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)
@@ -388,6 +405,7 @@
     { "rmprofiles",           1, do_rm_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 89a4225..245694a 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -357,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/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/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/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/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/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/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/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/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/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 42d0810..910aeae 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -118,6 +118,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 +402,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 +418,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 +546,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 +559,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 +572,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 +608,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));
@@ -782,6 +804,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 +853,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 +1010,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 +1155,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 +1183,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 +1572,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 +2074,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 +2086,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],
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index b0088e6..4dc0764 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);
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 3a0e21f..019bcec 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2236,6 +2236,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);
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index d864874..e41fbdd 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -2274,6 +2274,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);
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 eba58c6..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;
@@ -272,6 +273,7 @@
     Vector<LayerRef> active_layers;
     VkDebugReportCallbackEXT message;
     DebugReportCallbackList debug_report_callbacks;
+    InstanceExtensionSet enabled_extensions;
 
     struct {
         VkInstance instance;
@@ -285,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>
@@ -622,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];
@@ -630,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.
@@ -701,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;
     }
@@ -783,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;
@@ -925,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
@@ -934,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;
             }
         }
@@ -997,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;
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
 
 // -----------------------------------------------------------------------------