DO NOT MERGE: fix build try #2 am: 778b6f4902 am: 034bc1799c  -s ours am: dbc9a47831  -s ours am: a2685ebb1e
am: 1d94a1d036  -s ours

* commit '1d94a1d036cb4bc8d9b178f56fa3bbddc81b7f10':
  DO NOT MERGE: fix build try #2
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 515d761..9def406 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -137,6 +137,9 @@
         { REQ,      "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable" },
         { REQ,      "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable" },
     } },
+    { "regulators",  "Voltage and Current Regulators", 0, {
+        { REQ,      "/sys/kernel/debug/tracing/events/regulator/enable" },
+    } },
 };
 
 /* Command line options */
@@ -897,7 +900,7 @@
                     g_traceOverwrite = true;
                 } else if (!strcmp(long_options[option_index].name, "async_stop")) {
                     async = true;
-                    traceStop = false;
+                    traceStart = false;
                 } else if (!strcmp(long_options[option_index].name, "async_dump")) {
                     async = true;
                     traceStart = false;
diff --git a/cmds/bugreport/bugreport.cpp b/cmds/bugreport/bugreport.cpp
index b606406..6892b57 100644
--- a/cmds/bugreport/bugreport.cpp
+++ b/cmds/bugreport/bugreport.cpp
@@ -86,6 +86,6 @@
     } while (bytes_written != 0 && bytes_to_send > 0);
   }
 
-  TEMP_FAILURE_RETRY(close(s));
+  close(s);
   return 0;
 }
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index a33dcf3..ef8db06 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -18,6 +18,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <limits.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -99,8 +100,170 @@
     closedir(d);
 }
 
+static bool skip_not_stat(const char *path) {
+    static const char stat[] = "/stat";
+    size_t len = strlen(path);
+    if (path[len - 1] == '/') { /* Directory? */
+        return false;
+    }
+    return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
+}
+
+static const char mmcblk0[] = "/sys/block/mmcblk0/";
+unsigned long worst_write_perf = 20000; /* in KB/s */
+
+static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
+    unsigned long fields[11], read_perf, write_perf;
+    bool z;
+    char *cp, *buffer = NULL;
+    size_t i = 0;
+    FILE *fp = fdopen(fd, "rb");
+    getline(&buffer, &i, fp);
+    fclose(fp);
+    if (!buffer) {
+        return -errno;
+    }
+    i = strlen(buffer);
+    while ((i > 0) && (buffer[i - 1] == '\n')) {
+        buffer[--i] = '\0';
+    }
+    if (!*buffer) {
+        free(buffer);
+        return 0;
+    }
+    z = true;
+    for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
+        fields[i] = strtol(cp, &cp, 0);
+        if (fields[i] != 0) {
+            z = false;
+        }
+    }
+    if (z) { /* never accessed */
+        free(buffer);
+        return 0;
+    }
+
+    if (!strncmp(path, mmcblk0, sizeof(mmcblk0) - 1)) {
+        path += sizeof(mmcblk0) - 1;
+    }
+
+    printf("%s: %s\n", path, buffer);
+    free(buffer);
+
+    read_perf = 0;
+    if (fields[3]) {
+        read_perf = 512 * fields[2] / fields[3];
+    }
+    write_perf = 0;
+    if (fields[7]) {
+        write_perf = 512 * fields[6] / fields[7];
+    }
+    printf("%s: read: %luKB/s write: %luKB/s\n", path, read_perf, write_perf);
+    if ((write_perf > 1) && (write_perf < worst_write_perf)) {
+        worst_write_perf = write_perf;
+    }
+    return 0;
+}
+
+/* Copied policy from system/core/logd/LogBuffer.cpp */
+
+#define LOG_BUFFER_SIZE (256 * 1024)
+#define LOG_BUFFER_MIN_SIZE (64 * 1024UL)
+#define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL)
+
+static bool valid_size(unsigned long value) {
+    if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) {
+        return false;
+    }
+
+    long pages = sysconf(_SC_PHYS_PAGES);
+    if (pages < 1) {
+        return true;
+    }
+
+    long pagesize = sysconf(_SC_PAGESIZE);
+    if (pagesize <= 1) {
+        pagesize = PAGE_SIZE;
+    }
+
+    // maximum memory impact a somewhat arbitrary ~3%
+    pages = (pages + 31) / 32;
+    unsigned long maximum = pages * pagesize;
+
+    if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) {
+        return true;
+    }
+
+    return value <= maximum;
+}
+
+static unsigned long property_get_size(const char *key) {
+    unsigned long value;
+    char *cp, property[PROPERTY_VALUE_MAX];
+
+    property_get(key, property, "");
+    value = strtoul(property, &cp, 10);
+
+    switch(*cp) {
+    case 'm':
+    case 'M':
+        value *= 1024;
+    /* FALLTHRU */
+    case 'k':
+    case 'K':
+        value *= 1024;
+    /* FALLTHRU */
+    case '\0':
+        break;
+
+    default:
+        value = 0;
+    }
+
+    if (!valid_size(value)) {
+        value = 0;
+    }
+
+    return value;
+}
+
+/* timeout in ms */
+static unsigned long logcat_timeout(char *name) {
+    static const char global_tuneable[] = "persist.logd.size"; // Settings App
+    static const char global_default[] = "ro.logd.size";       // BoardConfig.mk
+    char key[PROP_NAME_MAX];
+    unsigned long property_size, default_size;
+
+    default_size = property_get_size(global_tuneable);
+    if (!default_size) {
+        default_size = property_get_size(global_default);
+    }
+
+    snprintf(key, sizeof(key), "%s.%s", global_tuneable, name);
+    property_size = property_get_size(key);
+
+    if (!property_size) {
+        snprintf(key, sizeof(key), "%s.%s", global_default, name);
+        property_size = property_get_size(key);
+    }
+
+    if (!property_size) {
+        property_size = default_size;
+    }
+
+    if (!property_size) {
+        property_size = LOG_BUFFER_SIZE;
+    }
+
+    /* Engineering margin is ten-fold our guess */
+    return 10 * (property_size + worst_write_perf) / worst_write_perf;
+}
+
+/* End copy from system/core/logd/LogBuffer.cpp */
+
 /* dumps the current system state to stdout */
 static void dumpstate() {
+    unsigned long timeout;
     time_t now = time(NULL);
     char build[PROPERTY_VALUE_MAX], fingerprint[PROPERTY_VALUE_MAX];
     char radio[PROPERTY_VALUE_MAX], bootloader[PROPERTY_VALUE_MAX];
@@ -133,7 +296,7 @@
 
     dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
     run_command("UPTIME", 10, "uptime", NULL);
-    dump_file("MMC PERF", "/sys/block/mmcblk0/stat");
+    dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
     dump_file("MEMORY INFO", "/proc/meminfo");
     run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-t", NULL);
     run_command("PROCRANK", 20, "procrank", NULL);
@@ -149,7 +312,6 @@
     dump_file("KERNEL WAKE SOURCES", "/d/wakeup_sources");
     dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
     dump_file("KERNEL SYNC", "/d/sync");
-    dump_file("KERNEL BLUEDROID", "/d/bluedroid");
 
     run_command("PROCESSES", 10, "ps", "-P", NULL);
     run_command("PROCESSES AND THREADS", 10, "ps", "-t", "-p", "-P", NULL);
@@ -169,9 +331,24 @@
     }
 
     // dump_file("EVENT LOG TAGS", "/etc/event-log-tags");
-    run_command("SYSTEM LOG", 20, "logcat", "-v", "threadtime", "-d", "*:v", NULL);
-    run_command("EVENT LOG", 20, "logcat", "-b", "events", "-v", "threadtime", "-d", "*:v", NULL);
-    run_command("RADIO LOG", 20, "logcat", "-b", "radio", "-v", "threadtime", "-d", "*:v", NULL);
+    // calculate timeout
+    timeout = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash");
+    if (timeout < 20000) {
+        timeout = 20000;
+    }
+    run_command("SYSTEM LOG", timeout / 1000, "logcat", "-v", "threadtime", "-d", "*:v", NULL);
+    timeout = logcat_timeout("events");
+    if (timeout < 20000) {
+        timeout = 20000;
+    }
+    run_command("EVENT LOG", timeout / 1000, "logcat", "-b", "events", "-v", "threadtime", "-d", "*:v", NULL);
+    timeout = logcat_timeout("radio");
+    if (timeout < 20000) {
+        timeout = 20000;
+    }
+    run_command("RADIO LOG", timeout / 1000, "logcat", "-b", "radio", "-v", "threadtime", "-d", "*:v", NULL);
+
+    run_command("LOG STATISTICS", 10, "logcat", "-b", "all", "-S", NULL);
 
     /* show the traces we collected in main(), if that was done */
     if (dump_traces_path != NULL) {
@@ -242,8 +419,6 @@
     run_command("LAST LOGCAT", 10, "logcat", "-L", "-v", "threadtime",
                                              "-b", "all", "-d", "*:v", NULL);
 
-    for_each_userid(do_dump_settings, NULL);
-
     /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
 
     run_command("NETWORK INTERFACES", 10, "ip", "link", NULL);
@@ -259,6 +434,8 @@
     run_command("ARP CACHE", 10, "ip", "-4", "neigh", "show", NULL);
     run_command("IPv6 ND CACHE", 10, "ip", "-6", "neigh", "show", NULL);
 
+    run_command("NETWORK DIAGNOSTICS", 10, "dumpsys", "connectivity", "--diag", NULL);
+
     run_command("IPTABLES", 10, SU_PATH, "root", "iptables", "-L", "-nvx", NULL);
     run_command("IP6TABLES", 10, SU_PATH, "root", "ip6tables", "-L", "-nvx", NULL);
     run_command("IPTABLE NAT", 10, SU_PATH, "root", "iptables", "-t", "nat", "-L", "-nvx", NULL);
@@ -362,6 +539,7 @@
     run_command("CHECKIN NETSTATS", 30, "dumpsys", "netstats", "--checkin", NULL);
     run_command("CHECKIN PROCSTATS", 30, "dumpsys", "procstats", "-c", NULL);
     run_command("CHECKIN USAGESTATS", 30, "dumpsys", "usagestats", "-c", NULL);
+    run_command("CHECKIN PACKAGE", 30, "dumpsys", "package", "--checkin", NULL);
 
     printf("========================================================\n");
     printf("== Running Application Activities\n");
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index d17a677..c5d3044 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -26,7 +26,6 @@
 
 typedef void (for_each_pid_func)(int, const char *);
 typedef void (for_each_tid_func)(int, int, const char *);
-typedef void (for_each_userid_func)(int);
 
 /* prints the contents of a file */
 int dump_file(const char *title, const char *path);
@@ -36,6 +35,16 @@
  */
 int dump_file_from_fd(const char *title, const char *path, int fd);
 
+/* 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
+ * to false when set to NULL. dump_from_fd will always be
+ * called with title NULL.
+ */
+int dump_files(const char *title, const char *dir,
+        bool (*skip)(const char *path),
+        int (*dump_from_fd)(const char *title, const char *path, int fd));
+
 /* forks a command and waits for it to finish -- terminate args with NULL */
 int run_command(const char *title, int timeout_seconds, const char *command, ...);
 
@@ -57,9 +66,6 @@
 /* for each thread in the system, run the specified function */
 void for_each_tid(for_each_tid_func func, const char *header);
 
-/* for each user id in the system, run the specified function */
-void for_each_userid(for_each_userid_func func, const char *header);
-
 /* Displays a blocked processes in-kernel wait channel */
 void show_wchan(int pid, int tid, const char *name);
 
@@ -69,9 +75,6 @@
 /* Gets the dmesg output for the kernel */
 void do_dmesg();
 
-/* Dumps settings for a given user id */
-void do_dump_settings(int userid);
-
 /* Prints the contents of all the routing tables, both IPv4 and IPv6. */
 void dump_route_tables();
 
diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c
index cf14c8b..d679787 100644
--- a/cmds/dumpstate/utils.c
+++ b/cmds/dumpstate/utils.c
@@ -206,22 +206,6 @@
     return;
 }
 
-void do_dump_settings(int userid) {
-    char title[255];
-    char dbpath[255];
-    char sql[255];
-    sprintf(title, "SYSTEM SETTINGS (user %d)", userid);
-    if (userid == 0) {
-        strcpy(dbpath, "/data/data/com.android.providers.settings/databases/settings.db");
-        strcpy(sql, "pragma user_version; select * from system; select * from secure; select * from global;");
-    } else {
-        sprintf(dbpath, "/data/system/users/%d/settings.db", userid);
-        strcpy(sql, "pragma user_version; select * from system; select * from secure;");
-    }
-    run_command(title, 20, SU_PATH, "root", "sqlite3", dbpath, sql, NULL);
-    return;
-}
-
 void do_dmesg() {
     printf("------ KERNEL LOG (dmesg) ------\n");
     /* Get size of kernel buffer */
@@ -306,7 +290,7 @@
             }
         }
     }
-    TEMP_FAILURE_RETRY(close(fd));
+    close(fd);
 
     if (!newline) printf("\n");
     if (title) printf("\n");
@@ -326,6 +310,75 @@
     return _dump_file_from_fd(title, path, fd);
 }
 
+/* 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
+ * to false when set to NULL. dump_from_fd will always be
+ * called with title NULL.
+ */
+int dump_files(const char *title, const char *dir,
+        bool (*skip)(const char *path),
+        int (*dump_from_fd)(const char *title, const char *path, int fd)) {
+    DIR *dirp;
+    struct dirent *d;
+    char *newpath = NULL;
+    char *slash = "/";
+    int fd, retval = 0;
+
+    if (title) {
+        printf("------ %s (%s) ------\n", title, dir);
+    }
+
+    if (dir[strlen(dir) - 1] == '/') {
+        ++slash;
+    }
+    dirp = opendir(dir);
+    if (dirp == NULL) {
+        retval = -errno;
+        fprintf(stderr, "%s: %s\n", dir, strerror(errno));
+        return retval;
+    }
+
+    if (!dump_from_fd) {
+        dump_from_fd = dump_file_from_fd;
+    }
+    for (; ((d = readdir(dirp))); free(newpath), newpath = NULL) {
+        if ((d->d_name[0] == '.')
+         && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
+          || (d->d_name[1] == '\0'))) {
+            continue;
+        }
+        asprintf(&newpath, "%s%s%s%s", dir, slash, d->d_name,
+                 (d->d_type == DT_DIR) ? "/" : "");
+        if (!newpath) {
+            retval = -errno;
+            continue;
+        }
+        if (skip && (*skip)(newpath)) {
+            continue;
+        }
+        if (d->d_type == DT_DIR) {
+            int ret = dump_files(NULL, newpath, skip, dump_from_fd);
+            if (ret < 0) {
+                retval = ret;
+            }
+            continue;
+        }
+        fd = TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
+        if (fd < 0) {
+            retval = fd;
+            printf("*** %s: %s\n", newpath, strerror(errno));
+            continue;
+        }
+        (*dump_from_fd)(NULL, newpath, fd);
+    }
+    closedir(dirp);
+    if (title) {
+        printf("\n");
+    }
+    return retval;
+}
+
 /* fd must have been opened with the flag O_NONBLOCK. With this flag set,
  * it's possible to avoid issues where opening the file itself can get
  * stuck.
diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp
index de6fd96..7090b36 100644
--- a/cmds/installd/commands.cpp
+++ b/cmds/installd/commands.cpp
@@ -50,7 +50,7 @@
         return -1;
     }
 
-    std::string _pkgdir(create_package_data_path(uuid, pkgname, 0));
+    std::string _pkgdir(create_data_user_package_path(uuid, 0, pkgname));
     const char* pkgdir = _pkgdir.c_str();
 
     if (mkdir(pkgdir, 0751) < 0) {
@@ -80,7 +80,7 @@
 
 int uninstall(const char *uuid, const char *pkgname, userid_t userid)
 {
-    std::string _pkgdir(create_package_data_path(uuid, pkgname, userid));
+    std::string _pkgdir(create_data_user_package_path(uuid, userid, pkgname));
     const char* pkgdir = _pkgdir.c_str();
 
     remove_profile_file(pkgname);
@@ -115,7 +115,7 @@
         return -1;
     }
 
-    std::string _pkgdir(create_package_data_path(uuid, pkgname, 0));
+    std::string _pkgdir(create_data_user_package_path(uuid, 0, pkgname));
     const char* pkgdir = _pkgdir.c_str();
 
     if (stat(pkgdir, &s) < 0) return -1;
@@ -141,7 +141,7 @@
 
 int delete_user_data(const char *uuid, const char *pkgname, userid_t userid)
 {
-    std::string _pkgdir(create_package_data_path(uuid, pkgname, userid));
+    std::string _pkgdir(create_data_user_package_path(uuid, userid, pkgname));
     const char* pkgdir = _pkgdir.c_str();
 
     return delete_dir_contents(pkgdir, 0, NULL);
@@ -149,7 +149,7 @@
 
 int make_user_data(const char *uuid, const char *pkgname, uid_t uid, userid_t userid, const char* seinfo)
 {
-    std::string _pkgdir(create_package_data_path(uuid, pkgname, userid));
+    std::string _pkgdir(create_data_user_package_path(uuid, userid, pkgname));
     const char* pkgdir = _pkgdir.c_str();
 
     if (mkdir(pkgdir, 0751) < 0) {
@@ -177,15 +177,48 @@
     return 0;
 }
 
-int move_user_data(const char *from_uuid, const char *to_uuid,
-        const char *package_name, appid_t appid, const char* seinfo) {
+int copy_complete_app(const char *from_uuid, const char *to_uuid,
+        const char *package_name, const char *data_app_name, appid_t appid,
+        const char* seinfo) {
     std::vector<userid_t> users = get_known_users(from_uuid);
 
-    // Copy package private data for all known users
+    // Copy app
+    {
+        std::string from(create_data_app_package_path(from_uuid, data_app_name));
+        std::string to(create_data_app_package_path(to_uuid, data_app_name));
+        std::string to_parent(create_data_app_path(to_uuid));
+
+        char *argv[] = {
+            (char*) kCpPath,
+            (char*) "-F", /* delete any existing destination file first (--remove-destination) */
+            (char*) "-p", /* preserve timestamps, ownership, and permissions */
+            (char*) "-R", /* recurse into subdirectories (DEST must be a directory) */
+            (char*) "-P", /* Do not follow symlinks [default] */
+            (char*) "-d", /* don't dereference symlinks */
+            (char*) from.c_str(),
+            (char*) to_parent.c_str()
+        };
+
+        LOG(DEBUG) << "Copying " << from << " to " << to;
+        int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true);
+
+        if (rc != 0) {
+            LOG(ERROR) << "Failed copying " << from << " to " << to
+                    << ": status " << rc;
+            goto fail;
+        }
+
+        if (selinux_android_restorecon(to.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
+            LOG(ERROR) << "Failed to restorecon " << to;
+            goto fail;
+        }
+    }
+
+    // Copy private data for all known users
     for (auto user : users) {
-        std::string from(create_package_data_path(from_uuid, package_name, user));
-        std::string to(create_package_data_path(to_uuid, package_name, user));
-        std::string to_user(create_data_user_path(to_uuid, user));
+        std::string from(create_data_user_package_path(from_uuid, user, package_name));
+        std::string to(create_data_user_package_path(to_uuid, user, package_name));
+        std::string to_parent(create_data_user_path(to_uuid, user));
 
         // Data source may not exist for all users; that's okay
         if (access(from.c_str(), F_OK) != 0) {
@@ -213,7 +246,7 @@
             (char*) "-P", /* Do not follow symlinks [default] */
             (char*) "-d", /* don't dereference symlinks */
             (char*) from.c_str(),
-            (char*) to_user.c_str()
+            (char*) to_parent.c_str()
         };
 
         LOG(DEBUG) << "Copying " << from << " to " << to;
@@ -224,26 +257,28 @@
                     << ": status " << rc;
             goto fail;
         }
-
-        if (restorecon_data(to_uuid, package_name, seinfo, uid) != 0) {
-            LOG(ERROR) << "Failed to restorecon " << to;
-            goto fail;
-        }
     }
 
-    // Copy successful, so delete old data
-    for (auto user : users) {
-        std::string from(create_package_data_path(from_uuid, package_name, user));
-        if (delete_dir_contents(from.c_str(), 1, NULL) != 0) {
-            LOG(WARNING) << "Failed to delete " << from;
-        }
+    if (restorecon_data(to_uuid, package_name, seinfo, multiuser_get_uid(0, appid)) != 0) {
+        LOG(ERROR) << "Failed to restorecon";
+        goto fail;
     }
+
+    // We let the framework scan the new location and persist that before
+    // deleting the data in the old location; this ordering ensures that
+    // we can recover from things like battery pulls.
     return 0;
 
 fail:
     // Nuke everything we might have already copied
+    {
+        std::string to(create_data_app_package_path(to_uuid, data_app_name));
+        if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
+            LOG(WARNING) << "Failed to rollback " << to;
+        }
+    }
     for (auto user : users) {
-        std::string to(create_package_data_path(to_uuid, package_name, user));
+        std::string to(create_data_user_package_path(to_uuid, user, package_name));
         if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
             LOG(WARNING) << "Failed to rollback " << to;
         }
@@ -289,7 +324,7 @@
 int delete_cache(const char *uuid, const char *pkgname, userid_t userid)
 {
     std::string _cachedir(
-            create_package_data_path(uuid, pkgname, userid) + CACHE_DIR_POSTFIX);
+            create_data_user_package_path(uuid, userid, pkgname) + CACHE_DIR_POSTFIX);
     const char* cachedir = _cachedir.c_str();
 
     /* delete contents, not the directory, no exceptions */
@@ -299,7 +334,7 @@
 int delete_code_cache(const char *uuid, const char *pkgname, userid_t userid)
 {
     std::string _codecachedir(
-            create_package_data_path(uuid, pkgname, userid) + CACHE_DIR_POSTFIX);
+            create_data_user_package_path(uuid, userid, pkgname) + CODE_CACHE_DIR_POSTFIX);
     const char* codecachedir = _codecachedir.c_str();
 
     struct stat s;
@@ -454,7 +489,7 @@
     }
 }
 
-int get_size(const char *uuid, const char *pkgname, userid_t userid, const char *apkpath,
+int get_size(const char *uuid, const char *pkgname, int userid, const char *apkpath,
              const char *libdirpath, const char *fwdlock_apkpath, const char *asecpath,
              const char *instruction_set, int64_t *_codesize, int64_t *_datasize,
              int64_t *_cachesize, int64_t* _asecsize)
@@ -470,30 +505,38 @@
     int64_t cachesize = 0;
     int64_t asecsize = 0;
 
-        /* count the source apk as code -- but only if it's not
-         * on the /system partition and its not on the sdcard.
-         */
+    /* count the source apk as code -- but only if it's not
+     * on the /system partition and its not on the sdcard. */
     if (validate_system_app_path(apkpath) &&
             strncmp(apkpath, android_asec_dir.path, android_asec_dir.len) != 0) {
         if (stat(apkpath, &s) == 0) {
             codesize += stat_size(&s);
+            if (S_ISDIR(s.st_mode)) {
+                d = opendir(apkpath);
+                if (d != NULL) {
+                    dfd = dirfd(d);
+                    codesize += calculate_dir_size(dfd);
+                    closedir(d);
+                }
+            }
         }
     }
-        /* count the forward locked apk as code if it is given
-         */
+
+    /* count the forward locked apk as code if it is given */
     if (fwdlock_apkpath != NULL && fwdlock_apkpath[0] != '!') {
         if (stat(fwdlock_apkpath, &s) == 0) {
             codesize += stat_size(&s);
         }
     }
-        /* count the cached dexfile as code */
+
+    /* count the cached dexfile as code */
     if (!create_cache_path(path, apkpath, instruction_set)) {
         if (stat(path, &s) == 0) {
             codesize += stat_size(&s);
         }
     }
 
-        /* add in size of any libraries */
+    /* add in size of any libraries */
     if (libdirpath != NULL && libdirpath[0] != '!') {
         d = opendir(libdirpath);
         if (d != NULL) {
@@ -503,68 +546,76 @@
         }
     }
 
-        /* compute asec size if it is given
-         */
+    /* compute asec size if it is given */
     if (asecpath != NULL && asecpath[0] != '!') {
         if (stat(asecpath, &s) == 0) {
             asecsize += stat_size(&s);
         }
     }
 
-    std::string _pkgdir(create_package_data_path(uuid, pkgname, userid));
-    const char* pkgdir = _pkgdir.c_str();
-
-    d = opendir(pkgdir);
-    if (d == NULL) {
-        goto done;
+    std::vector<userid_t> users;
+    if (userid == -1) {
+        users = get_known_users(uuid);
+    } else {
+        users.push_back(userid);
     }
-    dfd = dirfd(d);
 
-    /* most stuff in the pkgdir is data, except for the "cache"
-     * directory and below, which is cache, and the "lib" directory
-     * and below, which is code...
-     */
-    while ((de = readdir(d))) {
-        const char *name = de->d_name;
+    for (auto user : users) {
+        std::string _pkgdir(create_data_user_package_path(uuid, user, pkgname));
+        const char* pkgdir = _pkgdir.c_str();
 
-        if (de->d_type == DT_DIR) {
-            int subfd;
-            int64_t statsize = 0;
-            int64_t dirsize = 0;
-                /* always skip "." and ".." */
-            if (name[0] == '.') {
-                if (name[1] == 0) continue;
-                if ((name[1] == '.') && (name[2] == 0)) continue;
-            }
-            if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
-                statsize = stat_size(&s);
-            }
-            subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
-            if (subfd >= 0) {
-                dirsize = calculate_dir_size(subfd);
-            }
-            if(!strcmp(name,"lib")) {
-                codesize += dirsize + statsize;
-            } else if(!strcmp(name,"cache")) {
-                cachesize += dirsize + statsize;
+        d = opendir(pkgdir);
+        if (d == NULL) {
+            PLOG(WARNING) << "Failed to open " << pkgdir;
+            continue;
+        }
+        dfd = dirfd(d);
+
+        /* most stuff in the pkgdir is data, except for the "cache"
+         * directory and below, which is cache, and the "lib" directory
+         * and below, which is code...
+         */
+        while ((de = readdir(d))) {
+            const char *name = de->d_name;
+
+            if (de->d_type == DT_DIR) {
+                int subfd;
+                int64_t statsize = 0;
+                int64_t dirsize = 0;
+                    /* always skip "." and ".." */
+                if (name[0] == '.') {
+                    if (name[1] == 0) continue;
+                    if ((name[1] == '.') && (name[2] == 0)) continue;
+                }
+                if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
+                    statsize = stat_size(&s);
+                }
+                subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
+                if (subfd >= 0) {
+                    dirsize = calculate_dir_size(subfd);
+                }
+                if(!strcmp(name,"lib")) {
+                    codesize += dirsize + statsize;
+                } else if(!strcmp(name,"cache")) {
+                    cachesize += dirsize + statsize;
+                } else {
+                    datasize += dirsize + statsize;
+                }
+            } else if (de->d_type == DT_LNK && !strcmp(name,"lib")) {
+                // This is the symbolic link to the application's library
+                // code.  We'll count this as code instead of data, since
+                // it is not something that the app creates.
+                if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
+                    codesize += stat_size(&s);
+                }
             } else {
-                datasize += dirsize + statsize;
-            }
-        } else if (de->d_type == DT_LNK && !strcmp(name,"lib")) {
-            // This is the symbolic link to the application's library
-            // code.  We'll count this as code instead of data, since
-            // it is not something that the app creates.
-            if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
-                codesize += stat_size(&s);
-            }
-        } else {
-            if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
-                datasize += stat_size(&s);
+                if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
+                    datasize += stat_size(&s);
+                }
             }
         }
+        closedir(d);
     }
-    closedir(d);
-done:
     *_codesize = codesize;
     *_datasize = datasize;
     *_cachesize = cachesize;
@@ -684,6 +735,15 @@
     ALOGE("execv(%s) failed: %s\n", PATCHOAT_BIN, strerror(errno));
 }
 
+static bool check_boolean_property(const char* property_name, bool default_value = false) {
+    char tmp_property_value[PROPERTY_VALUE_MAX];
+    bool have_property = property_get(property_name, tmp_property_value, nullptr) > 0;
+    if (!have_property) {
+        return default_value;
+    }
+    return strcmp(tmp_property_value, "true") == 0;
+}
+
 static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name,
     const char* output_file_name, int swap_fd, const char *pkgname, const char *instruction_set,
     bool vm_safe_mode, bool debuggable)
@@ -744,9 +804,8 @@
                              (strcmp(vold_decrypt, "trigger_restart_min_framework") == 0 ||
                              (strcmp(vold_decrypt, "1") == 0)));
 
-    char use_jit_property[PROPERTY_VALUE_MAX];
-    bool have_jit_property = property_get("debug.usejit", use_jit_property, NULL) > 0;
-    bool use_jit = have_jit_property && strcmp(use_jit_property, "true") == 0;
+    bool use_jit = check_boolean_property("debug.usejit");
+    bool generate_debug_info = check_boolean_property("debug.generate-debug-info");
 
     static const char* DEX2OAT_BIN = "/system/bin/dex2oat";
 
@@ -839,6 +898,7 @@
                      + (have_dex2oat_threads_flag ? 1 : 0)
                      + (have_dex2oat_swap_fd ? 1 : 0)
                      + (have_dex2oat_relocation_skip_flag ? 2 : 0)
+                     + (generate_debug_info ? 1 : 0)
                      + (debuggable ? 1 : 0)
                      + dex2oat_flags_count];
     int i = 0;
@@ -877,6 +937,9 @@
     if (have_dex2oat_swap_fd) {
         argv[i++] = dex2oat_swap_fd;
     }
+    if (generate_debug_info) {
+        argv[i++] = "--generate-debug-info";
+    }
     if (debuggable) {
         argv[i++] = "--debuggable";
     }
@@ -921,20 +984,49 @@
 }
 
 /*
- * Whether dexopt should use a swap file when compiling an APK. If kAlwaysProvideSwapFile, do this
- * on all devices (dex2oat will make a more informed decision itself, anyways). Otherwise, only do
- * this on a low-mem device.
+ * Whether dexopt should use a swap file when compiling an APK.
+ *
+ * If kAlwaysProvideSwapFile, do this on all devices (dex2oat will make a more informed decision
+ * itself, anyways).
+ *
+ * Otherwise, read "dalvik.vm.dex2oat-swap". If the property exists, return whether it is "true".
+ *
+ * Otherwise, return true if this is a low-mem device.
+ *
+ * Otherwise, return default value.
  */
-static bool kAlwaysProvideSwapFile = true;
+static bool kAlwaysProvideSwapFile = false;
+static bool kDefaultProvideSwapFile = true;
 
 static bool ShouldUseSwapFileForDexopt() {
     if (kAlwaysProvideSwapFile) {
         return true;
     }
 
-    char low_mem_buf[PROPERTY_VALUE_MAX];
-    property_get("ro.config.low_ram", low_mem_buf, "");
-    return (strcmp(low_mem_buf, "true") == 0);
+    // Check the "override" property. If it exists, return value == "true".
+    char dex2oat_prop_buf[PROPERTY_VALUE_MAX];
+    if (property_get("dalvik.vm.dex2oat-swap", dex2oat_prop_buf, "") > 0) {
+        if (strcmp(dex2oat_prop_buf, "true") == 0) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    // Shortcut for default value. This is an implementation optimization for the process sketched
+    // above. If the default value is true, we can avoid to check whether this is a low-mem device,
+    // as low-mem is never returning false. The compiler will optimize this away if it can.
+    if (kDefaultProvideSwapFile) {
+        return true;
+    }
+
+    bool is_low_mem = check_boolean_property("ro.config.low_ram");
+    if (is_low_mem) {
+        return true;
+    }
+
+    // Default value must be false here.
+    return kDefaultProvideSwapFile;
 }
 
 /*
@@ -1448,7 +1540,7 @@
     struct stat s, libStat;
     int rc = 0;
 
-    std::string _pkgdir(create_package_data_path(uuid, pkgname, userId));
+    std::string _pkgdir(create_data_user_package_path(uuid, userId, pkgname));
     std::string _libsymlink(_pkgdir + PKG_LIB_POSTFIX);
 
     const char* pkgdir = _pkgdir.c_str();
@@ -1639,7 +1731,7 @@
 
     // Special case for owner on internal storage
     if (uuid == nullptr) {
-        std::string path(create_package_data_path(nullptr, pkgName, 0));
+        std::string path(create_data_user_package_path(nullptr, 0, pkgName));
 
         if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid, flags) < 0) {
             PLOG(ERROR) << "restorecon failed for " << path;
@@ -1717,6 +1809,31 @@
     return delete_dir_contents(apk_path, 1 /* also_delete_dir */ , NULL /* exclusion_predicate */);
 }
 
+int link_file(const char* relative_path, const char* from_base, const char* to_base) {
+    char from_path[PKG_PATH_MAX];
+    char to_path[PKG_PATH_MAX];
+    snprintf(from_path, PKG_PATH_MAX, "%s/%s", from_base, relative_path);
+    snprintf(to_path, PKG_PATH_MAX, "%s/%s", to_base, relative_path);
+
+    if (validate_apk_path_subdirs(from_path)) {
+        ALOGE("invalid app data sub-path '%s' (bad prefix)\n", from_path);
+        return -1;
+    }
+
+    if (validate_apk_path_subdirs(to_path)) {
+        ALOGE("invalid app data sub-path '%s' (bad prefix)\n", to_path);
+        return -1;
+    }
+
+    const int ret = link(from_path, to_path);
+    if (ret < 0) {
+        ALOGE("link(%s, %s) failed : %s", from_path, to_path, strerror(errno));
+        return -1;
+    }
+
+    return 0;
+}
+
 int calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path,
         const char *instruction_set) {
     char *file_name_start;
diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp
index 3a86181..13e3168 100644
--- a/cmds/installd/installd.cpp
+++ b/cmds/installd/installd.cpp
@@ -124,10 +124,10 @@
     return delete_user_data(parse_null(arg[0]), arg[1], atoi(arg[2])); /* uuid, pkgname, userid */
 }
 
-static int do_mv_user_data(char **arg, char reply[REPLY_MAX] __unused)
+static int do_cp_complete_app(char **arg, char reply[REPLY_MAX] __unused)
 {
-    // from_uuid, to_uuid, pkgname, appid, seinfo
-    return move_user_data(parse_null(arg[0]), parse_null(arg[1]), arg[2], atoi(arg[3]), arg[4]);
+    // from_uuid, to_uuid, package_name, data_app_name, appid, seinfo
+    return copy_complete_app(parse_null(arg[0]), parse_null(arg[1]), arg[2], arg[3], atoi(arg[4]), arg[5]);
 }
 
 static int do_mk_user_data(char **arg, char reply[REPLY_MAX] __unused)
@@ -179,6 +179,12 @@
     return rm_package_dir(arg[0]);
 }
 
+static int do_link_file(char **arg, char reply[REPLY_MAX] __unused)
+{
+    /* relative_path, from_base, to_base */
+    return link_file(arg[0], arg[1], arg[2]);
+}
+
 struct cmdinfo {
     const char *name;
     unsigned numargs;
@@ -200,7 +206,7 @@
     { "rmcodecache",          3, do_rm_code_cache },
     { "getsize",              8, do_get_size },
     { "rmuserdata",           3, do_rm_user_data },
-    { "mvuserdata",           5, do_mv_user_data },
+    { "cpcompleteapp",        6, do_cp_complete_app },
     { "movefiles",            0, do_movefiles },
     { "linklib",              4, do_linklib },
     { "mkuserdata",           5, do_mk_user_data },
@@ -209,7 +215,8 @@
     { "idmap",                3, do_idmap },
     { "restorecondata",       4, do_restorecon_data },
     { "createoatdir",         2, do_create_oat_dir },
-    { "rmpackagedir",         1, do_rm_package_dir},
+    { "rmpackagedir",         1, do_rm_package_dir },
+    { "linkfile",             3, do_link_file }
 };
 
 static int readx(int s, void *_buf, int count)
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index f31bf4f..7ec5793 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -142,10 +142,6 @@
 
 /* util.c */
 
-// TODO: rename to create_data_user_package_path
-std::string create_package_data_path(const char* volume_uuid,
-        const char* package_name, userid_t user);
-
 int create_pkg_path(char path[PKG_PATH_MAX],
                     const char *pkgname,
                     const char *postfix,
@@ -153,8 +149,15 @@
 
 std::string create_data_path(const char* volume_uuid);
 
+std::string create_data_app_path(const char* volume_uuid);
+
+std::string create_data_app_package_path(const char* volume_uuid, const char* package_name);
+
 std::string create_data_user_path(const char* volume_uuid, userid_t userid);
 
+std::string create_data_user_package_path(const char* volume_uuid,
+        userid_t user, const char* package_name);
+
 std::string create_data_media_path(const char* volume_uuid, userid_t userid);
 
 std::vector<userid_t> get_known_users(const char* volume_uuid);
@@ -200,6 +203,7 @@
 int copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix);
 
 int validate_apk_path(const char *path);
+int validate_apk_path_subdirs(const char *path);
 
 int append_and_increment(char** dst, const char* src, size_t* dst_size);
 
@@ -221,8 +225,9 @@
 int delete_user_data(const char *uuid, const char *pkgname, userid_t userid);
 int make_user_data(const char *uuid, const char *pkgname, uid_t uid,
         userid_t userid, const char* seinfo);
-int move_user_data(const char* from_uuid, const char *to_uuid,
-        const char *package_name, appid_t appid, const char* seinfo);
+int copy_complete_app(const char* from_uuid, const char *to_uuid,
+        const char *package_name, const char *data_app_name, appid_t appid,
+        const char* seinfo);
 int make_user_config(userid_t userid);
 int delete_user(const char *uuid, userid_t userid);
 int delete_cache(const char *uuid, const char *pkgname, userid_t userid);
@@ -230,9 +235,11 @@
 int move_dex(const char *src, const char *dst, const char *instruction_set);
 int rm_dex(const char *path, const char *instruction_set);
 int protect(char *pkgname, gid_t gid);
-int get_size(const char *uuid, const char *pkgname, userid_t userid, const char *apkpath, const char *libdirpath,
-             const char *fwdlock_apkpath, const char *asecpath, const char *instruction_set,
-             int64_t *codesize, int64_t *datasize, int64_t *cachesize, int64_t *asecsize);
+int get_size(const char *uuid, const char *pkgname, int userid,
+        const char *apkpath, const char *libdirpath,
+        const char *fwdlock_apkpath, const char *asecpath,
+        const char *instruction_set, int64_t *codesize, int64_t *datasize,
+        int64_t *cachesize, int64_t *asecsize);
 int free_cache(const char *uuid, int64_t free_size);
 int dexopt(const char *apk_path, uid_t uid, bool is_public, const char *pkgName,
            const char *instruction_set, int dexopt_needed, bool vm_safe_mode,
@@ -248,3 +255,4 @@
                             const char *instruction_set);
 int move_package_dir(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path,
                             const char *instruction_set);
+int link_file(const char *relative_path, const char *from_base, const char *to_base);
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 4ce559d..5e397f9 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -455,6 +455,13 @@
             create_data_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b"));
 }
 
+TEST_F(UtilsTest, CreateDataAppPath) {
+    EXPECT_EQ("/data/app", create_data_app_path(nullptr));
+
+    EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/app",
+            create_data_app_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b"));
+}
+
 TEST_F(UtilsTest, CreateDataUserPath) {
     EXPECT_EQ("/data/data", create_data_user_path(nullptr, 0));
     EXPECT_EQ("/data/user/10", create_data_user_path(nullptr, 10));
@@ -475,14 +482,21 @@
             create_data_media_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 10));
 }
 
-TEST_F(UtilsTest, CreatePackageDataPath) {
-    EXPECT_EQ("/data/data/com.example", create_package_data_path(nullptr, "com.example", 0));
-    EXPECT_EQ("/data/user/10/com.example", create_package_data_path(nullptr, "com.example", 10));
+TEST_F(UtilsTest, CreateDataAppPackagePath) {
+    EXPECT_EQ("/data/app/com.example", create_data_app_package_path(nullptr, "com.example"));
+
+    EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/app/com.example",
+            create_data_app_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", "com.example"));
+}
+
+TEST_F(UtilsTest, CreateDataUserPackagePath) {
+    EXPECT_EQ("/data/data/com.example", create_data_user_package_path(nullptr, 0, "com.example"));
+    EXPECT_EQ("/data/user/10/com.example", create_data_user_package_path(nullptr, 10, "com.example"));
 
     EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/user/0/com.example",
-            create_package_data_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", "com.example", 0));
+            create_data_user_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, "com.example"));
     EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/user/10/com.example",
-            create_package_data_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", "com.example", 10));
+            create_data_user_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 10, "com.example"));
 }
 
 }
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index ba411cd..7db3fb9 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -37,16 +37,31 @@
 }
 
 /**
+ * Create the path name where package app contents should be stored for
+ * the given volume UUID and package name.  An empty UUID is assumed to
+ * be internal storage.
+ */
+std::string create_data_app_package_path(const char* volume_uuid,
+        const char* package_name) {
+    CHECK(is_valid_filename(package_name));
+    CHECK(is_valid_package_name(package_name) == 0);
+
+    return StringPrintf("%s/%s",
+            create_data_app_path(volume_uuid).c_str(), package_name);
+}
+
+/**
  * Create the path name where package data should be stored for the given
  * volume UUID, package name, and user ID. An empty UUID is assumed to be
  * internal storage.
  */
-std::string create_package_data_path(const char* volume_uuid,
-        const char* package_name, userid_t user) {
+std::string create_data_user_package_path(const char* volume_uuid,
+        userid_t user, const char* package_name) {
     CHECK(is_valid_filename(package_name));
     CHECK(is_valid_package_name(package_name) == 0);
 
-    return StringPrintf("%s/%s", create_data_user_path(volume_uuid, user).c_str(), package_name);
+    return StringPrintf("%s/%s",
+            create_data_user_path(volume_uuid, user).c_str(), package_name);
 }
 
 int create_pkg_path(char path[PKG_PATH_MAX], const char *pkgname,
@@ -56,7 +71,7 @@
         return -1;
     }
 
-    std::string _tmp(create_package_data_path(nullptr, pkgname, userid) + postfix);
+    std::string _tmp(create_data_user_package_path(nullptr, userid, pkgname) + postfix);
     const char* tmp = _tmp.c_str();
     if (strlen(tmp) >= PKG_PATH_MAX) {
         path[0] = '\0';
@@ -77,6 +92,13 @@
 }
 
 /**
+ * Create the path name for app data.
+ */
+std::string create_data_app_path(const char* volume_uuid) {
+    return StringPrintf("%s/app", create_data_path(volume_uuid).c_str());
+}
+
+/**
  * Create the path name for user data for a certain userid.
  */
 std::string create_data_user_path(const char* volume_uuid, userid_t userid) {
@@ -1021,15 +1043,13 @@
 }
 
 /**
- * Check whether path points to a valid path for an APK file. Only one level of
- * subdirectory names is allowed. Returns -1 when an invalid path is encountered
- * and 0 when a valid path is encountered.
+ * Check whether path points to a valid path for an APK file. The path must
+ * begin with a whitelisted prefix path and must be no deeper than |maxSubdirs| within
+ * that path. Returns -1 when an invalid path is encountered and 0 when a valid path
+ * is encountered.
  */
-int validate_apk_path(const char *path)
-{
+static int validate_apk_path_internal(const char *path, int maxSubdirs) {
     const dir_rec_t* dir = NULL;
-    int maxSubdirs = 1;
-
     if (!strncmp(path, android_app_dir.path, android_app_dir.len)) {
         dir = &android_app_dir;
     } else if (!strncmp(path, android_app_private_dir.path, android_app_private_dir.len)) {
@@ -1038,7 +1058,9 @@
         dir = &android_asec_dir;
     } else if (!strncmp(path, android_mnt_expand_dir.path, android_mnt_expand_dir.len)) {
         dir = &android_mnt_expand_dir;
-        maxSubdirs = 2;
+        if (maxSubdirs < 2) {
+            maxSubdirs = 2;
+        }
     } else {
         return -1;
     }
@@ -1046,6 +1068,14 @@
     return validate_path(dir, path, maxSubdirs);
 }
 
+int validate_apk_path(const char* path) {
+    return validate_apk_path_internal(path, 1 /* maxSubdirs */);
+}
+
+int validate_apk_path_subdirs(const char* path) {
+    return validate_apk_path_internal(path, 3 /* maxSubdirs */);
+}
+
 int append_and_increment(char** dst, const char* src, size_t* dst_size) {
     ssize_t ret = strlcpy(*dst, src, *dst_size);
     if (ret < 0 || (size_t) ret >= *dst_size) {
diff --git a/cmds/service/service.cpp b/cmds/service/service.cpp
index 97fc47c..428b87c 100644
--- a/cmds/service/service.cpp
+++ b/cmds/service/service.cpp
@@ -146,6 +146,15 @@
                                 break;
                             }
                             data.writeInt32(atoi(argv[optind++]));
+                        } else if (strcmp(argv[optind], "i64") == 0) {
+                            optind++;
+                            if (optind >= argc) {
+                                aerr << "service: no integer supplied for 'i64'" << endl;
+                                wantsUsage = true;
+                                result = 10;
+                                break;
+                            }
+                            data.writeInt64(atoll(argv[optind++]));
                         } else if (strcmp(argv[optind], "s16") == 0) {
                             optind++;
                             if (optind >= argc) {
@@ -155,6 +164,24 @@
                                 break;
                             }
                             data.writeString16(String16(argv[optind++]));
+                        } else if (strcmp(argv[optind], "f") == 0) {
+                            optind++;
+                            if (optind >= argc) {
+                                aerr << "service: no number supplied for 'f'" << endl;
+                                wantsUsage = true;
+                                result = 10;
+                                break;
+                            }
+                            data.writeFloat(atof(argv[optind++]));
+                        } else if (strcmp(argv[optind], "d") == 0) {
+                            optind++;
+                            if (optind >= argc) {
+                                aerr << "service: no number supplied for 'd'" << endl;
+                                wantsUsage = true;
+                                result = 10;
+                                break;
+                            }
+                            data.writeDouble(atof(argv[optind++]));
                         } else if (strcmp(argv[optind], "null") == 0) {
                             optind++;
                             data.writeStrongBinder(NULL);
@@ -272,9 +299,12 @@
         aout << "Usage: service [-h|-?]\n"
                 "       service list\n"
                 "       service check SERVICE\n"
-                "       service call SERVICE CODE [i32 INT | s16 STR] ...\n"
+                "       service call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR ] ...\n"
                 "Options:\n"
-                "   i32: Write the integer INT into the send parcel.\n"
+                "   i32: Write the 32-bit integer N into the send parcel.\n"
+                "   i64: Write the 64-bit integer N into the send parcel.\n"
+                "   f:   Write the 32-bit single-precision number N into the send parcel.\n"
+                "   d:   Write the 64-bit double-precision number N into the send parcel.\n"
                 "   s16: Write the UTF-16 string STR into the send parcel.\n";
 //                "   intent: Write and Intent int the send parcel. ARGS can be\n"
 //                "       action=STR data=STR type=STR launchFlags=INT component=STR categories=STR[,STR,...]\n";
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index cacfe14..7fa9a39 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -361,6 +361,7 @@
 
     selinux_enabled = is_selinux_enabled();
     sehandle = selinux_android_service_context_handle();
+    selinux_status_open(true);
 
     if (selinux_enabled > 0) {
         if (sehandle == NULL) {
diff --git a/data/etc/android.hardware.audio.pro.xml b/data/etc/android.hardware.audio.pro.xml
new file mode 100644
index 0000000..5328d41
--- /dev/null
+++ b/data/etc/android.hardware.audio.pro.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<!-- This is the feature indicating professional audio, as specified by the
+     CDD. ONLY devices that meet the CDD's requirements may declare this
+     feature. -->
+<permissions>
+    <feature name="android.hardware.audio.pro" />
+</permissions>
diff --git a/data/etc/android.hardware.fingerprint.xml b/data/etc/android.hardware.fingerprint.xml
new file mode 100644
index 0000000..3181e7e
--- /dev/null
+++ b/data/etc/android.hardware.fingerprint.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<!-- This is the standard set of features for a biometric fingerprint sensor. -->
+<permissions>
+    <feature name="android.hardware.fingerprint" />
+</permissions>
diff --git a/data/etc/android.hardware.sensor.hifi_sensors.xml b/data/etc/android.hardware.sensor.hifi_sensors.xml
new file mode 100644
index 0000000..bb3901c
--- /dev/null
+++ b/data/etc/android.hardware.sensor.hifi_sensors.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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.
+-->
+
+<!-- Feature for devices supporting hifi sensors. -->
+<permissions>
+    <feature name="android.hardware.sensor.hifi_sensors" />
+</permissions>
diff --git a/data/etc/android.software.midi.xml b/data/etc/android.software.midi.xml
new file mode 100644
index 0000000..a03cd55
--- /dev/null
+++ b/data/etc/android.software.midi.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<permissions>
+    <feature name="android.software.midi" />
+</permissions>
diff --git a/include/android/configuration.h b/include/android/configuration.h
index be00066..7573cca 100644
--- a/include/android/configuration.h
+++ b/include/android/configuration.h
@@ -78,6 +78,10 @@
     ACONFIGURATION_SCREENLONG_NO = 0x1,
     ACONFIGURATION_SCREENLONG_YES = 0x2,
 
+    ACONFIGURATION_SCREENROUND_ANY = 0x00,
+    ACONFIGURATION_SCREENROUND_NO = 0x1,
+    ACONFIGURATION_SCREENROUND_YES = 0x2,
+
     ACONFIGURATION_UI_MODE_TYPE_ANY = 0x00,
     ACONFIGURATION_UI_MODE_TYPE_NORMAL = 0x01,
     ACONFIGURATION_UI_MODE_TYPE_DESK = 0x02,
@@ -115,6 +119,7 @@
     ACONFIGURATION_UI_MODE = 0x1000,
     ACONFIGURATION_SMALLEST_SCREEN_SIZE = 0x2000,
     ACONFIGURATION_LAYOUTDIR = 0x4000,
+    ACONFIGURATION_SCREEN_ROUND = 0x8000,
 
     ACONFIGURATION_MNC_ZERO = 0xffff,
 };
@@ -288,6 +293,16 @@
 void AConfiguration_setScreenLong(AConfiguration* config, int32_t screenLong);
 
 /**
+ * Return the current ACONFIGURATION_SCREENROUND_* set in the configuration.
+ */
+int32_t AConfiguration_getScreenRound(AConfiguration* config);
+
+/**
+ * Set the current screen round in the configuration.
+ */
+void AConfiguration_setScreenRound(AConfiguration* config, int32_t screenRound);
+
+/**
  * Return the current ACONFIGURATION_UI_MODE_TYPE_* set in the configuration.
  */
 int32_t AConfiguration_getUiModeType(AConfiguration* config);
diff --git a/include/android/input.h b/include/android/input.h
index a660761..efbbb85 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -305,6 +305,12 @@
     /* The pointer is not down but has exited the boundaries of a window or view.
      */
     AMOTION_EVENT_ACTION_HOVER_EXIT = 10,
+
+    /* One or more buttons have been pressed. */
+    AMOTION_EVENT_ACTION_BUTTON_PRESS = 11,
+
+    /* One or more buttons have been released. */
+    AMOTION_EVENT_ACTION_BUTTON_RELEASE = 12,
 };
 
 /*
@@ -405,6 +411,8 @@
     AMOTION_EVENT_BUTTON_TERTIARY = 1 << 2,
     AMOTION_EVENT_BUTTON_BACK = 1 << 3,
     AMOTION_EVENT_BUTTON_FORWARD = 1 << 4,
+    AMOTION_EVENT_BUTTON_STYLUS_PRIMARY = 1 << 5,
+    AMOTION_EVENT_BUTTON_STYLUS_SECONDARY = 1 << 6,
 };
 
 /*
@@ -445,6 +453,7 @@
     AINPUT_SOURCE_TOUCHSCREEN = 0x00001000 | AINPUT_SOURCE_CLASS_POINTER,
     AINPUT_SOURCE_MOUSE = 0x00002000 | AINPUT_SOURCE_CLASS_POINTER,
     AINPUT_SOURCE_STYLUS = 0x00004000 | AINPUT_SOURCE_CLASS_POINTER,
+    AINPUT_SOURCE_BLUETOOTH_STYLUS = 0x00008000 | AINPUT_SOURCE_STYLUS,
     AINPUT_SOURCE_TRACKBALL = 0x00010000 | AINPUT_SOURCE_CLASS_NAVIGATION,
     AINPUT_SOURCE_TOUCHPAD = 0x00100000 | AINPUT_SOURCE_CLASS_POSITION,
     AINPUT_SOURCE_TOUCH_NAVIGATION = 0x00200000 | AINPUT_SOURCE_CLASS_NONE,
diff --git a/include/android/keycodes.h b/include/android/keycodes.h
index 268d092..de9e735 100644
--- a/include/android/keycodes.h
+++ b/include/android/keycodes.h
@@ -303,15 +303,14 @@
     AKEYCODE_TV_MEDIA_CONTEXT_MENU = 257,
     AKEYCODE_TV_TIMER_PROGRAMMING = 258,
     AKEYCODE_HELP            = 259,
-    /** Primary stem key for Wear
-     * Main power/reset button on watch. */
-    AKEYCODE_STEM_PRIMARY = 264,
-    /** Generic stem key 1 for Wear */
-    AKEYCODE_STEM_1 = 265,
-    /** Generic stem key 2 for Wear */
-    AKEYCODE_STEM_2 = 266,
-    /** Generic stem key 3 for Wear */
-    AKEYCODE_STEM_3 = 267
+    AKEYCODE_NAVIGATE_PREVIOUS = 260,
+    AKEYCODE_NAVIGATE_NEXT   = 261,
+    AKEYCODE_NAVIGATE_IN     = 262,
+    AKEYCODE_NAVIGATE_OUT    = 263,
+    AKEYCODE_MEDIA_SKIP_FORWARD = 272,
+    AKEYCODE_MEDIA_SKIP_BACKWARD = 273,
+    AKEYCODE_MEDIA_STEP_FORWARD = 274,
+    AKEYCODE_MEDIA_STEP_BACKWARD = 275
 
     // NOTE: If you add a new keycode here you must also add it to several other files.
     //       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h
new file mode 100644
index 0000000..6c718c9
--- /dev/null
+++ b/include/android/multinetwork.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2015 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_MULTINETWORK_H
+#define ANDROID_MULTINETWORK_H
+
+#include <netdb.h>
+#include <stdlib.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/**
+ * The corresponding C type for android.net.Network#getNetworkHandle() return
+ * values.  The Java signed long value can be safely cast to a net_handle_t:
+ *
+ *     [C]    ((net_handle_t) java_long_network_handle)
+ *     [C++]  static_cast<net_handle_t>(java_long_network_handle)
+ *
+ * as appropriate.
+ */
+typedef uint64_t net_handle_t;
+
+/**
+ * The value NETWORK_UNSPECIFIED indicates no specific network.
+ *
+ * For some functions (documented below), a previous binding may be cleared
+ * by an invocation with NETWORK_UNSPECIFIED.
+ *
+ * Depending on the context it may indicate an error.  It is expressly
+ * not used to indicate some notion of the "current default network".
+ */
+#define NETWORK_UNSPECIFIED  ((net_handle_t)0)
+
+
+/**
+ * All functions below that return an int return 0 on success or -1
+ * on failure with an appropriate errno value set.
+ */
+
+
+/**
+ * Set the network to be used by the given socket file descriptor.
+ *
+ * To clear a previous socket binding invoke with NETWORK_UNSPECIFIED.
+ *
+ * This is the equivalent of:
+ *
+ *     [ android.net.Network#bindSocket() ]
+ *     https://developer.android.com/reference/android/net/Network.html#bindSocket(java.net.Socket)
+ */
+int android_setsocknetwork(net_handle_t network, int fd);
+
+
+/**
+ * Binds the current process to |network|.  All sockets created in the future
+ * (and not explicitly bound via android_setsocknetwork()) will be bound to
+ * |network|.  All host name resolutions will be limited to |network| as well.
+ * Note that if the network identified by |network| ever disconnects, all
+ * sockets created in this way will cease to work and all host name
+ * resolutions will fail.  This is by design so an application doesn't
+ * accidentally use sockets it thinks are still bound to a particular network.
+ *
+ * To clear a previous process binding invoke with NETWORK_UNSPECIFIED.
+ *
+ * This is the equivalent of:
+ *
+ *     [ android.net.ConnectivityManager#setProcessDefaultNetwork() ]
+ *     https://developer.android.com/reference/android/net/ConnectivityManager.html#setProcessDefaultNetwork(android.net.Network)
+ */
+int android_setprocnetwork(net_handle_t network);
+
+
+/**
+ * Perform hostname resolution via the DNS servers associated with |network|.
+ *
+ * All arguments (apart from |network|) are used identically as those passed
+ * to getaddrinfo(3).  Return and error values are identical to those of
+ * getaddrinfo(3), and in particular gai_strerror(3) can be used as expected.
+ * Similar to getaddrinfo(3):
+ *     - |hints| may be NULL (in which case man page documented defaults apply)
+ *     - either |node| or |service| may be NULL, but not both
+ *     - |res| must not be NULL
+ *
+ * This is the equivalent of:
+ *
+ *     [ android.net.Network#getAllByName() ]
+ *     https://developer.android.com/reference/android/net/Network.html#getAllByName(java.lang.String)
+ */
+int android_getaddrinfofornetwork(net_handle_t network,
+        const char *node, const char *service,
+        const struct addrinfo *hints, struct addrinfo **res);
+
+__END_DECLS
+
+#endif  // ANDROID_MULTINETWORK_H
diff --git a/include/android/sensor.h b/include/android/sensor.h
index d58c460..1be6232 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -193,15 +193,28 @@
 /*****************************************************************************/
 
 /*
- * Get a reference to the sensor manager. ASensorManager is a singleton.
+ * Get a reference to the sensor manager. ASensorManager is a singleton
+ * per package as different packages may have access to different sensors.
+ *
+ * Deprecated: Use ASensorManager_getInstanceForPackage(const char*) instead.
  *
  * Example:
  *
  *     ASensorManager* sensorManager = ASensorManager_getInstance();
  *
  */
-ASensorManager* ASensorManager_getInstance();
+__attribute__ ((deprecated)) ASensorManager* ASensorManager_getInstance();
 
+/*
+ * Get a reference to the sensor manager. ASensorManager is a singleton
+ * per package as different packages may have access to different sensors.
+ *
+ * Example:
+ *
+ *    ASensorManager* sensorManager = ASensorManager_getInstanceForPackage("foo.bar.baz");
+ *
+ */
+ASensorManager* ASensorManager_getInstanceForPackage(const char* packageName);
 
 /*
  * Returns the list of available sensors.
diff --git a/include/android/trace.h b/include/android/trace.h
new file mode 100644
index 0000000..e42e334
--- /dev/null
+++ b/include/android/trace.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 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_NATIVE_TRACE_H
+#define ANDROID_NATIVE_TRACE_H
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Returns true if tracing is enabled. Use this signal to avoid expensive computation only necessary
+ * when tracing is enabled.
+ */
+bool ATrace_isEnabled();
+
+/**
+ * Writes a tracing message to indicate that the given section of code has begun. This call must be
+ * followed by a corresponding call to endSection() on the same thread.
+ *
+ * Note: At this time the vertical bar character '|' and newline character '\n' are used internally
+ * by the tracing mechanism. If sectionName contains these characters they will be replaced with a
+ * space character in the trace.
+ */
+void ATrace_beginSection(const char* sectionName);
+
+/**
+ * Writes a tracing message to indicate that a given section of code has ended. This call must be
+ * preceeded by a corresponding call to beginSection(char*) on the same thread. Calling this method
+ * will mark the end of the most recently begun section of code, so care must be taken to ensure
+ * that beginSection / endSection pairs are properly nested and called from the same thread.
+ */
+void ATrace_endSection();
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // ANDROID_NATIVE_TRACE_H
diff --git a/include/binder/AppOpsManager.h b/include/binder/AppOpsManager.h
index 256cb94..042927c 100644
--- a/include/binder/AppOpsManager.h
+++ b/include/binder/AppOpsManager.h
@@ -63,7 +63,35 @@
         OP_ACCESS_NOTIFICATIONS = 25,
         OP_CAMERA = 26,
         OP_RECORD_AUDIO = 27,
-        OP_PLAY_AUDIO = 28
+        OP_PLAY_AUDIO = 28,
+        OP_READ_CLIPBOARD = 29,
+        OP_WRITE_CLIPBOARD = 30,
+        OP_TAKE_MEDIA_BUTTONS = 31,
+        OP_TAKE_AUDIO_FOCUS = 32,
+        OP_AUDIO_MASTER_VOLUME = 33,
+        OP_AUDIO_VOICE_VOLUME = 34,
+        OP_AUDIO_RING_VOLUME = 35,
+        OP_AUDIO_MEDIA_VOLUME = 36,
+        OP_AUDIO_ALARM_VOLUME = 37,
+        OP_AUDIO_NOTIFICATION_VOLUME = 38,
+        OP_AUDIO_BLUETOOTH_VOLUME = 39,
+        OP_WAKE_LOCK = 40,
+        OP_MONITOR_LOCATION = 41,
+        OP_MONITOR_HIGH_POWER_LOCATION = 42,
+        OP_GET_USAGE_STATS = 43,
+        OP_MUTE_MICROPHONE = 44,
+        OP_TOAST_WINDOW = 45,
+        OP_PROJECT_MEDIA = 46,
+        OP_ACTIVATE_VPN = 47,
+        OP_WRITE_WALLPAPER = 48,
+        OP_ASSIST_STRUCTURE = 49,
+        OP_ASSIST_SCREENSHOT = 50,
+        OP_READ_PHONE_STATE = 51,
+        OP_ADD_VOICEMAIL = 52,
+        OP_USE_SIP = 53,
+        OP_PROCESS_OUTGOING_CALLS = 54,
+        OP_USE_FINGERPRINT = 55,
+        OP_BODY_SENSORS = 56
     };
 
     AppOpsManager();
@@ -75,6 +103,7 @@
     void startWatchingMode(int32_t op, const String16& packageName,
             const sp<IAppOpsCallback>& callback);
     void stopWatchingMode(const sp<IAppOpsCallback>& callback);
+    int32_t permissionToOpCode(const String16& permission);
 
 private:
     Mutex mLock;
diff --git a/include/binder/IAppOpsService.h b/include/binder/IAppOpsService.h
index 193e9cc..cd81efa 100644
--- a/include/binder/IAppOpsService.h
+++ b/include/binder/IAppOpsService.h
@@ -40,6 +40,7 @@
             const sp<IAppOpsCallback>& callback) = 0;
     virtual void stopWatchingMode(const sp<IAppOpsCallback>& callback) = 0;
     virtual sp<IBinder> getToken(const sp<IBinder>& clientToken) = 0;
+    virtual int32_t permissionToOpCode(const String16& permission) = 0;
 
     enum {
         CHECK_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
@@ -49,6 +50,7 @@
         START_WATCHING_MODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+4,
         STOP_WATCHING_MODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+5,
         GET_TOKEN_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+6,
+        PERMISSION_TO_OP_CODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+7,
     };
 
     enum {
diff --git a/include/binder/IBatteryStats.h b/include/binder/IBatteryStats.h
index 7ddac57..5f38186 100644
--- a/include/binder/IBatteryStats.h
+++ b/include/binder/IBatteryStats.h
@@ -36,6 +36,12 @@
     virtual void noteStopAudio(int uid) = 0;
     virtual void noteResetVideo() = 0;
     virtual void noteResetAudio() = 0;
+    virtual void noteFlashlightOn(int uid) = 0;
+    virtual void noteFlashlightOff(int uid) = 0;
+    virtual void noteStartCamera(int uid) = 0;
+    virtual void noteStopCamera(int uid) = 0;
+    virtual void noteResetCamera() = 0;
+    virtual void noteResetFlashlight() = 0;
 
     enum {
         NOTE_START_SENSOR_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
@@ -46,6 +52,12 @@
         NOTE_STOP_AUDIO_TRANSACTION,
         NOTE_RESET_VIDEO_TRANSACTION,
         NOTE_RESET_AUDIO_TRANSACTION,
+        NOTE_FLASHLIGHT_ON_TRANSACTION,
+        NOTE_FLASHLIGHT_OFF_TRANSACTION,
+        NOTE_START_CAMERA_TRANSACTION,
+        NOTE_STOP_CAMERA_TRANSACTION,
+        NOTE_RESET_CAMERA_TRANSACTION,
+        NOTE_RESET_FLASHLIGHT_TRANSACTION
     };
 };
 
diff --git a/include/binder/IPCThreadState.h b/include/binder/IPCThreadState.h
index 60c2242..1853cff 100644
--- a/include/binder/IPCThreadState.h
+++ b/include/binder/IPCThreadState.h
@@ -76,14 +76,18 @@
                                                         BpBinder* proxy); 
 
     static  void                shutdown();
-    
+
     // Call this to disable switching threads to background scheduling when
     // receiving incoming IPC calls.  This is specifically here for the
     // Android system process, since it expects to have background apps calling
     // in to it but doesn't want to acquire locks in its services while in
     // the background.
     static  void                disableBackgroundScheduling(bool disable);
-    
+
+            // Call blocks until the number of executing binder threads is less than
+            // the maximum number of binder threads threads allowed for this process.
+            void                blockUntilThreadAvailable();
+
 private:
                                 IPCThreadState();
                                 ~IPCThreadState();
@@ -101,9 +105,9 @@
             status_t            getAndExecuteCommand();
             status_t            executeCommand(int32_t command);
             void                processPendingDerefs();
-            
+
             void                clearCaller();
-            
+
     static  void                threadDestructor(void *st);
     static  void                freeBuffer(Parcel* parcel,
                                            const uint8_t* data, size_t dataSize,
@@ -114,7 +118,7 @@
     const   pid_t               mMyThreadId;
             Vector<BBinder*>    mPendingStrongDerefs;
             Vector<RefBase::weakref_type*> mPendingWeakDerefs;
-            
+
             Parcel              mIn;
             Parcel              mOut;
             status_t            mLastError;
diff --git a/include/binder/IPermissionController.h b/include/binder/IPermissionController.h
index f9d371b..4e5fb34 100644
--- a/include/binder/IPermissionController.h
+++ b/include/binder/IPermissionController.h
@@ -19,6 +19,7 @@
 #define ANDROID_IPERMISSION_CONTROLLER_H
 
 #include <binder/IInterface.h>
+#include <stdlib.h>
 
 namespace android {
 
@@ -29,11 +30,16 @@
 public:
     DECLARE_META_INTERFACE(PermissionController);
 
-    virtual bool                checkPermission(const String16& permission,
-                                                int32_t pid, int32_t uid) = 0;
-    
+    virtual bool checkPermission(const String16& permission, int32_t pid, int32_t uid) = 0;
+
+    virtual void getPackagesForUid(const uid_t uid, Vector<String16> &packages) = 0;
+
+    virtual bool isRuntimePermission(const String16& permission) = 0;
+
     enum {
-        CHECK_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION
+        CHECK_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+        GET_PACKAGES_FOR_UID_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 1,
+        IS_RUNTIME_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 2
     };
 };
 
diff --git a/include/binder/IProcessInfoService.h b/include/binder/IProcessInfoService.h
new file mode 100644
index 0000000..dc62f45
--- /dev/null
+++ b/include/binder/IProcessInfoService.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2015 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_I_PROCESS_INFO_SERVICE_H
+#define ANDROID_I_PROCESS_INFO_SERVICE_H
+
+#include <binder/IInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IProcessInfoService : public IInterface {
+public:
+    DECLARE_META_INTERFACE(ProcessInfoService);
+
+    virtual status_t    getProcessStatesFromPids( size_t length,
+                                                  /*in*/ int32_t* pids,
+                                                  /*out*/ int32_t* states) = 0;
+
+    enum {
+        GET_PROCESS_STATES_FROM_PIDS = IBinder::FIRST_CALL_TRANSACTION,
+    };
+};
+
+// ----------------------------------------------------------------------
+
+class BnProcessInfoService : public BnInterface<IProcessInfoService> {
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_I_PROCESS_INFO_SERVICE_H
diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
index a52e044..3ada1e9 100644
--- a/include/binder/Parcel.h
+++ b/include/binder/Parcel.h
@@ -60,6 +60,7 @@
     status_t            appendFrom(const Parcel *parcel,
                                    size_t start, size_t len);
 
+    bool                allowFds() const;
     bool                pushAllowFds(bool allowFds);
     void                restoreAllowFds(bool lastValue);
 
@@ -96,6 +97,7 @@
     status_t            writeInt32(int32_t val);
     status_t            writeUint32(uint32_t val);
     status_t            writeInt64(int64_t val);
+    status_t            writeUint64(uint64_t val);
     status_t            writeFloat(float val);
     status_t            writeDouble(double val);
     status_t            writeCString(const char* str);
@@ -129,16 +131,18 @@
     // will be closed once the parcel is destroyed.
     status_t            writeDupFileDescriptor(int fd);
 
-    // Writes a raw fd and optional comm channel fd to the parcel as a ParcelFileDescriptor.
-    // A dup's of the fds are made, which will be closed once the parcel is destroyed.
-    // Null values are passed as -1.
-    status_t            writeParcelFileDescriptor(int fd, int commChannel = -1);
-
     // Writes a blob to the parcel.
     // If the blob is small, then it is stored in-place, otherwise it is
-    // transferred by way of an anonymous shared memory region.
+    // transferred by way of an anonymous shared memory region.  Prefer sending
+    // immutable blobs if possible since they may be subsequently transferred between
+    // processes without further copying whereas mutable blobs always need to be copied.
     // The caller should call release() on the blob after writing its contents.
-    status_t            writeBlob(size_t len, WritableBlob* outBlob);
+    status_t            writeBlob(size_t len, bool mutableCopy, WritableBlob* outBlob);
+
+    // Write an existing immutable blob file descriptor to the parcel.
+    // This allows the client to send the same blob to multiple processes
+    // as long as it keeps a dup of the blob file descriptor handy for later.
+    status_t            writeDupImmutableBlobFileDescriptor(int fd);
 
     status_t            writeObject(const flat_binder_object& val, bool nullMetaData);
 
@@ -157,6 +161,8 @@
     status_t            readUint32(uint32_t *pArg) const;
     int64_t             readInt64() const;
     status_t            readInt64(int64_t *pArg) const;
+    uint64_t            readUint64() const;
+    status_t            readUint64(uint64_t *pArg) const;
     float               readFloat() const;
     status_t            readFloat(float *pArg) const;
     double              readDouble() const;
@@ -195,11 +201,6 @@
     // in the parcel, which you do not own -- use dup() to get your own copy.
     int                 readFileDescriptor() const;
 
-    // Reads a ParcelFileDescriptor from the parcel.  Returns the raw fd as
-    // the result, and the optional comm channel fd in outCommChannel.
-    // Null values are returned as -1.
-    int                 readParcelFileDescriptor(int& outCommChannel) const;
-
     // Reads a blob from the parcel.
     // The caller should call release() on the blob after reading its contents.
     status_t            readBlob(size_t len, ReadableBlob* outBlob) const;
@@ -277,16 +278,19 @@
         Blob();
         ~Blob();
 
+        void clear();
         void release();
         inline size_t size() const { return mSize; }
+        inline int fd() const { return mFd; };
+        inline bool isMutable() const { return mMutable; }
 
     protected:
-        void init(bool mapped, void* data, size_t size);
-        void clear();
+        void init(int fd, void* data, size_t size, bool isMutable);
 
-        bool mMapped;
+        int mFd; // owned by parcel so not closed when released
         void* mData;
         size_t mSize;
+        bool mMutable;
     };
 
     class FlattenableHelperInterface {
@@ -327,6 +331,7 @@
         friend class Parcel;
     public:
         inline const void* data() const { return mData; }
+        inline void* mutableData() { return isMutable() ? mData : NULL; }
     };
 
     class WritableBlob : public Blob {
@@ -334,6 +339,12 @@
     public:
         inline void* data() { return mData; }
     };
+
+private:
+    size_t mBlobAshmemSize;
+
+public:
+    size_t getBlobAshmemSize() const;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/include/binder/ProcessInfoService.h b/include/binder/ProcessInfoService.h
new file mode 100644
index 0000000..c5ead20
--- /dev/null
+++ b/include/binder/ProcessInfoService.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2015 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_PROCESS_INFO_SERVICE_H
+#define ANDROID_PROCESS_INFO_SERVICE_H
+
+#include <binder/IProcessInfoService.h>
+#include <utils/Errors.h>
+#include <utils/Singleton.h>
+#include <sys/types.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class ProcessInfoService : public Singleton<ProcessInfoService> {
+
+    friend class Singleton<ProcessInfoService>;
+    sp<IProcessInfoService> mProcessInfoService;
+    Mutex mProcessInfoLock;
+
+    ProcessInfoService();
+
+    status_t getProcessStatesImpl(size_t length, /*in*/ int32_t* pids, /*out*/ int32_t* states);
+    void updateBinderLocked();
+
+    static const int BINDER_ATTEMPT_LIMIT = 5;
+
+public:
+
+    /**
+     * For each PID in the given "pids" input array, write the current process state
+     * for that process into the "states" output array, or
+     * ActivityManager.PROCESS_STATE_NONEXISTENT * to indicate that no process with the given PID
+     * exists.
+     *
+     * Returns NO_ERROR if this operation was successful, or a negative error code otherwise.
+     */
+    static status_t getProcessStatesFromPids(size_t length, /*in*/ int32_t* pids,
+            /*out*/ int32_t* states) {
+        return ProcessInfoService::getInstance().getProcessStatesImpl(length, /*in*/ pids,
+                /*out*/ states);
+    }
+
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_PROCESS_INFO_SERVICE_H
+
diff --git a/include/binder/ProcessState.h b/include/binder/ProcessState.h
index 3bc978d..f9edc2a 100644
--- a/include/binder/ProcessState.h
+++ b/include/binder/ProcessState.h
@@ -24,6 +24,8 @@
 
 #include <utils/threads.h>
 
+#include <pthread.h>
+
 // ---------------------------------------------------------------------------
 namespace android {
 
@@ -71,25 +73,33 @@
                                 ProcessState(const ProcessState& o);
             ProcessState&       operator=(const ProcessState& o);
             String8             makeBinderThreadName();
-            
+
             struct handle_entry {
                 IBinder* binder;
                 RefBase::weakref_type* refs;
             };
-            
+
             handle_entry*       lookupHandleLocked(int32_t handle);
 
             int                 mDriverFD;
             void*               mVMStart;
-            
+
+            // Protects thread count variable below.
+            pthread_mutex_t     mThreadCountLock;
+            pthread_cond_t      mThreadCountDecrement;
+            // Number of binder threads current executing a command.
+            size_t              mExecutingThreadsCount;
+            // Maximum number for binder threads allowed for this process.
+            size_t              mMaxThreads;
+
     mutable Mutex               mLock;  // protects everything below.
-            
+
             Vector<handle_entry>mHandleToObject;
 
             bool                mManagesContexts;
             context_check_func  mBinderContextCheckFunc;
             void*               mBinderContextUserData;
-            
+
             KeyedVector<String16, sp<IBinder> >
                                 mContexts;
 
diff --git a/include/gui/BufferItem.h b/include/gui/BufferItem.h
index 000ef0e..145efe6 100644
--- a/include/gui/BufferItem.h
+++ b/include/gui/BufferItem.h
@@ -72,7 +72,13 @@
     // to set by queueBuffer each time this slot is queued. This value
     // is guaranteed to be monotonically increasing for each newly
     // acquired buffer.
-    int64_t mTimestamp;
+    union {
+        int64_t mTimestamp;
+        struct {
+            uint32_t mTimestampLo;
+            uint32_t mTimestampHi;
+        };
+    };
 
     // mIsAutoTimestamp indicates whether mTimestamp was generated
     // automatically when the buffer was queued.
@@ -84,7 +90,13 @@
     android_dataspace mDataSpace;
 
     // mFrameNumber is the number of the queued frame for this slot.
-    uint64_t mFrameNumber;
+    union {
+        uint64_t mFrameNumber;
+        struct {
+            uint32_t mFrameNumberLo;
+            uint32_t mFrameNumberHi;
+        };
+    };
 
     union {
         // mSlot is the slot index of this buffer (default INVALID_BUFFER_SLOT).
diff --git a/include/gui/BufferItemConsumer.h b/include/gui/BufferItemConsumer.h
index 930fabf..56c7a3f 100644
--- a/include/gui/BufferItemConsumer.h
+++ b/include/gui/BufferItemConsumer.h
@@ -86,21 +86,6 @@
     status_t releaseBuffer(const BufferItem &item,
             const sp<Fence>& releaseFence = Fence::NO_FENCE);
 
-    // setDefaultBufferSize is used to set the size of buffers returned by
-    // requestBuffers when a with and height of zero is requested.
-    status_t setDefaultBufferSize(uint32_t w, uint32_t h);
-
-    // setDefaultBufferFormat allows the BufferQueue to create
-    // GraphicBuffers of a defaultFormat if no format is specified
-    // in dequeueBuffer
-    status_t setDefaultBufferFormat(PixelFormat defaultFormat);
-
-    // setDefaultBufferDataSpace allows the BufferQueue to create
-    // GraphicBuffers of a defaultDataSpace if no data space is specified
-    // in queueBuffer.
-    // The initial default is HAL_DATASPACE_UNKNOWN
-    status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace);
-
 };
 
 } // namespace android
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index 721b218..09300a2 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -62,9 +62,10 @@
     public:
         ProxyConsumerListener(const wp<ConsumerListener>& consumerListener);
         virtual ~ProxyConsumerListener();
-        virtual void onFrameAvailable(const BufferItem& item);
-        virtual void onBuffersReleased();
-        virtual void onSidebandStreamChanged();
+        virtual void onFrameAvailable(const BufferItem& item) override;
+        virtual void onFrameReplaced(const BufferItem& item) override;
+        virtual void onBuffersReleased() override;
+        virtual void onSidebandStreamChanged() override;
     private:
         // mConsumerListener is a weak reference to the IConsumerListener.  This is
         // the raison d'etre of ProxyConsumerListener.
diff --git a/include/gui/BufferQueueConsumer.h b/include/gui/BufferQueueConsumer.h
index 9c91fc7..cde302f 100644
--- a/include/gui/BufferQueueConsumer.h
+++ b/include/gui/BufferQueueConsumer.h
@@ -47,7 +47,7 @@
     // returned.  The presentation time is in nanoseconds, and the time base
     // is CLOCK_MONOTONIC.
     virtual status_t acquireBuffer(BufferItem* outBuffer,
-            nsecs_t expectedPresent);
+            nsecs_t expectedPresent, uint64_t maxFrameNumber = 0) override;
 
     // See IGraphicBufferConsumer::detachBuffer
     virtual status_t detachBuffer(int slot);
diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
index 9a43516..99134ea 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -270,6 +270,16 @@
     // mAllowAllocation determines whether dequeueBuffer is allowed to allocate
     // new buffers
     bool mAllowAllocation;
+
+    // mBufferAge tracks the age of the contents of the most recently dequeued
+    // buffer as the number of frames that have elapsed since it was last queued
+    uint64_t mBufferAge;
+
+    // mGenerationNumber stores the current generation number of the attached
+    // producer. Any attempt to attach a buffer with a different generation
+    // number will fail.
+    uint32_t mGenerationNumber;
+
 }; // class BufferQueueCore
 
 } // namespace android
diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h
index ed660fb..9754a89 100644
--- a/include/gui/BufferQueueProducer.h
+++ b/include/gui/BufferQueueProducer.h
@@ -175,6 +175,12 @@
     // See IGraphicBufferProducer::allowAllocation
     virtual status_t allowAllocation(bool allow);
 
+    // See IGraphicBufferProducer::setGenerationNumber
+    virtual status_t setGenerationNumber(uint32_t generationNumber);
+
+    // See IGraphicBufferProducer::getConsumerName
+    virtual String8 getConsumerName() const override;
+
 private:
     // This is required by the IBinder::DeathRecipient interface
     virtual void binderDied(const wp<IBinder>& who);
diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h
index d56fa89..9307a26 100644
--- a/include/gui/ConsumerBase.h
+++ b/include/gui/ConsumerBase.h
@@ -38,15 +38,9 @@
         protected ConsumerListener {
 public:
     struct FrameAvailableListener : public virtual RefBase {
-        // onFrameAvailable() is called each time an additional frame becomes
-        // available for consumption. This means that frames that are queued
-        // while in asynchronous mode only trigger the callback if no previous
-        // frames are pending. Frames queued while in synchronous mode always
-        // trigger the callback.
-        //
-        // This is called without any lock held and can be called concurrently
-        // by multiple threads.
+        // See IConsumerListener::onFrame{Available,Replaced}
         virtual void onFrameAvailable(const BufferItem& item) = 0;
+        virtual void onFrameReplaced(const BufferItem& /* item */) {}
     };
 
     virtual ~ConsumerBase();
@@ -62,6 +56,9 @@
     // or by OpenGL ES as a texture) then those buffer will remain allocated.
     void abandon();
 
+    // Returns true if the ConsumerBase is in the 'abandoned' state
+    bool isAbandoned();
+
     // set the name of the ConsumerBase that will be used to identify it in
     // log messages.
     void setName(const String8& name);
@@ -79,6 +76,15 @@
     // See IGraphicBufferConsumer::detachBuffer
     status_t detachBuffer(int slot);
 
+    // See IGraphicBufferConsumer::setDefaultBufferSize
+    status_t setDefaultBufferSize(uint32_t width, uint32_t height);
+
+    // See IGraphicBufferConsumer::setDefaultBufferFormat
+    status_t setDefaultBufferFormat(PixelFormat defaultFormat);
+
+    // See IGraphicBufferConsumer::setDefaultBufferDataSpace
+    status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace);
+
 private:
     ConsumerBase(const ConsumerBase&);
     void operator=(const ConsumerBase&);
@@ -104,14 +110,16 @@
 
     // Implementation of the IConsumerListener interface.  These
     // calls are used to notify the ConsumerBase of asynchronous events in the
-    // BufferQueue.  The onFrameAvailable and onBuffersReleased methods should
-    // not need to be overridden by derived classes, but if they are overridden
-    // the ConsumerBase implementation must be called from the derived class.
-    // The ConsumerBase version of onSidebandStreamChanged does nothing and can
-    // be overriden by derived classes if they want the notification.
-    virtual void onFrameAvailable(const BufferItem& item);
-    virtual void onBuffersReleased();
-    virtual void onSidebandStreamChanged();
+    // BufferQueue.  The onFrameAvailable, onFrameReplaced, and
+    // onBuffersReleased methods should not need to be overridden by derived
+    // classes, but if they are overridden the ConsumerBase implementation must
+    // be called from the derived class. The ConsumerBase version of
+    // onSidebandStreamChanged does nothing and can be overriden by derived
+    // classes if they want the notification.
+    virtual void onFrameAvailable(const BufferItem& item) override;
+    virtual void onFrameReplaced(const BufferItem& item) override;
+    virtual void onBuffersReleased() override;
+    virtual void onSidebandStreamChanged() override;
 
     // freeBufferLocked frees up the given buffer slot.  If the slot has been
     // initialized this will release the reference to the GraphicBuffer in that
@@ -156,7 +164,8 @@
     // initialization that must take place the first time a buffer is assigned
     // to a slot.  If it is overridden the derived class's implementation must
     // call ConsumerBase::acquireBufferLocked.
-    virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen);
+    virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen,
+            uint64_t maxFrameNumber = 0);
 
     // releaseBufferLocked relinquishes control over a buffer, returning that
     // control to the BufferQueue.
diff --git a/include/gui/CpuConsumer.h b/include/gui/CpuConsumer.h
index c99ab29..3b07a31 100644
--- a/include/gui/CpuConsumer.h
+++ b/include/gui/CpuConsumer.h
@@ -80,23 +80,6 @@
     // log messages.
     void setName(const String8& name);
 
-    // setDefaultBufferSize is used to set the size of buffers returned by
-    // requestBuffers when a width and height of zero is requested.
-    // A call to setDefaultBufferSize() may trigger requestBuffers() to
-    // be called from the client. Default size is 1x1.
-    status_t setDefaultBufferSize(uint32_t width, uint32_t height);
-
-    // setDefaultBufferFormat allows CpuConsumer's BufferQueue to create buffers
-    // of a defaultFormat if no format is specified by producer.
-    // The initial default is PIXEL_FORMAT_RGBA_8888.
-    status_t setDefaultBufferFormat(PixelFormat defaultFormat);
-
-    // setDefaultBufferDataSpace allows the BufferQueue to create
-    // GraphicBuffers of a defaultDataSpace if no data space is specified
-    // in queueBuffer.
-    // The initial default is HAL_DATASPACE_UNKNOWN
-    status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace);
-
     // Gets the next graphics buffer from the producer and locks it for CPU use,
     // filling out the passed-in locked buffer structure with the native pointer
     // and metadata. Returns BAD_VALUE if no new buffer is available, and
diff --git a/include/gui/GLConsumer.h b/include/gui/GLConsumer.h
index 4912580..c35c7be 100644
--- a/include/gui/GLConsumer.h
+++ b/include/gui/GLConsumer.h
@@ -241,7 +241,8 @@
 
     // acquireBufferLocked overrides the ConsumerBase method to update the
     // mEglSlots array in addition to the ConsumerBase behavior.
-    virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen);
+    virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen,
+            uint64_t maxFrameNumber = 0) override;
 
     // releaseBufferLocked overrides the ConsumerBase method to update the
     // mEglSlots array in addition to the ConsumerBase.
diff --git a/include/gui/IGraphicBufferConsumer.h b/include/gui/IGraphicBufferConsumer.h
index 8f31b55..60ec9cc 100644
--- a/include/gui/IGraphicBufferConsumer.h
+++ b/include/gui/IGraphicBufferConsumer.h
@@ -69,6 +69,12 @@
     // returned.  The presentation time is in nanoseconds, and the time base
     // is CLOCK_MONOTONIC.
     //
+    // If maxFrameNumber is non-zero, it indicates that acquireBuffer should
+    // only return a buffer with a frame number less than or equal to
+    // maxFrameNumber. If no such frame is available (such as when a buffer has
+    // been replaced but the consumer has not received the onFrameReplaced
+    // callback), then PRESENT_LATER will be returned.
+    //
     // Return of NO_ERROR means the operation completed as normal.
     //
     // Return of a positive value means the operation could not be completed
@@ -78,7 +84,8 @@
     //
     // Return of a negative value means an error has occurred:
     // * INVALID_OPERATION - too many buffers have been acquired
-    virtual status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen) = 0;
+    virtual status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen,
+            uint64_t maxFrameNumber = 0) = 0;
 
     // detachBuffer attempts to remove all ownership of the buffer in the given
     // slot from the buffer queue. If this call succeeds, the slot will be
@@ -103,7 +110,8 @@
     // will be deallocated as stale.
     //
     // Return of a value other than NO_ERROR means an error has occurred:
-    // * BAD_VALUE - outSlot or buffer were NULL
+    // * BAD_VALUE - outSlot or buffer were NULL, or the generation number of
+    //               the buffer did not match the buffer queue.
     // * INVALID_OPERATION - cannot attach the buffer because it would cause too
     //                       many buffers to be acquired.
     // * NO_MEMORY - no free slots available
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index 5c50b2b..9530de1 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -218,8 +218,9 @@
     //
     // Return of a negative value means an error has occurred:
     // * NO_INIT - the buffer queue has been abandoned.
-    // * BAD_VALUE - outSlot or buffer were NULL or invalid combination of
-    //               async mode and buffer count override.
+    // * BAD_VALUE - outSlot or buffer were NULL, invalid combination of
+    //               async mode and buffer count override, or the generation
+    //               number of the buffer did not match the buffer queue.
     // * INVALID_OPERATION - cannot attach the buffer because it would cause
     //                       too many buffers to be dequeued, either because
     //                       the producer already has a single buffer dequeued
@@ -470,6 +471,18 @@
     // eligible slot is available, dequeueBuffer will block or return an error
     // as usual.
     virtual status_t allowAllocation(bool allow) = 0;
+
+    // Sets the current generation number of the BufferQueue.
+    //
+    // This generation number will be inserted into any buffers allocated by the
+    // BufferQueue, and any attempts to attach a buffer with a different
+    // generation number will fail. Buffers already in the queue are not
+    // affected and will retain their current generation number. The generation
+    // number defaults to 0.
+    virtual status_t setGenerationNumber(uint32_t generationNumber) = 0;
+
+    // Returns the name of the connected consumer.
+    virtual String8 getConsumerName() const = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/gui/ISensorServer.h b/include/gui/ISensorServer.h
index 9c8afc5..3dca2a3 100644
--- a/include/gui/ISensorServer.h
+++ b/include/gui/ISensorServer.h
@@ -30,14 +30,17 @@
 
 class Sensor;
 class ISensorEventConnection;
+class String8;
 
 class ISensorServer : public IInterface
 {
 public:
     DECLARE_META_INTERFACE(SensorServer);
 
-    virtual Vector<Sensor> getSensorList() = 0;
-    virtual sp<ISensorEventConnection> createSensorEventConnection() = 0;
+    virtual Vector<Sensor> getSensorList(const String16& opPackageName) = 0;
+    virtual sp<ISensorEventConnection> createSensorEventConnection(const String8& packageName,
+             int mode, const String16& opPackageName) = 0;
+    virtual int32_t isDataInjectionEnabled() = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/gui/Sensor.h b/include/gui/Sensor.h
index 27a215e..8142be6 100644
--- a/include/gui/Sensor.h
+++ b/include/gui/Sensor.h
@@ -71,6 +71,8 @@
     uint32_t getFifoMaxEventCount() const;
     const String8& getStringType() const;
     const String8& getRequiredPermission() const;
+    bool isRequiredPermissionRuntime() const;
+    int32_t getRequiredAppOp() const;
     int32_t getMaxDelay() const;
     uint32_t getFlags() const;
     bool isWakeUpSensor() const;
@@ -97,6 +99,8 @@
     uint32_t mFifoMaxEventCount;
     String8 mStringType;
     String8 mRequiredPermission;
+    bool mRequiredPermissionRuntime = false;
+    int32_t mRequiredAppOp;
     int32_t mMaxDelay;
     uint32_t mFlags;
     static void flattenString8(void*& buffer, size_t& size, const String8& string8);
diff --git a/include/gui/SensorEventQueue.h b/include/gui/SensorEventQueue.h
index 02b3d38..e5b9fc5 100644
--- a/include/gui/SensorEventQueue.h
+++ b/include/gui/SensorEventQueue.h
@@ -23,6 +23,7 @@
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
+#include <utils/String16.h>
 
 #include <gui/BitTube.h>
 
@@ -52,7 +53,7 @@
 
     enum { MAX_RECEIVE_BUFFER_EVENT_COUNT = 256 };
 
-            SensorEventQueue(const sp<ISensorEventConnection>& connection);
+    SensorEventQueue(const sp<ISensorEventConnection>& connection);
     virtual ~SensorEventQueue();
     virtual void onFirstRef();
 
@@ -77,6 +78,8 @@
     status_t flush() const;
     // Send an ack for every wake_up sensor event that is set to WAKE_UP_SENSOR_EVENT_NEEDS_ACK.
     void sendAck(const ASensorEvent* events, int count);
+
+    status_t injectSensorEvent(const ASensorEvent& event);
 private:
     sp<Looper> getLooper() const;
     sp<ISensorEventConnection> mSensorEventConnection;
diff --git a/include/gui/SensorManager.h b/include/gui/SensorManager.h
index 3176462..3796067 100644
--- a/include/gui/SensorManager.h
+++ b/include/gui/SensorManager.h
@@ -17,15 +17,20 @@
 #ifndef ANDROID_GUI_SENSOR_MANAGER_H
 #define ANDROID_GUI_SENSOR_MANAGER_H
 
+#include <map>
+
 #include <stdint.h>
 #include <sys/types.h>
 
 #include <binder/IBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
 
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 #include <utils/Singleton.h>
 #include <utils/Vector.h>
+#include <utils/String8.h>
 
 #include <gui/SensorEventQueue.h>
 
@@ -40,20 +45,69 @@
 class ISensorServer;
 class Sensor;
 class SensorEventQueue;
-
 // ----------------------------------------------------------------------------
 
 class SensorManager :
-    public ASensorManager,
-    public Singleton<SensorManager>
+    public ASensorManager
 {
 public:
-    SensorManager();
+    static SensorManager& getInstanceForPackage(const String16& packageName) {
+        Mutex::Autolock _l(sLock);
+
+        SensorManager* sensorManager;
+        std::map<String16, SensorManager*>::iterator iterator =
+                sPackageInstances.find(packageName);
+
+        if (iterator != sPackageInstances.end()) {
+            sensorManager = iterator->second;
+        } else {
+            String16 opPackageName = packageName;
+
+            // It is possible that the calling code has no access to the package name.
+            // In this case we will get the packages for the calling UID and pick the
+            // first one for attributing the app op. This will work correctly for
+            // runtime permissions as for legacy apps we will toggle the app op for
+            // all packages in the UID. The caveat is that the operation may be attributed
+            // to the wrong package and stats based on app ops may be slightly off.
+            if (opPackageName.size() <= 0) {
+                sp<IBinder> binder = defaultServiceManager()->getService(String16("permission"));
+                if (binder != 0) {
+                    const uid_t uid = IPCThreadState::self()->getCallingUid();
+                    Vector<String16> packages;
+                    interface_cast<IPermissionController>(binder)->getPackagesForUid(uid, packages);
+                    if (!packages.isEmpty()) {
+                        opPackageName = packages[0];
+                    } else {
+                        ALOGE("No packages for calling UID");
+                    }
+                } else {
+                    ALOGE("Cannot get permission service");
+                }
+            }
+
+            sensorManager = new SensorManager(opPackageName);
+
+            // If we had no package name, we looked it up from the UID and the sensor
+            // manager instance we created should also be mapped to the empty package
+            // name, to avoid looking up the packages for a UID and get the same result.
+            if (packageName.size() <= 0) {
+                sPackageInstances.insert(std::make_pair(String16(), sensorManager));
+            }
+
+            // Stash the per package sensor manager.
+            sPackageInstances.insert(std::make_pair(opPackageName, sensorManager));
+        }
+
+        return *sensorManager;
+    }
+
+    SensorManager(const String16& opPackageName);
     ~SensorManager();
 
     ssize_t getSensorList(Sensor const* const** list) const;
     Sensor const* getDefaultSensor(int type);
-    sp<SensorEventQueue> createEventQueue();
+    sp<SensorEventQueue> createEventQueue(String8 packageName = String8(""), int mode = 0);
+    bool isDataInjectionEnabled();
 
 private:
     // DeathRecipient interface
@@ -62,11 +116,15 @@
     status_t assertStateLocked() const;
 
 private:
+    static Mutex sLock;
+    static std::map<String16, SensorManager*> sPackageInstances;
+
     mutable Mutex mLock;
     mutable sp<ISensorServer> mSensorServer;
     mutable Sensor const** mSensorList;
     mutable Vector<Sensor> mSensors;
     mutable sp<IBinder::DeathRecipient> mDeathObserver;
+    const String16 mOpPackageName;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index a9f78cf..72f1067 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -101,6 +101,14 @@
      */
     void allocateBuffers();
 
+    /* Sets the generation number on the IGraphicBufferProducer and updates the
+     * generation number on any buffers attached to the Surface after this call.
+     * See IGBP::setGenerationNumber for more information. */
+    status_t setGenerationNumber(uint32_t generationNumber);
+
+    // See IGraphicBufferProducer::getConsumerName
+    String8 getConsumerName() const;
+
 protected:
     virtual ~Surface();
 
@@ -179,7 +187,7 @@
     virtual int unlockAndPost();
 
     virtual int connect(int api, const sp<IProducerListener>& listener);
-    virtual int detachNextBuffer(ANativeWindowBuffer** outBuffer,
+    virtual int detachNextBuffer(sp<GraphicBuffer>* outBuffer,
             sp<Fence>* outFence);
     virtual int attachBuffer(ANativeWindowBuffer*);
 
@@ -305,6 +313,10 @@
     // When a non-CPU producer is attached, this reflects the surface damage
     // (the change since the previous frame) passed in by the producer.
     Region mDirtyRegion;
+
+    // Stores the current generation number. See setGenerationNumber and
+    // IGraphicBufferProducer::setGenerationNumber for more information.
+    uint32_t mGenerationNumber;
 };
 
 }; // namespace android
diff --git a/include/input/IInputFlinger.h b/include/input/IInputFlinger.h
new file mode 100644
index 0000000..629310f
--- /dev/null
+++ b/include/input/IInputFlinger.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2013 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 _LIBINPUT_IINPUT_FLINGER_H
+#define _LIBINPUT_IINPUT_FLINGER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/IInterface.h>
+
+namespace android {
+
+/*
+ * This class defines the Binder IPC interface for accessing various
+ * InputFlinger features.
+ */
+class IInputFlinger : public IInterface {
+public:
+    DECLARE_META_INTERFACE(InputFlinger);
+};
+
+
+/**
+ * Binder implementation.
+ */
+class BnInputFlinger : public BnInterface<IInputFlinger> {
+public:
+    enum {
+        DO_SOMETHING_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+    };
+
+    virtual status_t onTransact(uint32_t code, const Parcel& data,
+            Parcel* reply, uint32_t flags = 0);
+};
+
+} // namespace android
+
+#endif // _LIBINPUT_IINPUT_FLINGER_H
diff --git a/include/input/Input.h b/include/input/Input.h
index 80845b4..617175b 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -385,6 +385,12 @@
 
     inline int32_t getButtonState() const { return mButtonState; }
 
+    inline int32_t setButtonState(int32_t buttonState) { mButtonState = buttonState; }
+
+    inline int32_t getActionButton() const { return mActionButton; }
+
+    inline void setActionButton(int32_t button) { mActionButton = button; }
+
     inline float getXOffset() const { return mXOffset; }
 
     inline float getYOffset() const { return mYOffset; }
@@ -538,6 +544,7 @@
             int32_t deviceId,
             int32_t source,
             int32_t action,
+            int32_t actionButton,
             int32_t flags,
             int32_t edgeFlags,
             int32_t metaState,
@@ -590,6 +597,7 @@
 
 protected:
     int32_t mAction;
+    int32_t mActionButton;
     int32_t mFlags;
     int32_t mEdgeFlags;
     int32_t mMetaState;
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index adf9fb9..1ea69d3 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -73,7 +73,8 @@
     };
 
     void initialize(int32_t id, int32_t generation, int32_t controllerNumber,
-            const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal);
+            const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal,
+            bool hasMic);
 
     inline int32_t getId() const { return mId; }
     inline int32_t getControllerNumber() const { return mControllerNumber; }
@@ -84,6 +85,7 @@
         return mAlias.isEmpty() ? mIdentifier.name : mAlias;
     }
     inline bool isExternal() const { return mIsExternal; }
+    inline bool hasMic() const { return mHasMic; }
     inline uint32_t getSources() const { return mSources; }
 
     const MotionRange* getMotionRange(int32_t axis, uint32_t source) const;
@@ -121,6 +123,7 @@
     InputDeviceIdentifier mIdentifier;
     String8 mAlias;
     bool mIsExternal;
+    bool mHasMic;
     uint32_t mSources;
     int32_t mKeyboardType;
     sp<KeyCharacterMap> mKeyCharacterMap;
diff --git a/include/input/InputEventLabels.h b/include/input/InputEventLabels.h
index 8a339f7..a7a9329 100644
--- a/include/input/InputEventLabels.h
+++ b/include/input/InputEventLabels.h
@@ -299,10 +299,14 @@
     DEFINE_KEYCODE(TV_MEDIA_CONTEXT_MENU),
     DEFINE_KEYCODE(TV_TIMER_PROGRAMMING),
     DEFINE_KEYCODE(HELP),
-    DEFINE_KEYCODE(STEM_PRIMARY),
-    DEFINE_KEYCODE(STEM_1),
-    DEFINE_KEYCODE(STEM_2),
-    DEFINE_KEYCODE(STEM_3),
+    DEFINE_KEYCODE(NAVIGATE_PREVIOUS),
+    DEFINE_KEYCODE(NAVIGATE_NEXT),
+    DEFINE_KEYCODE(NAVIGATE_IN),
+    DEFINE_KEYCODE(NAVIGATE_OUT),
+    DEFINE_KEYCODE(MEDIA_SKIP_FORWARD),
+    DEFINE_KEYCODE(MEDIA_SKIP_BACKWARD),
+    DEFINE_KEYCODE(MEDIA_STEP_FORWARD),
+    DEFINE_KEYCODE(MEDIA_STEP_BACKWARD),
 
     { NULL, 0 }
 };
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index e7e383b..f31bcea 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -84,6 +84,7 @@
             int32_t deviceId;
             int32_t source;
             int32_t action;
+            int32_t actionButton;
             int32_t flags;
             int32_t metaState;
             int32_t buttonState;
@@ -95,7 +96,7 @@
             float yPrecision;
             uint32_t pointerCount;
             // Note that PointerCoords requires 8 byte alignment.
-            struct Pointer{
+            struct Pointer {
                 PointerProperties properties;
                 PointerCoords coords;
             } pointers[MAX_POINTERS];
@@ -232,6 +233,7 @@
             int32_t deviceId,
             int32_t source,
             int32_t action,
+            int32_t actionButton,
             int32_t flags,
             int32_t edgeFlags,
             int32_t metaState,
diff --git a/include/media/drm/DrmAPI.h b/include/media/drm/DrmAPI.h
index 49939fd..272881b 100644
--- a/include/media/drm/DrmAPI.h
+++ b/include/media/drm/DrmAPI.h
@@ -80,7 +80,10 @@
             kDrmPluginEventProvisionRequired = 1,
             kDrmPluginEventKeyNeeded,
             kDrmPluginEventKeyExpired,
-            kDrmPluginEventVendorDefined
+            kDrmPluginEventVendorDefined,
+            kDrmPluginEventSessionReclaimed,
+            kDrmPluginEventExpirationUpdate,
+            kDrmPluginEventKeysChange,
         };
 
         // Drm keys can be for offline content or for online streaming.
@@ -93,6 +96,33 @@
             kKeyType_Release
         };
 
+        // Enumerate KeyRequestTypes to allow an app to determine the
+        // type of a key request returned from getKeyRequest.
+        enum KeyRequestType {
+            kKeyRequestType_Unknown,
+            kKeyRequestType_Initial,
+            kKeyRequestType_Renewal,
+            kKeyRequestType_Release
+        };
+
+        // Enumerate KeyStatusTypes which indicate the state of a key
+        enum KeyStatusType
+        {
+            kKeyStatusType_Usable,
+            kKeyStatusType_Expired,
+            kKeyStatusType_OutputNotAllowed,
+            kKeyStatusType_StatusPending,
+            kKeyStatusType_InternalError
+        };
+
+        // Used by sendKeysChange to report the usability status of each
+        // key to the app.
+        struct KeyStatus
+        {
+            Vector<uint8_t> mKeyId;
+            KeyStatusType mType;
+        };
+
         DrmPlugin() {}
         virtual ~DrmPlugin() {}
 
@@ -135,7 +165,8 @@
                           Vector<uint8_t> const &initData,
                           String8 const &mimeType, KeyType keyType,
                           KeyedVector<String8, String8> const &optionalParameters,
-                          Vector<uint8_t> &request, String8 &defaultUrl) = 0;
+                          Vector<uint8_t> &request, String8 &defaultUrl,
+                          KeyRequestType *keyRequestType) = 0;
 
         //
         // After a key response is received by the app, it is provided to the
@@ -315,11 +346,18 @@
         }
 
     protected:
-        // Plugins call sendEvent to deliver events to the java app
+        // Plugins call these methods to deliver events to the java app
         void sendEvent(EventType eventType, int extra,
                        Vector<uint8_t> const *sessionId,
                        Vector<uint8_t> const *data);
 
+        void sendExpirationUpdate(Vector<uint8_t> const *sessionId,
+                                  int64_t expiryTimeInMS);
+
+        void sendKeysChange(Vector<uint8_t> const *sessionId,
+                            Vector<DrmPlugin::KeyStatus> const *keyStatusList,
+                            bool hasNewUsableKey);
+
     private:
         Mutex mEventLock;
         sp<DrmPluginListener> mListener;
@@ -331,14 +369,20 @@
     {
     public:
         virtual void sendEvent(DrmPlugin::EventType eventType, int extra,
-                               Vector<uint8_t> const *sesionId,
+                               Vector<uint8_t> const *sessionId,
                                Vector<uint8_t> const *data) = 0;
+
+        virtual void sendExpirationUpdate(Vector<uint8_t> const *sessionId,
+                                          int64_t expiryTimeInMS) = 0;
+
+        virtual void sendKeysChange(Vector<uint8_t> const *sessionId,
+                                    Vector<DrmPlugin::KeyStatus> const *keyStatusList,
+                                    bool hasNewUsableKey) = 0;
     };
 
     inline void DrmPlugin::sendEvent(EventType eventType, int extra,
                                      Vector<uint8_t> const *sessionId,
                                      Vector<uint8_t> const *data) {
-
         mEventLock.lock();
         sp<DrmPluginListener> listener = mListener;
         mEventLock.unlock();
@@ -348,6 +392,28 @@
         }
     }
 
+    inline void DrmPlugin::sendExpirationUpdate(Vector<uint8_t> const *sessionId,
+                                                int64_t expiryTimeInMS) {
+        mEventLock.lock();
+        sp<DrmPluginListener> listener = mListener;
+        mEventLock.unlock();
+
+        if (listener != NULL) {
+            listener->sendExpirationUpdate(sessionId, expiryTimeInMS);
+        }
+    }
+
+    inline void DrmPlugin::sendKeysChange(Vector<uint8_t> const *sessionId,
+                                          Vector<DrmPlugin::KeyStatus> const *keyStatusList,
+                                          bool hasNewUsableKey) {
+        mEventLock.lock();
+        sp<DrmPluginListener> listener = mListener;
+        mEventLock.unlock();
+
+        if (listener != NULL) {
+            listener->sendKeysChange(sessionId, keyStatusList, hasNewUsableKey);
+        }
+    }
 }  // namespace android
 
 #endif // DRM_API_H_
diff --git a/include/media/hardware/CryptoAPI.h b/include/media/hardware/CryptoAPI.h
index c800825..3e3257f 100644
--- a/include/media/hardware/CryptoAPI.h
+++ b/include/media/hardware/CryptoAPI.h
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
+#include <media/stagefright/MediaErrors.h>
 #include <utils/Errors.h>
+#include <utils/Vector.h>
 
 #ifndef CRYPTO_API_H_
 
@@ -68,7 +70,18 @@
     // the resolution of the video being decrypted.  The media player should
     // call this method when the resolution is determined and any time it
     // is subsequently changed.
-    virtual void notifyResolution(uint32_t width, uint32_t height) {}
+
+    virtual void notifyResolution(uint32_t /* width */, uint32_t /* height */) {}
+
+    // A MediaDrm session may be associated with a MediaCrypto session.  The
+    // associated MediaDrm session is used to load decryption keys
+    // into the crypto/drm plugin.  The keys are then referenced by key-id
+    // in the 'key' parameter to the decrypt() method.
+    // Should return NO_ERROR on success, ERROR_DRM_SESSION_NOT_OPENED if
+    // the session is not opened and a code from MediaErrors.h otherwise.
+    virtual status_t setMediaDrmSession(const Vector<uint8_t> & /*sessionId */) {
+        return ERROR_UNSUPPORTED;
+    }
 
     // If the error returned falls into the range
     // ERROR_DRM_VENDOR_MIN..ERROR_DRM_VENDOR_MAX, errorDetailMsg should be
diff --git a/include/media/hardware/HardwareAPI.h b/include/media/hardware/HardwareAPI.h
index d5f42be..1008c22 100644
--- a/include/media/hardware/HardwareAPI.h
+++ b/include/media/hardware/HardwareAPI.h
@@ -52,9 +52,9 @@
     OMX_BOOL enable;
 };
 
-// A pointer to this struct is passed to OMX_SetParameter() when the extension
-// index "OMX.google.android.index.storeMetaDataInBuffers"
-// is given.
+// A pointer to this struct is passed to OMX_SetParameter() when the extension index
+// "OMX.google.android.index.storeMetaDataInBuffers" or
+// "OMX.google.android.index.storeANWBufferInMetadata" is given.
 //
 // When meta data is stored in the video buffers passed between OMX clients
 // and OMX components, interpretation of the buffer data is up to the
@@ -62,19 +62,33 @@
 // some information helpful for the receiver to locate the actual data.
 // The buffer receiver thus needs to know how to interpret what is stored
 // in these buffers, with mechanisms pre-determined externally. How to
-// interpret the meta data is outside of the scope of this method.
+// interpret the meta data is outside of the scope of this parameter.
 //
-// Currently, this is specifically used to pass meta data from video source
-// (camera component, for instance) to video encoder to avoid memcpying of
-// input video frame data. To do this, bStoreMetaData is set to OMX_TRUE.
-// If bStoreMetaData is set to false, real YUV frame data will be stored
-// in the buffers. In addition, if no OMX_SetParameter() call is made
-// with the corresponding extension index, real YUV data is stored
-// in the buffers.
+// Currently, this is used to pass meta data from video source (camera component, for instance) to
+// video encoder to avoid memcpying of input video frame data, as well as to pass dynamic output
+// buffer to video decoder. To do this, bStoreMetaData is set to OMX_TRUE.
 //
-// For video decoder output port, the metadata buffer layout is defined below.
+// If bStoreMetaData is set to false, real YUV frame data will be stored in input buffers, and
+// the output buffers contain either real YUV frame data, or are themselves native handles as
+// directed by enable/use-android-native-buffer parameter settings.
+// In addition, if no OMX_SetParameter() call is made on a port with the corresponding extension
+// index, the component should not assume that the client is not using metadata mode for the port.
 //
-// Metadata buffers are registered with the component using UseBuffer calls.
+// If the component supports this using the "OMX.google.android.index.storeANWBufferInMetadata"
+// extension and bStoreMetaData is set to OMX_TRUE, data is passed using the VideoNativeMetadata
+// layout as defined below. Each buffer will be accompanied by a fence. The fence must signal
+// before the buffer can be used (e.g. read from or written into). When returning such buffer to
+// the client, component must provide a new fence that must signal before the returned buffer can
+// be used (e.g. read from or written into). The component owns the incoming fenceFd, and must close
+// it when fence has signaled. The client will own and close the returned fence file descriptor.
+//
+// If the component supports this using the "OMX.google.android.index.storeMetaDataInBuffers"
+// extension and bStoreMetaData is set to OMX_TRUE, data is passed using VideoGrallocMetadata
+// (the layout of which is the VideoGrallocMetadata defined below). Camera input can be also passed
+// as "CameraSource", the layout of which is vendor dependent.
+//
+// Metadata buffers are registered with the component using UseBuffer calls, or can be allocated
+// by the component for encoder-metadata-output buffers.
 struct StoreMetaDataInBuffersParams {
     OMX_U32 nSize;
     OMX_VERSIONTYPE nVersion;
@@ -84,9 +98,26 @@
 
 // Meta data buffer layout used to transport output frames to the decoder for
 // dynamic buffer handling.
-struct VideoDecoderOutputMetaData {
-  MetadataBufferType eType;
-  buffer_handle_t pHandle;
+struct VideoGrallocMetadata {
+    MetadataBufferType eType;               // must be kMetadataBufferTypeGrallocSource
+#ifdef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
+    OMX_PTR pHandle;
+#else
+    buffer_handle_t pHandle;
+#endif
+};
+
+// Legacy name for VideoGrallocMetadata struct.
+struct VideoDecoderOutputMetaData : public VideoGrallocMetadata {};
+
+struct VideoNativeMetadata {
+    MetadataBufferType eType;               // must be kMetadataBufferTypeANWBuffer
+#ifdef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
+    OMX_PTR pBuffer;
+#else
+    struct ANativeWindowBuffer* pBuffer;
+#endif
+    int nFenceFd;                           // -1 if unused
 };
 
 // A pointer to this struct is passed to OMX_SetParameter() when the extension
@@ -173,17 +204,17 @@
     };
 
     Type mType;
-    size_t mNumPlanes;              // number of planes
-    size_t mWidth;                  // width of largest plane (unpadded, as in nFrameWidth)
-    size_t mHeight;                 // height of largest plane (unpadded, as in nFrameHeight)
-    size_t mBitDepth;               // useable bit depth
+    uint32_t mNumPlanes;              // number of planes
+    uint32_t mWidth;                  // width of largest plane (unpadded, as in nFrameWidth)
+    uint32_t mHeight;                 // height of largest plane (unpadded, as in nFrameHeight)
+    uint32_t mBitDepth;               // useable bit depth
     struct PlaneInfo {
-        size_t mOffset;             // offset of first pixel of the plane in bytes
-                                    // from buffer offset
-        size_t mColInc;             // column increment in bytes
-        size_t mRowInc;             // row increment in bytes
-        size_t mHorizSubsampling;   // subsampling compared to the largest plane
-        size_t mVertSubsampling;    // subsampling compared to the largest plane
+        uint32_t mOffset;             // offset of first pixel of the plane in bytes
+                                      // from buffer offset
+        uint32_t mColInc;             // column increment in bytes
+        uint32_t mRowInc;             // row increment in bytes
+        uint32_t mHorizSubsampling;   // subsampling compared to the largest plane
+        uint32_t mVertSubsampling;    // subsampling compared to the largest plane
     };
     PlaneInfo mPlane[MAX_NUM_PLANES];
 };
diff --git a/include/media/hardware/MetadataBufferType.h b/include/media/hardware/MetadataBufferType.h
index 5876c40..b765203 100644
--- a/include/media/hardware/MetadataBufferType.h
+++ b/include/media/hardware/MetadataBufferType.h
@@ -77,28 +77,43 @@
      * GRalloc buffer. The encoder needs to interpret this GRalloc handle
      * and encode the frames.
      * --------------------------------------------------------------
-     * |  kMetadataBufferTypeGrallocSource | sizeof(buffer_handle_t) |
+     * |  kMetadataBufferTypeGrallocSource | buffer_handle_t buffer |
      * --------------------------------------------------------------
+     *
+     * See the VideoGrallocMetadata structure.
      */
     kMetadataBufferTypeGrallocSource = 1,
 
     /*
      * kMetadataBufferTypeGraphicBuffer is used to indicate that
      * the payload of the metadata buffers can be interpreted as
-     * a GraphicBuffer.  It is only to be used by software encoders.
-     * In this case, the metadata that the encoder receives
-     * will have a byte stream that consists of two parts:
+     * an ANativeWindowBuffer, and that a fence is provided.
+     *
+     * In this case, the metadata will have a byte stream that consists of three parts:
      * 1. First, there is an integer indicating that the metadata
-     * contains a GraphicBuffer (kMetadataBufferTypeGraphicBuffer)
-     * 2. This is followed by the pointer to the GraphicBuffer that
-     * is to be encoded.  Encoder must not create a sp<> from this
-     * graphic buffer, or free it, as it does not actually own this
-     * buffer.
-     * --------------------------------------------------------------
-     * |  kMetadataBufferTypeGraphicBuffer | sizeof(GraphicBuffer *) |
-     * --------------------------------------------------------------
+     * contains an ANativeWindowBuffer (kMetadataBufferTypeANWBuffer)
+     * 2. This is followed by the pointer to the ANativeWindowBuffer.
+     * Codec must not free this buffer as it does not actually own this buffer.
+     * 3. Finally, there is an integer containing a fence file descriptor.
+     * The codec must wait on the fence before encoding or decoding into this
+     * buffer. When the buffer is returned, codec must replace this file descriptor
+     * with a new fence, that will be waited on before the buffer is replaced
+     * (encoder) or read (decoder).
+     * ---------------------------------
+     * |  kMetadataBufferTypeANWBuffer |
+     * ---------------------------------
+     * |  ANativeWindowBuffer *buffer  |
+     * ---------------------------------
+     * |  int fenceFd                  |
+     * ---------------------------------
+     *
+     * See the VideoNativeMetadata structure.
      */
-    kMetadataBufferTypeGraphicBuffer = 2,
+    kMetadataBufferTypeANWBuffer = 2,
+
+    /* This value is used by framework, but is never used inside a metadata buffer  */
+    kMetadataBufferTypeInvalid = -1,
+
 
     // Add more here...
 
diff --git a/include/media/openmax/OMX_AsString.h b/include/media/openmax/OMX_AsString.h
index 0f177a1..ae8430d 100644
--- a/include/media/openmax/OMX_AsString.h
+++ b/include/media/openmax/OMX_AsString.h
@@ -287,6 +287,7 @@
 //      case OMX_EventComponentResumed:          return "ComponentResumed";
 //      case OMX_EventDynamicResourcesAvailable: return "DynamicResourcesAvailable";
 //      case OMX_EventPortFormatDetected:        return "PortFormatDetected";
+        case OMX_EventOutputRendered:            return "OutputRendered";
         default:                                 return def;
     }
 }
@@ -521,6 +522,9 @@
         case OMX_IndexParamVideoHevc:                   return "ParamVideoHevc";
 //      case OMX_IndexParamSliceSegments:               return "ParamSliceSegments";
         case OMX_IndexConfigAutoFramerateConversion:    return "ConfigAutoFramerateConversion";
+        case OMX_IndexConfigPriority:                   return "ConfigPriority";
+        case OMX_IndexConfigOperatingRate:              return "ConfigOperatingRate";
+        case OMX_IndexParamConsumerUsageBits:           return "ParamConsumerUsageBits";
         default:                                        return asString((OMX_INDEXTYPE)i, def);
     }
 }
diff --git a/include/media/openmax/OMX_Core.h b/include/media/openmax/OMX_Core.h
index 12f2b3b..521c223 100644
--- a/include/media/openmax/OMX_Core.h
+++ b/include/media/openmax/OMX_Core.h
@@ -503,12 +503,24 @@
     OMX_EventResourcesAcquired,   /**< component has been granted resources and is
                                        automatically starting the state change from
                                        OMX_StateWaitForResources to OMX_StateIdle. */
-   OMX_EventComponentResumed,     /**< Component resumed due to reacquisition of resources */
-   OMX_EventDynamicResourcesAvailable, /**< Component has acquired previously unavailable dynamic resources */
-   OMX_EventPortFormatDetected,      /**< Component has detected a supported format. */
-   OMX_EventKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
-   OMX_EventVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
-   OMX_EventMax = 0x7FFFFFFF
+    OMX_EventComponentResumed,     /**< Component resumed due to reacquisition of resources */
+    OMX_EventDynamicResourcesAvailable, /**< Component has acquired previously unavailable dynamic resources */
+    OMX_EventPortFormatDetected,      /**< Component has detected a supported format. */
+    OMX_EventKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
+    OMX_EventVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+
+    /** Event when tunneled decoder has rendered an output
+     *  nData1 must contain the number of timestamps returned
+     *  pEventData must point to an array of the OMX_VIDEO_RENDEREVENTTYPE structs containing the
+     *  render-timestamps of each frame. Component may batch rendered timestamps using this event,
+     *  but must signal the event no more than 40ms after the first frame in the batch. The frames
+     *  must be ordered by system timestamp inside and across batches.
+     *
+     *  If component is doing frame-rate conversion, it must signal the render time of each
+     *  converted frame, and must interpolate media timestamps for in-between frames.
+     */
+    OMX_EventOutputRendered = 0x7F000001,
+    OMX_EventMax = 0x7FFFFFFF
 } OMX_EVENTTYPE;
 
 typedef struct OMX_CALLBACKTYPE
diff --git a/include/media/openmax/OMX_IVCommon.h b/include/media/openmax/OMX_IVCommon.h
index a5b9d18..f9b6f4b 100644
--- a/include/media/openmax/OMX_IVCommon.h
+++ b/include/media/openmax/OMX_IVCommon.h
@@ -157,6 +157,7 @@
      * an acceptable range once that is done.
      * */
     OMX_COLOR_FormatAndroidOpaque = 0x7F000789,
+    OMX_COLOR_Format32BitRGBA8888 = 0x7F00A000,
     /** Flexible 8-bit YUV format.  Codec should report this format
      *  as being supported if it supports any YUV420 packed planar
      *  or semiplanar formats.  When port is set to use this format,
diff --git a/include/media/openmax/OMX_IndexExt.h b/include/media/openmax/OMX_IndexExt.h
index ea3d0da..25bea1f 100644
--- a/include/media/openmax/OMX_IndexExt.h
+++ b/include/media/openmax/OMX_IndexExt.h
@@ -83,6 +83,9 @@
     /* Other configurations */
     OMX_IndexExtOtherStartUnused = OMX_IndexKhronosExtensions + 0x00800000,
     OMX_IndexConfigAutoFramerateConversion,         /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigPriority,                        /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexConfigOperatingRate,                   /**< reference: OMX_PARAM_U32TYPE in Q16 format for video and in Hz for audio */
+    OMX_IndexParamConsumerUsageBits,                /**< reference: OMX_PARAM_U32TYPE */
 
     /* Time configurations */
     OMX_IndexExtTimeStartUnused = OMX_IndexKhronosExtensions + 0x00900000,
diff --git a/include/media/openmax/OMX_VideoExt.h b/include/media/openmax/OMX_VideoExt.h
index 3c97e14..34c0405 100644
--- a/include/media/openmax/OMX_VideoExt.h
+++ b/include/media/openmax/OMX_VideoExt.h
@@ -203,6 +203,12 @@
     OMX_BOOL bEnableLoopFilterAcrossSlices;
 } OMX_VIDEO_SLICESEGMENTSTYPE;
 
+/** Structure to return timestamps of rendered output frames for tunneled components */
+typedef struct OMX_VIDEO_RENDEREVENTTYPE {
+    OMX_S64 nMediaTimeUs;  // timestamp of rendered video frame
+    OMX_S64 nSystemTimeNs; // system monotonic time at the time frame was rendered
+} OMX_VIDEO_RENDEREVENTTYPE;
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/include/private/gui/LayerState.h b/include/private/gui/LayerState.h
index 2fa6ff9..cbe8733 100644
--- a/include/private/gui/LayerState.h
+++ b/include/private/gui/LayerState.h
@@ -39,6 +39,7 @@
     enum {
         eLayerHidden        = 0x01,     // SURFACE_HIDDEN in SurfaceControl.java
         eLayerOpaque        = 0x02,     // SURFACE_OPAQUE
+        eLayerSecure        = 0x80,     // SECURE
     };
 
     enum {
@@ -48,10 +49,9 @@
         eAlphaChanged               = 0x00000008,
         eMatrixChanged              = 0x00000010,
         eTransparentRegionChanged   = 0x00000020,
-        eVisibilityChanged          = 0x00000040,
+        eFlagsChanged               = 0x00000040,
         eLayerStackChanged          = 0x00000080,
         eCropChanged                = 0x00000100,
-        eOpacityChanged             = 0x00000200,
     };
 
     layer_state_t()
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index f91d192..3da720f 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -94,6 +94,11 @@
     Rect getBounds() const              { return Rect(width, height); }
     uint64_t getId() const              { return mId; }
 
+    uint32_t getGenerationNumber() const { return mGenerationNumber; }
+    void setGenerationNumber(uint32_t generation) {
+        mGenerationNumber = generation;
+    }
+
     status_t reallocate(uint32_t inWidth, uint32_t inHeight,
             PixelFormat inFormat, uint32_t inUsage);
 
@@ -166,6 +171,11 @@
     sp<ANativeWindowBuffer> mWrappedBuffer;
 
     uint64_t mId;
+
+    // Stores the generation number of this buffer. If this number does not
+    // match the BufferQueue's internal generation number (set through
+    // IGBP::setGenerationNumber), attempts to attach the buffer will fail.
+    uint32_t mGenerationNumber;
 };
 
 }; // namespace android
diff --git a/libs/binder/Android.mk b/libs/binder/Android.mk
index 79decfe..d5860ef 100644
--- a/libs/binder/Android.mk
+++ b/libs/binder/Android.mk
@@ -26,6 +26,8 @@
     IMemory.cpp \
     IPCThreadState.cpp \
     IPermissionController.cpp \
+    IProcessInfoService.cpp \
+    ProcessInfoService.cpp \
     IServiceManager.cpp \
     MemoryDealer.cpp \
     MemoryBase.cpp \
diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp
index c562c30..e4d8201 100644
--- a/libs/binder/AppOpsManager.cpp
+++ b/libs/binder/AppOpsManager.cpp
@@ -104,4 +104,13 @@
     }
 }
 
+int32_t AppOpsManager::permissionToOpCode(const String16& permission) {
+    sp<IAppOpsService> service = getService();
+    if (service != NULL) {
+        return service->permissionToOpCode(permission);
+    }
+    return -1;
+}
+
+
 }; // namespace android
diff --git a/libs/binder/BufferedTextOutput.cpp b/libs/binder/BufferedTextOutput.cpp
index 2d493c1..1339a67 100644
--- a/libs/binder/BufferedTextOutput.cpp
+++ b/libs/binder/BufferedTextOutput.cpp
@@ -49,9 +49,12 @@
     
     status_t append(const char* txt, size_t len) {
         if ((len+bufferPos) > bufferSize) {
-            void* b = realloc(buffer, ((len+bufferPos)*3)/2);
+            size_t newSize = ((len+bufferPos)*3)/2;
+            if (newSize < (len+bufferPos)) return NO_MEMORY;    // overflow
+            void* b = realloc(buffer, newSize);
             if (!b) return NO_MEMORY;
             buffer = (char*)b;
+            bufferSize = newSize;
         }
         memcpy(buffer+bufferPos, txt, len);
         bufferPos += len;
diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp
index 86abdc0..9558376 100644
--- a/libs/binder/IAppOpsService.cpp
+++ b/libs/binder/IAppOpsService.cpp
@@ -111,6 +111,17 @@
         if (reply.readExceptionCode() != 0) return NULL;
         return reply.readStrongBinder();
     }
+
+
+    virtual int32_t permissionToOpCode(const String16& permission) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
+        data.writeString16(permission);
+        remote()->transact(PERMISSION_TO_OP_CODE_TRANSACTION, data, &reply);
+        // fail on exception
+        if (reply.readExceptionCode() != 0) return -1;
+        return reply.readInt32();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AppOpsService, "com.android.internal.app.IAppOpsService");
@@ -187,6 +198,14 @@
             reply->writeStrongBinder(token);
             return NO_ERROR;
         } break;
+        case PERMISSION_TO_OP_CODE_TRANSACTION: {
+            CHECK_INTERFACE(IAppOpsService, data, reply);
+            String16 permission = data.readString16();
+            const int32_t opCode = permissionToOpCode(permission);
+            reply->writeNoException();
+            reply->writeInt32(opCode);
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/libs/binder/IBatteryStats.cpp b/libs/binder/IBatteryStats.cpp
index 8f3b7b4..e32c628 100644
--- a/libs/binder/IBatteryStats.cpp
+++ b/libs/binder/IBatteryStats.cpp
@@ -89,6 +89,47 @@
         data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor());
         remote()->transact(NOTE_RESET_AUDIO_TRANSACTION, data, &reply);
     }
+
+    virtual void noteFlashlightOn(int uid) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor());
+        data.writeInt32(uid);
+        remote()->transact(NOTE_FLASHLIGHT_ON_TRANSACTION, data, &reply);
+    }
+
+    virtual void noteFlashlightOff(int uid) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor());
+        data.writeInt32(uid);
+        remote()->transact(NOTE_FLASHLIGHT_OFF_TRANSACTION, data, &reply);
+    }
+
+    virtual void noteStartCamera(int uid) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor());
+        data.writeInt32(uid);
+        remote()->transact(NOTE_START_CAMERA_TRANSACTION, data, &reply);
+    }
+
+    virtual void noteStopCamera(int uid) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor());
+        data.writeInt32(uid);
+        remote()->transact(NOTE_STOP_CAMERA_TRANSACTION, data, &reply);
+    }
+
+    virtual void noteResetCamera() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor());
+        remote()->transact(NOTE_RESET_CAMERA_TRANSACTION, data, &reply);
+    }
+
+    virtual void noteResetFlashlight() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor());
+        remote()->transact(NOTE_RESET_FLASHLIGHT_TRANSACTION, data, &reply);
+    }
+
 };
 
 IMPLEMENT_META_INTERFACE(BatteryStats, "com.android.internal.app.IBatteryStats");
@@ -155,6 +196,46 @@
             reply->writeNoException();
             return NO_ERROR;
         } break;
+        case NOTE_FLASHLIGHT_ON_TRANSACTION: {
+            CHECK_INTERFACE(IBatteryStats, data, reply);
+            int uid = data.readInt32();
+            noteFlashlightOn(uid);
+            reply->writeNoException();
+            return NO_ERROR;
+        } break;
+        case NOTE_FLASHLIGHT_OFF_TRANSACTION: {
+            CHECK_INTERFACE(IBatteryStats, data, reply);
+            int uid = data.readInt32();
+            noteFlashlightOff(uid);
+            reply->writeNoException();
+            return NO_ERROR;
+        } break;
+        case NOTE_START_CAMERA_TRANSACTION: {
+            CHECK_INTERFACE(IBatteryStats, data, reply);
+            int uid = data.readInt32();
+            noteStartCamera(uid);
+            reply->writeNoException();
+            return NO_ERROR;
+        } break;
+        case NOTE_STOP_CAMERA_TRANSACTION: {
+            CHECK_INTERFACE(IBatteryStats, data, reply);
+            int uid = data.readInt32();
+            noteStopCamera(uid);
+            reply->writeNoException();
+            return NO_ERROR;
+        } break;
+        case NOTE_RESET_CAMERA_TRANSACTION: {
+            CHECK_INTERFACE(IBatteryStats, data, reply);
+            noteResetCamera();
+            reply->writeNoException();
+            return NO_ERROR;
+        } break;
+        case NOTE_RESET_FLASHLIGHT_TRANSACTION: {
+            CHECK_INTERFACE(IBatteryStats, data, reply);
+            noteResetFlashlight();
+            reply->writeNoException();
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/libs/binder/IInterface.cpp b/libs/binder/IInterface.cpp
index 8c60dc4..2fcd3d9 100644
--- a/libs/binder/IInterface.cpp
+++ b/libs/binder/IInterface.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "IInterface"
+#include <utils/Log.h>
 #include <binder/IInterface.h>
 
 namespace android {
@@ -41,6 +43,25 @@
     return iface->onAsBinder();
 }
 
+
 // ---------------------------------------------------------------------------
 
 }; // namespace android
+
+extern "C" {
+
+void _ZN7android10IInterface8asBinderEv(void *retval, void* self) {
+    ALOGW("deprecated asBinder call, please update your code");
+    //ALOGI("self: %p, retval: %p", self, retval);
+    android::sp<android::IBinder> *ret = new(retval) android::sp<android::IBinder>;
+    *ret = android::IInterface::asBinder((android::IInterface*)self);
+}
+
+void _ZNK7android10IInterface8asBinderEv(void *retval, void *self) {
+    ALOGW("deprecated asBinder call, please update your code");
+    //ALOGI("self: %p, retval: %p", self, retval);
+    android::sp<android::IBinder> *ret = new(retval) android::sp<android::IBinder>;
+    *ret = android::IInterface::asBinder((android::IInterface*)self);
+}
+
+} // extern "C"
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 9f68aa8..ef88181 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -399,6 +399,18 @@
     talkWithDriver(false);
 }
 
+void IPCThreadState::blockUntilThreadAvailable()
+{
+    pthread_mutex_lock(&mProcess->mThreadCountLock);
+    while (mProcess->mExecutingThreadsCount >= mProcess->mMaxThreads) {
+        ALOGW("Waiting for thread to be free. mExecutingThreadsCount=%lu mMaxThreads=%lu\n",
+                static_cast<unsigned long>(mProcess->mExecutingThreadsCount),
+                static_cast<unsigned long>(mProcess->mMaxThreads));
+        pthread_cond_wait(&mProcess->mThreadCountDecrement, &mProcess->mThreadCountLock);
+    }
+    pthread_mutex_unlock(&mProcess->mThreadCountLock);
+}
+
 status_t IPCThreadState::getAndExecuteCommand()
 {
     status_t result;
@@ -414,8 +426,17 @@
                  << getReturnString(cmd) << endl;
         }
 
+        pthread_mutex_lock(&mProcess->mThreadCountLock);
+        mProcess->mExecutingThreadsCount++;
+        pthread_mutex_unlock(&mProcess->mThreadCountLock);
+
         result = executeCommand(cmd);
 
+        pthread_mutex_lock(&mProcess->mThreadCountLock);
+        mProcess->mExecutingThreadsCount--;
+        pthread_cond_broadcast(&mProcess->mThreadCountDecrement);
+        pthread_mutex_unlock(&mProcess->mThreadCountLock);
+
         // After executing the command, ensure that the thread is returned to the
         // foreground cgroup before rejoining the pool.  The driver takes care of
         // restoring the priority, but doesn't do anything with cgroups so we
diff --git a/libs/binder/IPermissionController.cpp b/libs/binder/IPermissionController.cpp
index 437113d..6bba996 100644
--- a/libs/binder/IPermissionController.cpp
+++ b/libs/binder/IPermissionController.cpp
@@ -48,6 +48,36 @@
         if (reply.readExceptionCode() != 0) return 0;
         return reply.readInt32() != 0;
     }
+
+    virtual void getPackagesForUid(const uid_t uid, Vector<String16>& packages)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor());
+        data.writeInt32(uid);
+        remote()->transact(GET_PACKAGES_FOR_UID_TRANSACTION, data, &reply);
+        // fail on exception
+        if (reply.readExceptionCode() != 0) {
+            return;
+        }
+        const int32_t size = reply.readInt32();
+        if (size <= 0) {
+            return;
+        }
+        for (int i = 0; i < size; i++) {
+            packages.push(reply.readString16());
+        }
+    }
+
+    virtual bool isRuntimePermission(const String16& permission)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor());
+        data.writeString16(permission);
+        remote()->transact(IS_RUNTIME_PERMISSION_TRANSACTION, data, &reply);
+        // fail on exception
+        if (reply.readExceptionCode() != 0) return false;
+        return reply.readInt32() != 0;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(PermissionController, "android.os.IPermissionController");
@@ -57,7 +87,6 @@
 status_t BnPermissionController::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
-    //printf("PermissionController received: "); data.print();
     switch(code) {
         case CHECK_PERMISSION_TRANSACTION: {
             CHECK_INTERFACE(IPermissionController, data, reply);
@@ -69,6 +98,30 @@
             reply->writeInt32(res ? 1 : 0);
             return NO_ERROR;
         } break;
+
+        case GET_PACKAGES_FOR_UID_TRANSACTION: {
+            CHECK_INTERFACE(IPermissionController, data, reply);
+            int32_t uid = data.readInt32();
+            Vector<String16> packages;
+            getPackagesForUid(uid, packages);
+            reply->writeNoException();
+            size_t size = packages.size();
+            reply->writeInt32(size);
+            for (size_t i = 0; i < size; i++) {
+                reply->writeString16(packages[i]);
+            }
+            return NO_ERROR;
+        } break;
+
+        case IS_RUNTIME_PERMISSION_TRANSACTION: {
+            CHECK_INTERFACE(IPermissionController, data, reply);
+            String16 permission = data.readString16();
+            const bool res = isRuntimePermission(permission);
+            reply->writeNoException();
+            reply->writeInt32(res ? 1 : 0);
+            return NO_ERROR;
+        } break;
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/libs/binder/IProcessInfoService.cpp b/libs/binder/IProcessInfoService.cpp
new file mode 100644
index 0000000..d86eb27
--- /dev/null
+++ b/libs/binder/IProcessInfoService.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2015 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 <binder/IProcessInfoService.h>
+#include <binder/Parcel.h>
+#include <utils/Errors.h>
+#include <sys/types.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class BpProcessInfoService : public BpInterface<IProcessInfoService> {
+public:
+    BpProcessInfoService(const sp<IBinder>& impl)
+        : BpInterface<IProcessInfoService>(impl) {}
+
+    virtual status_t getProcessStatesFromPids(size_t length, /*in*/ int32_t* pids,
+            /*out*/ int32_t* states)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IProcessInfoService::getInterfaceDescriptor());
+        data.writeInt32Array(length, pids);
+        data.writeInt32(length); // write length of output array, used by java AIDL stubs
+        status_t err = remote()->transact(GET_PROCESS_STATES_FROM_PIDS, data, &reply);
+        if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) {
+            return err;
+        }
+        int32_t replyLen = reply.readInt32();
+        if (static_cast<size_t>(replyLen) != length) {
+            return NOT_ENOUGH_DATA;
+        }
+        if (replyLen > 0 && (err = reply.read(states, length * sizeof(*states))) != NO_ERROR) {
+            return err;
+        }
+        return reply.readInt32();
+    }
+
+};
+
+IMPLEMENT_META_INTERFACE(ProcessInfoService, "android.os.IProcessInfoService");
+
+// ----------------------------------------------------------------------
+
+status_t BnProcessInfoService::onTransact( uint32_t code, const Parcel& data, Parcel* reply,
+        uint32_t flags) {
+    switch(code) {
+        case GET_PROCESS_STATES_FROM_PIDS: {
+            CHECK_INTERFACE(IProcessInfoService, data, reply);
+            int32_t arrayLen = data.readInt32();
+            if (arrayLen <= 0) {
+                reply->writeNoException();
+                reply->writeInt32(0);
+                reply->writeInt32(NOT_ENOUGH_DATA);
+                return NO_ERROR;
+            }
+
+            size_t len = static_cast<size_t>(arrayLen);
+            int32_t pids[len];
+            status_t res = data.read(pids, len * sizeof(*pids));
+
+            // Ignore output array length returned in the parcel here, as the states array must
+            // always be the same length as the input PIDs array.
+            int32_t states[len];
+            for (size_t i = 0; i < len; i++) states[i] = -1;
+            if (res == NO_ERROR) {
+                res = getProcessStatesFromPids(len, /*in*/ pids, /*out*/ states);
+            }
+            reply->writeNoException();
+            reply->writeInt32Array(len, states);
+            reply->writeInt32(res);
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index d769caa..7a4ddc4 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -54,7 +54,17 @@
 
 // ---------------------------------------------------------------------------
 
-#define PAD_SIZE(s) (((s)+3)&~3)
+// This macro should never be used at runtime, as a too large value
+// of s could cause an integer overflow. Instead, you should always
+// use the wrapper function pad_size()
+#define PAD_SIZE_UNSAFE(s) (((s)+3)&~3)
+
+static size_t pad_size(size_t s) {
+    if (s > (SIZE_T_MAX - 3)) {
+        abort();
+    }
+    return PAD_SIZE_UNSAFE(s);
+}
 
 // Note: must be kept in sync with android/os/StrictMode.java's PENALTY_GATHER
 #define STRICT_MODE_PENALTY_GATHER (0x40 << 16)
@@ -62,9 +72,6 @@
 // Note: must be kept in sync with android/os/Parcel.java's EX_HAS_REPLY_HEADER
 #define EX_HAS_REPLY_HEADER -128
 
-// Maximum size of a blob to transfer in-place.
-static const size_t IN_PLACE_BLOB_LIMIT = 40 * 1024;
-
 // XXX This can be made public if we want to provide
 // support for typed data.
 struct small_flat_data
@@ -79,6 +86,15 @@
 static size_t gParcelGlobalAllocSize = 0;
 static size_t gParcelGlobalAllocCount = 0;
 
+// Maximum size of a blob to transfer in-place.
+static const size_t BLOB_INPLACE_LIMIT = 16 * 1024;
+
+enum {
+    BLOB_INPLACE = 0,
+    BLOB_ASHMEM_IMMUTABLE = 1,
+    BLOB_ASHMEM_MUTABLE = 2,
+};
+
 void acquire_object(const sp<ProcessState>& proc,
     const flat_binder_object& obj, const void* who)
 {
@@ -355,6 +371,12 @@
 
 status_t Parcel::setDataSize(size_t size)
 {
+    if (size > INT32_MAX) {
+        // don't accept size_t values which may have come from an
+        // inadvertent conversion from a negative int.
+        return BAD_VALUE;
+    }
+
     status_t err;
     err = continueWrite(size);
     if (err == NO_ERROR) {
@@ -366,18 +388,36 @@
 
 void Parcel::setDataPosition(size_t pos) const
 {
+    if (pos > INT32_MAX) {
+        // don't accept size_t values which may have come from an
+        // inadvertent conversion from a negative int.
+        abort();
+    }
+
     mDataPos = pos;
     mNextObjectHint = 0;
 }
 
 status_t Parcel::setDataCapacity(size_t size)
 {
+    if (size > INT32_MAX) {
+        // don't accept size_t values which may have come from an
+        // inadvertent conversion from a negative int.
+        return BAD_VALUE;
+    }
+
     if (size > mDataCapacity) return continueWrite(size);
     return NO_ERROR;
 }
 
 status_t Parcel::setData(const uint8_t* buffer, size_t len)
 {
+    if (len > INT32_MAX) {
+        // don't accept size_t values which may have come from an
+        // inadvertent conversion from a negative int.
+        return BAD_VALUE;
+    }
+
     status_t err = restartWrite(len);
     if (err == NO_ERROR) {
         memcpy(const_cast<uint8_t*>(data()), buffer, len);
@@ -401,6 +441,12 @@
         return NO_ERROR;
     }
 
+    if (len > INT32_MAX) {
+        // don't accept size_t values which may have come from an
+        // inadvertent conversion from a negative int.
+        return BAD_VALUE;
+    }
+
     // range checks against the source parcel size
     if ((offset > parcel->mDataSize)
             || (len > parcel->mDataSize)
@@ -438,7 +484,8 @@
     if (numObjects > 0) {
         // grow objects
         if (mObjectsCapacity < mObjectsSize + numObjects) {
-            int newSize = ((mObjectsSize + numObjects)*3)/2;
+            size_t newSize = ((mObjectsSize + numObjects)*3)/2;
+            if (newSize < mObjectsSize) return NO_MEMORY;   // overflow
             binder_size_t *objects =
                 (binder_size_t*)realloc(mObjects, newSize*sizeof(binder_size_t));
             if (objects == (binder_size_t*)0) {
@@ -476,6 +523,11 @@
     return err;
 }
 
+bool Parcel::allowFds() const
+{
+    return mAllowFds;
+}
+
 bool Parcel::pushAllowFds(bool allowFds)
 {
     const bool origValue = mAllowFds;
@@ -561,6 +613,12 @@
 
 status_t Parcel::finishWrite(size_t len)
 {
+    if (len > INT32_MAX) {
+        // don't accept size_t values which may have come from an
+        // inadvertent conversion from a negative int.
+        return BAD_VALUE;
+    }
+
     //printf("Finish write of %d\n", len);
     mDataPos += len;
     ALOGV("finishWrite Setting data pos of %p to %zu", this, mDataPos);
@@ -574,6 +632,12 @@
 
 status_t Parcel::writeUnpadded(const void* data, size_t len)
 {
+    if (len > INT32_MAX) {
+        // don't accept size_t values which may have come from an
+        // inadvertent conversion from a negative int.
+        return BAD_VALUE;
+    }
+
     size_t end = mDataPos + len;
     if (end < mDataPos) {
         // integer overflow
@@ -593,6 +657,12 @@
 
 status_t Parcel::write(const void* data, size_t len)
 {
+    if (len > INT32_MAX) {
+        // don't accept size_t values which may have come from an
+        // inadvertent conversion from a negative int.
+        return BAD_VALUE;
+    }
+
     void* const d = writeInplace(len);
     if (d) {
         memcpy(d, data, len);
@@ -603,7 +673,13 @@
 
 void* Parcel::writeInplace(size_t len)
 {
-    const size_t padded = PAD_SIZE(len);
+    if (len > INT32_MAX) {
+        // don't accept size_t values which may have come from an
+        // inadvertent conversion from a negative int.
+        return NULL;
+    }
+
+    const size_t padded = pad_size(len);
 
     // sanity check for integer overflow
     if (mDataPos+padded < mDataPos) {
@@ -652,20 +728,32 @@
 }
 
 status_t Parcel::writeInt32Array(size_t len, const int32_t *val) {
-    if (!val) {
-        return writeAligned(-1);
+    if (len > INT32_MAX) {
+        // don't accept size_t values which may have come from an
+        // inadvertent conversion from a negative int.
+        return BAD_VALUE;
     }
-    status_t ret = writeAligned(len);
+
+    if (!val) {
+        return writeInt32(-1);
+    }
+    status_t ret = writeInt32(static_cast<uint32_t>(len));
     if (ret == NO_ERROR) {
         ret = write(val, len * sizeof(*val));
     }
     return ret;
 }
 status_t Parcel::writeByteArray(size_t len, const uint8_t *val) {
-    if (!val) {
-        return writeAligned(-1);
+    if (len > INT32_MAX) {
+        // don't accept size_t values which may have come from an
+        // inadvertent conversion from a negative int.
+        return BAD_VALUE;
     }
-    status_t ret = writeAligned(len);
+
+    if (!val) {
+        return writeInt32(-1);
+    }
+    status_t ret = writeInt32(static_cast<uint32_t>(len));
     if (ret == NO_ERROR) {
         ret = write(val, len * sizeof(*val));
     }
@@ -677,6 +765,11 @@
     return writeAligned(val);
 }
 
+status_t Parcel::writeUint64(uint64_t val)
+{
+    return writeAligned(val);
+}
+
 status_t Parcel::writePointer(uintptr_t val)
 {
     return writeAligned<binder_uintptr_t>(val);
@@ -805,45 +898,24 @@
     return err;
 }
 
-// WARNING: This method must stay in sync with
-// Parcelable.Creator<ParcelFileDescriptor> CREATOR
-// in frameworks/base/core/java/android/os/ParcelFileDescriptor.java
-status_t Parcel::writeParcelFileDescriptor(int fd, int commChannel) {
-    status_t status;
-
-    if (fd < 0) {
-        status = writeInt32(0); // ParcelFileDescriptor is null
-        if (status) return status;
-    } else {
-        status = writeInt32(1); // ParcelFileDescriptor is not null
-        if (status) return status;
-        status = writeDupFileDescriptor(fd);
-        if (status) return status;
-        if (commChannel < 0) {
-            status = writeInt32(0); // commChannel is null
-            if (status) return status;
-        } else {
-            status = writeInt32(1); // commChannel is not null
-            if (status) return status;
-            status = writeDupFileDescriptor(commChannel);
-        }
-    }
-    return status;
-}
-
-status_t Parcel::writeBlob(size_t len, WritableBlob* outBlob)
+status_t Parcel::writeBlob(size_t len, bool mutableCopy, WritableBlob* outBlob)
 {
-    status_t status;
+    if (len > INT32_MAX) {
+        // don't accept size_t values which may have come from an
+        // inadvertent conversion from a negative int.
+        return BAD_VALUE;
+    }
 
-    if (!mAllowFds || len <= IN_PLACE_BLOB_LIMIT) {
+    status_t status;
+    if (!mAllowFds || len <= BLOB_INPLACE_LIMIT) {
         ALOGV("writeBlob: write in place");
-        status = writeInt32(0);
+        status = writeInt32(BLOB_INPLACE);
         if (status) return status;
 
         void* ptr = writeInplace(len);
         if (!ptr) return NO_MEMORY;
 
-        outBlob->init(false /*mapped*/, ptr, len);
+        outBlob->init(-1, ptr, len, false);
         return NO_ERROR;
     }
 
@@ -851,6 +923,8 @@
     int fd = ashmem_create_region("Parcel Blob", len);
     if (fd < 0) return NO_MEMORY;
 
+    mBlobAshmemSize += len;
+
     int result = ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE);
     if (result < 0) {
         status = result;
@@ -859,15 +933,17 @@
         if (ptr == MAP_FAILED) {
             status = -errno;
         } else {
-            result = ashmem_set_prot_region(fd, PROT_READ);
+            if (!mutableCopy) {
+                result = ashmem_set_prot_region(fd, PROT_READ);
+            }
             if (result < 0) {
                 status = result;
             } else {
-                status = writeInt32(1);
+                status = writeInt32(mutableCopy ? BLOB_ASHMEM_MUTABLE : BLOB_ASHMEM_IMMUTABLE);
                 if (!status) {
                     status = writeFileDescriptor(fd, true /*takeOwnership*/);
                     if (!status) {
-                        outBlob->init(true /*mapped*/, ptr, len);
+                        outBlob->init(fd, ptr, len, mutableCopy);
                         return NO_ERROR;
                     }
                 }
@@ -879,6 +955,15 @@
     return status;
 }
 
+status_t Parcel::writeDupImmutableBlobFileDescriptor(int fd)
+{
+    // Must match up with what's done in writeBlob.
+    if (!mAllowFds) return FDS_NOT_ALLOWED;
+    status_t status = writeInt32(BLOB_ASHMEM_IMMUTABLE);
+    if (status) return status;
+    return writeDupFileDescriptor(fd);
+}
+
 status_t Parcel::write(const FlattenableHelperInterface& val)
 {
     status_t err;
@@ -887,6 +972,12 @@
     const size_t len = val.getFlattenedSize();
     const size_t fd_count = val.getFdCount();
 
+    if ((len > INT32_MAX) || (fd_count > INT32_MAX)) {
+        // don't accept size_t values which may have come from an
+        // inadvertent conversion from a negative int.
+        return BAD_VALUE;
+    }
+
     err = this->writeInt32(len);
     if (err) return err;
 
@@ -894,7 +985,7 @@
     if (err) return err;
 
     // payload
-    void* const buf = this->writeInplace(PAD_SIZE(len));
+    void* const buf = this->writeInplace(pad_size(len));
     if (buf == NULL)
         return BAD_VALUE;
 
@@ -923,6 +1014,15 @@
 restart_write:
         *reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val;
 
+        // remember if it's a file descriptor
+        if (val.type == BINDER_TYPE_FD) {
+            if (!mAllowFds) {
+                // fail before modifying our object index
+                return FDS_NOT_ALLOWED;
+            }
+            mHasFds = mFdsKnown = true;
+        }
+
         // Need to write meta-data?
         if (nullMetaData || val.binder != 0) {
             mObjects[mObjectsSize] = mDataPos;
@@ -930,14 +1030,6 @@
             mObjectsSize++;
         }
 
-        // remember if it's a file descriptor
-        if (val.type == BINDER_TYPE_FD) {
-            if (!mAllowFds) {
-                return FDS_NOT_ALLOWED;
-            }
-            mHasFds = mFdsKnown = true;
-        }
-
         return finishWrite(sizeof(flat_binder_object));
     }
 
@@ -947,6 +1039,7 @@
     }
     if (!enoughObjects) {
         size_t newSize = ((mObjectsSize+2)*3)/2;
+        if (newSize < mObjectsSize) return NO_MEMORY;   // overflow
         binder_size_t* objects = (binder_size_t*)realloc(mObjects, newSize*sizeof(binder_size_t));
         if (objects == NULL) return NO_MEMORY;
         mObjects = objects;
@@ -968,10 +1061,16 @@
 
 status_t Parcel::read(void* outData, size_t len) const
 {
-    if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize
-            && len <= PAD_SIZE(len)) {
+    if (len > INT32_MAX) {
+        // don't accept size_t values which may have come from an
+        // inadvertent conversion from a negative int.
+        return BAD_VALUE;
+    }
+
+    if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize
+            && len <= pad_size(len)) {
         memcpy(outData, mData+mDataPos, len);
-        mDataPos += PAD_SIZE(len);
+        mDataPos += pad_size(len);
         ALOGV("read Setting data pos of %p to %zu", this, mDataPos);
         return NO_ERROR;
     }
@@ -980,10 +1079,16 @@
 
 const void* Parcel::readInplace(size_t len) const
 {
-    if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize
-            && len <= PAD_SIZE(len)) {
+    if (len > INT32_MAX) {
+        // don't accept size_t values which may have come from an
+        // inadvertent conversion from a negative int.
+        return NULL;
+    }
+
+    if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize
+            && len <= pad_size(len)) {
         const void* data = mData+mDataPos;
-        mDataPos += PAD_SIZE(len);
+        mDataPos += pad_size(len);
         ALOGV("readInplace Setting data pos of %p to %zu", this, mDataPos);
         return data;
     }
@@ -992,7 +1097,7 @@
 
 template<class T>
 status_t Parcel::readAligned(T *pArg) const {
-    COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T));
+    COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
 
     if ((mDataPos+sizeof(T)) <= mDataSize) {
         const void* data = mData+mDataPos;
@@ -1016,7 +1121,7 @@
 
 template<class T>
 status_t Parcel::writeAligned(T val) {
-    COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T));
+    COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
 
     if ((mDataPos+sizeof(val)) <= mDataCapacity) {
 restart_write:
@@ -1060,6 +1165,16 @@
     return readAligned<int64_t>();
 }
 
+status_t Parcel::readUint64(uint64_t *pArg) const
+{
+    return readAligned(pArg);
+}
+
+uint64_t Parcel::readUint64() const
+{
+    return readAligned<uint64_t>();
+}
+
 status_t Parcel::readPointer(uintptr_t *pArg) const
 {
     status_t ret;
@@ -1147,7 +1262,7 @@
         const char* eos = reinterpret_cast<const char*>(memchr(str, 0, avail));
         if (eos) {
             const size_t len = eos - str;
-            mDataPos += PAD_SIZE(len+1);
+            mDataPos += pad_size(len+1);
             ALOGV("readCString Setting data pos of %p to %zu", this, mDataPos);
             return str;
         }
@@ -1261,46 +1376,31 @@
     return BAD_TYPE;
 }
 
-// WARNING: This method must stay in sync with writeToParcel()
-// in frameworks/base/core/java/android/os/ParcelFileDescriptor.java
-int Parcel::readParcelFileDescriptor(int& outCommChannel) const {
-    int fd;
-    outCommChannel = -1;
-
-    if (readInt32() == 0) {
-        fd = -1;
-    } else {
-        fd = readFileDescriptor();
-        if (fd >= 0 && readInt32() != 0) {
-            outCommChannel = readFileDescriptor();
-        }
-    }
-    return fd;
-}
-
 status_t Parcel::readBlob(size_t len, ReadableBlob* outBlob) const
 {
-    int32_t useAshmem;
-    status_t status = readInt32(&useAshmem);
+    int32_t blobType;
+    status_t status = readInt32(&blobType);
     if (status) return status;
 
-    if (!useAshmem) {
+    if (blobType == BLOB_INPLACE) {
         ALOGV("readBlob: read in place");
         const void* ptr = readInplace(len);
         if (!ptr) return BAD_VALUE;
 
-        outBlob->init(false /*mapped*/, const_cast<void*>(ptr), len);
+        outBlob->init(-1, const_cast<void*>(ptr), len, false);
         return NO_ERROR;
     }
 
     ALOGV("readBlob: read from ashmem");
+    bool isMutable = (blobType == BLOB_ASHMEM_MUTABLE);
     int fd = readFileDescriptor();
     if (fd == int(BAD_TYPE)) return BAD_VALUE;
 
-    void* ptr = ::mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
+    void* ptr = ::mmap(NULL, len, isMutable ? PROT_READ | PROT_WRITE : PROT_READ,
+            MAP_SHARED, fd, 0);
     if (ptr == MAP_FAILED) return NO_MEMORY;
 
-    outBlob->init(true /*mapped*/, ptr, len);
+    outBlob->init(fd, ptr, len, isMutable);
     return NO_ERROR;
 }
 
@@ -1310,8 +1410,14 @@
     const size_t len = this->readInt32();
     const size_t fd_count = this->readInt32();
 
+    if (len > INT32_MAX) {
+        // don't accept size_t values which may have come from an
+        // inadvertent conversion from a negative int.
+        return BAD_VALUE;
+    }
+
     // payload
-    void const* const buf = this->readInplace(PAD_SIZE(len));
+    void const* const buf = this->readInplace(pad_size(len));
     if (buf == NULL)
         return BAD_VALUE;
 
@@ -1550,6 +1656,12 @@
 
 status_t Parcel::growData(size_t len)
 {
+    if (len > INT32_MAX) {
+        // don't accept size_t values which may have come from an
+        // inadvertent conversion from a negative int.
+        return BAD_VALUE;
+    }
+
     size_t newSize = ((mDataSize+len)*3)/2;
     return (newSize <= mDataSize)
             ? (status_t) NO_MEMORY
@@ -1558,6 +1670,12 @@
 
 status_t Parcel::restartWrite(size_t desired)
 {
+    if (desired > INT32_MAX) {
+        // don't accept size_t values which may have come from an
+        // inadvertent conversion from a negative int.
+        return BAD_VALUE;
+    }
+
     if (mOwner) {
         freeData();
         return continueWrite(desired);
@@ -1598,6 +1716,12 @@
 
 status_t Parcel::continueWrite(size_t desired)
 {
+    if (desired > INT32_MAX) {
+        // don't accept size_t values which may have come from an
+        // inadvertent conversion from a negative int.
+        return BAD_VALUE;
+    }
+
     // If shrinking, first adjust for any objects that appear
     // after the new data size.
     size_t objectsSize = mObjectsSize;
@@ -1630,7 +1754,7 @@
         binder_size_t* objects = NULL;
 
         if (objectsSize) {
-            objects = (binder_size_t*)malloc(objectsSize*sizeof(binder_size_t));
+            objects = (binder_size_t*)calloc(objectsSize, sizeof(binder_size_t));
             if (!objects) {
                 free(data);
 
@@ -1766,6 +1890,7 @@
     mFdsKnown = true;
     mAllowFds = true;
     mOwner = NULL;
+    mBlobAshmemSize = 0;
 }
 
 void Parcel::scanForFds() const
@@ -1783,10 +1908,15 @@
     mFdsKnown = true;
 }
 
+size_t Parcel::getBlobAshmemSize() const
+{
+    return mBlobAshmemSize;
+}
+
 // --- Parcel::Blob ---
 
 Parcel::Blob::Blob() :
-        mMapped(false), mData(NULL), mSize(0) {
+        mFd(-1), mData(NULL), mSize(0), mMutable(false) {
 }
 
 Parcel::Blob::~Blob() {
@@ -1794,22 +1924,24 @@
 }
 
 void Parcel::Blob::release() {
-    if (mMapped && mData) {
+    if (mFd != -1 && mData) {
         ::munmap(mData, mSize);
     }
     clear();
 }
 
-void Parcel::Blob::init(bool mapped, void* data, size_t size) {
-    mMapped = mapped;
+void Parcel::Blob::init(int fd, void* data, size_t size, bool isMutable) {
+    mFd = fd;
     mData = data;
     mSize = size;
+    mMutable = isMutable;
 }
 
 void Parcel::Blob::clear() {
-    mMapped = false;
+    mFd = -1;
     mData = NULL;
     mSize = 0;
+    mMutable = false;
 }
 
 }; // namespace android
diff --git a/libs/binder/ProcessInfoService.cpp b/libs/binder/ProcessInfoService.cpp
new file mode 100644
index 0000000..fb28643
--- /dev/null
+++ b/libs/binder/ProcessInfoService.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2015 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 <binder/ProcessInfoService.h>
+#include <binder/IServiceManager.h>
+
+#include <utils/Log.h>
+#include <utils/String16.h>
+
+namespace android {
+
+ProcessInfoService::ProcessInfoService() {
+    updateBinderLocked();
+}
+
+status_t ProcessInfoService::getProcessStatesImpl(size_t length, /*in*/ int32_t* pids,
+        /*out*/ int32_t* states) {
+    status_t err = NO_ERROR;
+    sp<IProcessInfoService> pis;
+    mProcessInfoLock.lock();
+    pis = mProcessInfoService;
+    mProcessInfoLock.unlock();
+
+    for (int i = 0; i < BINDER_ATTEMPT_LIMIT; i++) {
+
+        if (pis != NULL) {
+            err = pis->getProcessStatesFromPids(length, /*in*/ pids, /*out*/ states);
+            if (err == NO_ERROR) return NO_ERROR; // success
+            if (IInterface::asBinder(pis)->isBinderAlive()) return err;
+        }
+        sleep(1);
+
+        mProcessInfoLock.lock();
+        if (pis == mProcessInfoService) {
+            updateBinderLocked();
+        }
+        pis = mProcessInfoService;
+        mProcessInfoLock.unlock();
+    }
+
+    ALOGW("%s: Could not retrieve process states from ProcessInfoService after %d retries.",
+            __FUNCTION__, BINDER_ATTEMPT_LIMIT);
+
+    return TIMED_OUT;
+}
+
+void ProcessInfoService::updateBinderLocked() {
+    const sp<IServiceManager> sm(defaultServiceManager());
+    if (sm != NULL) {
+        const String16 name("processinfo");
+        mProcessInfoService = interface_cast<IProcessInfoService>(sm->checkService(name));
+    }
+}
+
+ANDROID_SINGLETON_STATIC_INSTANCE(ProcessInfoService);
+
+}; // namespace android
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 303d6cf..016d3c5 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -42,12 +42,13 @@
 #include <sys/stat.h>
 
 #define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2))
+#define DEFAULT_MAX_BINDER_THREADS 15
 
 
 // ---------------------------------------------------------------------------
 
 namespace android {
- 
+
 class PoolThread : public Thread
 {
 public:
@@ -294,7 +295,9 @@
 
 status_t ProcessState::setThreadPoolMaxThreadCount(size_t maxThreads) {
     status_t result = NO_ERROR;
-    if (ioctl(mDriverFD, BINDER_SET_MAX_THREADS, &maxThreads) == -1) {
+    if (ioctl(mDriverFD, BINDER_SET_MAX_THREADS, &maxThreads) != -1) {
+        mMaxThreads = maxThreads;
+    } else {
         result = -errno;
         ALOGE("Binder ioctl to set max threads failed: %s", strerror(-result));
     }
@@ -322,7 +325,7 @@
             close(fd);
             fd = -1;
         }
-        size_t maxThreads = 15;
+        size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
         result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
         if (result == -1) {
             ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
@@ -336,6 +339,10 @@
 ProcessState::ProcessState()
     : mDriverFD(open_driver())
     , mVMStart(MAP_FAILED)
+    , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
+    , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
+    , mExecutingThreadsCount(0)
+    , mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
     , mManagesContexts(false)
     , mBinderContextCheckFunc(NULL)
     , mBinderContextUserData(NULL)
diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp
index 5793d40..8f64ae0 100644
--- a/libs/gui/BufferItem.cpp
+++ b/libs/gui/BufferItem.cpp
@@ -46,15 +46,16 @@
 }
 
 size_t BufferItem::getPodSize() const {
-    // Must align<8> before writing these fields for this to be correct
     size_t size = 0;
     addAligned(size, mCrop);
     addAligned(size, mTransform);
     addAligned(size, mScalingMode);
-    addAligned(size, mTimestamp);
+    addAligned(size, mTimestampLo);
+    addAligned(size, mTimestampHi);
     addAligned(size, mIsAutoTimestamp);
     addAligned(size, mDataSpace);
-    addAligned(size, mFrameNumber);
+    addAligned(size, mFrameNumberLo);
+    addAligned(size, mFrameNumberHi);
     addAligned(size, mSlot);
     addAligned(size, mIsDroppable);
     addAligned(size, mAcquireCalled);
@@ -126,9 +127,6 @@
     if (err) return err;
     FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize());
 
-    // Must align<8> so that getPodSize returns the correct value
-    size -= FlattenableUtils::align<8>(buffer);
-
     // Check we still have enough space
     if (size < getPodSize()) {
         return NO_MEMORY;
@@ -137,10 +135,12 @@
     writeAligned(buffer, size, mCrop);
     writeAligned(buffer, size, mTransform);
     writeAligned(buffer, size, mScalingMode);
-    writeAligned(buffer, size, mTimestamp);
+    writeAligned(buffer, size, mTimestampLo);
+    writeAligned(buffer, size, mTimestampHi);
     writeAligned(buffer, size, mIsAutoTimestamp);
     writeAligned(buffer, size, mDataSpace);
-    writeAligned(buffer, size, mFrameNumber);
+    writeAligned(buffer, size, mFrameNumberLo);
+    writeAligned(buffer, size, mFrameNumberHi);
     writeAligned(buffer, size, mSlot);
     writeAligned(buffer, size, mIsDroppable);
     writeAligned(buffer, size, mAcquireCalled);
@@ -183,9 +183,6 @@
     if (err) return err;
     FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize());
 
-    // Must align<8> so that getPodSize returns the correct value
-    size -= FlattenableUtils::align<8>(buffer);
-
     // Check we still have enough space
     if (size < getPodSize()) {
         return NO_MEMORY;
@@ -194,10 +191,12 @@
     readAligned(buffer, size, mCrop);
     readAligned(buffer, size, mTransform);
     readAligned(buffer, size, mScalingMode);
-    readAligned(buffer, size, mTimestamp);
+    readAligned(buffer, size, mTimestampLo);
+    readAligned(buffer, size, mTimestampHi);
     readAligned(buffer, size, mIsAutoTimestamp);
     readAligned(buffer, size, mDataSpace);
-    readAligned(buffer, size, mFrameNumber);
+    readAligned(buffer, size, mFrameNumberLo);
+    readAligned(buffer, size, mFrameNumberHi);
     readAligned(buffer, size, mSlot);
     readAligned(buffer, size, mIsDroppable);
     readAligned(buffer, size, mAcquireCalled);
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index 194121f..578b8d9 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -100,20 +100,4 @@
     return err;
 }
 
-status_t BufferItemConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) {
-    Mutex::Autolock _l(mMutex);
-    return mConsumer->setDefaultBufferSize(w, h);
-}
-
-status_t BufferItemConsumer::setDefaultBufferFormat(PixelFormat defaultFormat) {
-    Mutex::Autolock _l(mMutex);
-    return mConsumer->setDefaultBufferFormat(defaultFormat);
-}
-
-status_t BufferItemConsumer::setDefaultBufferDataSpace(
-        android_dataspace defaultDataSpace) {
-    Mutex::Autolock _l(mMutex);
-    return mConsumer->setDefaultBufferDataSpace(defaultDataSpace);
-}
-
 } // namespace android
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 2fcbaf2..ccbb5a2 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -39,6 +39,14 @@
     }
 }
 
+void BufferQueue::ProxyConsumerListener::onFrameReplaced(
+        const BufferItem& item) {
+    sp<ConsumerListener> listener(mConsumerListener.promote());
+    if (listener != NULL) {
+        listener->onFrameReplaced(item);
+    }
+}
+
 void BufferQueue::ProxyConsumerListener::onBuffersReleased() {
     sp<ConsumerListener> listener(mConsumerListener.promote());
     if (listener != NULL) {
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index c7d5e00..bb3e1b0 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -36,146 +36,171 @@
 BufferQueueConsumer::~BufferQueueConsumer() {}
 
 status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
-        nsecs_t expectedPresent) {
+        nsecs_t expectedPresent, uint64_t maxFrameNumber) {
     ATRACE_CALL();
-    Mutex::Autolock lock(mCore->mMutex);
 
-    // Check that the consumer doesn't currently have the maximum number of
-    // buffers acquired. We allow the max buffer count to be exceeded by one
-    // buffer so that the consumer can successfully set up the newly acquired
-    // buffer before releasing the old one.
-    int numAcquiredBuffers = 0;
-    for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
-        if (mSlots[s].mBufferState == BufferSlot::ACQUIRED) {
-            ++numAcquiredBuffers;
+    int numDroppedBuffers = 0;
+    sp<IProducerListener> listener;
+    {
+        Mutex::Autolock lock(mCore->mMutex);
+
+        // Check that the consumer doesn't currently have the maximum number of
+        // buffers acquired. We allow the max buffer count to be exceeded by one
+        // buffer so that the consumer can successfully set up the newly acquired
+        // buffer before releasing the old one.
+        int numAcquiredBuffers = 0;
+        for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
+            if (mSlots[s].mBufferState == BufferSlot::ACQUIRED) {
+                ++numAcquiredBuffers;
+            }
         }
-    }
-    if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) {
-        BQ_LOGE("acquireBuffer: max acquired buffer count reached: %d (max %d)",
-                numAcquiredBuffers, mCore->mMaxAcquiredBufferCount);
-        return INVALID_OPERATION;
-    }
+        if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) {
+            BQ_LOGE("acquireBuffer: max acquired buffer count reached: %d (max %d)",
+                    numAcquiredBuffers, mCore->mMaxAcquiredBufferCount);
+            return INVALID_OPERATION;
+        }
 
-    // Check if the queue is empty.
-    // In asynchronous mode the list is guaranteed to be one buffer deep,
-    // while in synchronous mode we use the oldest buffer.
-    if (mCore->mQueue.empty()) {
-        return NO_BUFFER_AVAILABLE;
-    }
+        // Check if the queue is empty.
+        // In asynchronous mode the list is guaranteed to be one buffer deep,
+        // while in synchronous mode we use the oldest buffer.
+        if (mCore->mQueue.empty()) {
+            return NO_BUFFER_AVAILABLE;
+        }
 
-    BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin());
+        BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin());
 
-    // If expectedPresent is specified, we may not want to return a buffer yet.
-    // If it's specified and there's more than one buffer queued, we may want
-    // to drop a buffer.
-    if (expectedPresent != 0) {
-        const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second
+        // If expectedPresent is specified, we may not want to return a buffer yet.
+        // If it's specified and there's more than one buffer queued, we may want
+        // to drop a buffer.
+        if (expectedPresent != 0) {
+            const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second
 
-        // The 'expectedPresent' argument indicates when the buffer is expected
-        // to be presented on-screen. If the buffer's desired present time is
-        // earlier (less) than expectedPresent -- meaning it will be displayed
-        // on time or possibly late if we show it as soon as possible -- we
-        // acquire and return it. If we don't want to display it until after the
-        // expectedPresent time, we return PRESENT_LATER without acquiring it.
-        //
-        // To be safe, we don't defer acquisition if expectedPresent is more
-        // than one second in the future beyond the desired present time
-        // (i.e., we'd be holding the buffer for a long time).
-        //
-        // NOTE: Code assumes monotonic time values from the system clock
-        // are positive.
-
-        // Start by checking to see if we can drop frames. We skip this check if
-        // the timestamps are being auto-generated by Surface. If the app isn't
-        // generating timestamps explicitly, it probably doesn't want frames to
-        // be discarded based on them.
-        while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) {
-            // If entry[1] is timely, drop entry[0] (and repeat). We apply an
-            // additional criterion here: we only drop the earlier buffer if our
-            // desiredPresent falls within +/- 1 second of the expected present.
-            // Otherwise, bogus desiredPresent times (e.g., 0 or a small
-            // relative timestamp), which normally mean "ignore the timestamp
-            // and acquire immediately", would cause us to drop frames.
+            // The 'expectedPresent' argument indicates when the buffer is expected
+            // to be presented on-screen. If the buffer's desired present time is
+            // earlier (less) than expectedPresent -- meaning it will be displayed
+            // on time or possibly late if we show it as soon as possible -- we
+            // acquire and return it. If we don't want to display it until after the
+            // expectedPresent time, we return PRESENT_LATER without acquiring it.
             //
-            // We may want to add an additional criterion: don't drop the
-            // earlier buffer if entry[1]'s fence hasn't signaled yet.
-            const BufferItem& bufferItem(mCore->mQueue[1]);
-            nsecs_t desiredPresent = bufferItem.mTimestamp;
-            if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC ||
-                    desiredPresent > expectedPresent) {
-                // This buffer is set to display in the near future, or
-                // desiredPresent is garbage. Either way we don't want to drop
-                // the previous buffer just to get this on the screen sooner.
-                BQ_LOGV("acquireBuffer: nodrop desire=%" PRId64 " expect=%"
-                        PRId64 " (%" PRId64 ") now=%" PRId64,
+            // To be safe, we don't defer acquisition if expectedPresent is more
+            // than one second in the future beyond the desired present time
+            // (i.e., we'd be holding the buffer for a long time).
+            //
+            // NOTE: Code assumes monotonic time values from the system clock
+            // are positive.
+
+            // Start by checking to see if we can drop frames. We skip this check if
+            // the timestamps are being auto-generated by Surface. If the app isn't
+            // generating timestamps explicitly, it probably doesn't want frames to
+            // be discarded based on them.
+            while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) {
+                const BufferItem& bufferItem(mCore->mQueue[1]);
+
+                // If dropping entry[0] would leave us with a buffer that the
+                // consumer is not yet ready for, don't drop it.
+                if (maxFrameNumber && bufferItem.mFrameNumber > maxFrameNumber) {
+                    break;
+                }
+
+                // If entry[1] is timely, drop entry[0] (and repeat). We apply an
+                // additional criterion here: we only drop the earlier buffer if our
+                // desiredPresent falls within +/- 1 second of the expected present.
+                // Otherwise, bogus desiredPresent times (e.g., 0 or a small
+                // relative timestamp), which normally mean "ignore the timestamp
+                // and acquire immediately", would cause us to drop frames.
+                //
+                // We may want to add an additional criterion: don't drop the
+                // earlier buffer if entry[1]'s fence hasn't signaled yet.
+                nsecs_t desiredPresent = bufferItem.mTimestamp;
+                if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC ||
+                        desiredPresent > expectedPresent) {
+                    // This buffer is set to display in the near future, or
+                    // desiredPresent is garbage. Either way we don't want to drop
+                    // the previous buffer just to get this on the screen sooner.
+                    BQ_LOGV("acquireBuffer: nodrop desire=%" PRId64 " expect=%"
+                            PRId64 " (%" PRId64 ") now=%" PRId64,
+                            desiredPresent, expectedPresent,
+                            desiredPresent - expectedPresent,
+                            systemTime(CLOCK_MONOTONIC));
+                    break;
+                }
+
+                BQ_LOGV("acquireBuffer: drop desire=%" PRId64 " expect=%" PRId64
+                        " size=%zu",
+                        desiredPresent, expectedPresent, mCore->mQueue.size());
+                if (mCore->stillTracking(front)) {
+                    // Front buffer is still in mSlots, so mark the slot as free
+                    mSlots[front->mSlot].mBufferState = BufferSlot::FREE;
+                    mCore->mFreeBuffers.push_back(front->mSlot);
+                    listener = mCore->mConnectedProducerListener;
+                    ++numDroppedBuffers;
+                }
+                mCore->mQueue.erase(front);
+                front = mCore->mQueue.begin();
+            }
+
+            // See if the front buffer is ready to be acquired
+            nsecs_t desiredPresent = front->mTimestamp;
+            bool bufferIsDue = desiredPresent <= expectedPresent ||
+                    desiredPresent > expectedPresent + MAX_REASONABLE_NSEC;
+            bool consumerIsReady = maxFrameNumber > 0 ?
+                    front->mFrameNumber <= maxFrameNumber : true;
+            if (!bufferIsDue || !consumerIsReady) {
+                BQ_LOGV("acquireBuffer: defer desire=%" PRId64 " expect=%" PRId64
+                        " (%" PRId64 ") now=%" PRId64 " frame=%" PRIu64
+                        " consumer=%" PRIu64,
                         desiredPresent, expectedPresent,
                         desiredPresent - expectedPresent,
-                        systemTime(CLOCK_MONOTONIC));
-                break;
+                        systemTime(CLOCK_MONOTONIC),
+                        front->mFrameNumber, maxFrameNumber);
+                return PRESENT_LATER;
             }
 
-            BQ_LOGV("acquireBuffer: drop desire=%" PRId64 " expect=%" PRId64
-                    " size=%zu",
-                    desiredPresent, expectedPresent, mCore->mQueue.size());
-            if (mCore->stillTracking(front)) {
-                // Front buffer is still in mSlots, so mark the slot as free
-                mSlots[front->mSlot].mBufferState = BufferSlot::FREE;
-                mCore->mFreeBuffers.push_back(front->mSlot);
-            }
-            mCore->mQueue.erase(front);
-            front = mCore->mQueue.begin();
-        }
-
-        // See if the front buffer is due
-        nsecs_t desiredPresent = front->mTimestamp;
-        if (desiredPresent > expectedPresent &&
-                desiredPresent < expectedPresent + MAX_REASONABLE_NSEC) {
-            BQ_LOGV("acquireBuffer: defer desire=%" PRId64 " expect=%" PRId64
-                    " (%" PRId64 ") now=%" PRId64,
-                    desiredPresent, expectedPresent,
+            BQ_LOGV("acquireBuffer: accept desire=%" PRId64 " expect=%" PRId64 " "
+                    "(%" PRId64 ") now=%" PRId64, desiredPresent, expectedPresent,
                     desiredPresent - expectedPresent,
                     systemTime(CLOCK_MONOTONIC));
-            return PRESENT_LATER;
         }
 
-        BQ_LOGV("acquireBuffer: accept desire=%" PRId64 " expect=%" PRId64 " "
-                "(%" PRId64 ") now=%" PRId64, desiredPresent, expectedPresent,
-                desiredPresent - expectedPresent,
-                systemTime(CLOCK_MONOTONIC));
+        int slot = front->mSlot;
+        *outBuffer = *front;
+        ATRACE_BUFFER_INDEX(slot);
+
+        BQ_LOGV("acquireBuffer: acquiring { slot=%d/%" PRIu64 " buffer=%p }",
+                slot, front->mFrameNumber, front->mGraphicBuffer->handle);
+        // If the front buffer is still being tracked, update its slot state
+        if (mCore->stillTracking(front)) {
+            mSlots[slot].mAcquireCalled = true;
+            mSlots[slot].mNeedsCleanupOnRelease = false;
+            mSlots[slot].mBufferState = BufferSlot::ACQUIRED;
+            mSlots[slot].mFence = Fence::NO_FENCE;
+        }
+
+        // If the buffer has previously been acquired by the consumer, set
+        // mGraphicBuffer to NULL to avoid unnecessarily remapping this buffer
+        // on the consumer side
+        if (outBuffer->mAcquireCalled) {
+            outBuffer->mGraphicBuffer = NULL;
+        }
+
+        mCore->mQueue.erase(front);
+
+        // We might have freed a slot while dropping old buffers, or the producer
+        // may be blocked waiting for the number of buffers in the queue to
+        // decrease.
+        mCore->mDequeueCondition.broadcast();
+
+        ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size());
+
+        mCore->validateConsistencyLocked();
     }
 
-    int slot = front->mSlot;
-    *outBuffer = *front;
-    ATRACE_BUFFER_INDEX(slot);
-
-    BQ_LOGV("acquireBuffer: acquiring { slot=%d/%" PRIu64 " buffer=%p }",
-            slot, front->mFrameNumber, front->mGraphicBuffer->handle);
-    // If the front buffer is still being tracked, update its slot state
-    if (mCore->stillTracking(front)) {
-        mSlots[slot].mAcquireCalled = true;
-        mSlots[slot].mNeedsCleanupOnRelease = false;
-        mSlots[slot].mBufferState = BufferSlot::ACQUIRED;
-        mSlots[slot].mFence = Fence::NO_FENCE;
+    if (listener != NULL) {
+        for (int i = 0; i < numDroppedBuffers; ++i) {
+            listener->onBufferReleased();
+        }
     }
 
-    // If the buffer has previously been acquired by the consumer, set
-    // mGraphicBuffer to NULL to avoid unnecessarily remapping this buffer
-    // on the consumer side
-    if (outBuffer->mAcquireCalled) {
-        outBuffer->mGraphicBuffer = NULL;
-    }
-
-    mCore->mQueue.erase(front);
-
-    // We might have freed a slot while dropping old buffers, or the producer
-    // may be blocked waiting for the number of buffers in the queue to
-    // decrease.
-    mCore->mDequeueCondition.broadcast();
-
-    ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size());
-
-    mCore->validateConsistencyLocked();
-
     return NO_ERROR;
 }
 
@@ -236,6 +261,13 @@
         return INVALID_OPERATION;
     }
 
+    if (buffer->getGenerationNumber() != mCore->mGenerationNumber) {
+        BQ_LOGE("attachBuffer: generation number mismatch [buffer %u] "
+                "[queue %u]", buffer->getGenerationNumber(),
+                mCore->mGenerationNumber);
+        return BAD_VALUE;
+    }
+
     // Find a free slot to put the buffer into
     int found = BufferQueueCore::INVALID_BUFFER_SLOT;
     if (!mCore->mFreeSlots.empty()) {
@@ -292,6 +324,8 @@
 
     if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS ||
             releaseFence == NULL) {
+        BQ_LOGE("releaseBuffer: slot %d out of range or fence %p NULL", slot,
+                releaseFence.get());
         return BAD_VALUE;
     }
 
@@ -330,7 +364,7 @@
             mSlots[slot].mNeedsCleanupOnRelease = false;
             return STALE_BUFFER_SLOT;
         } else {
-            BQ_LOGV("releaseBuffer: attempted to release buffer slot %d "
+            BQ_LOGE("releaseBuffer: attempted to release buffer slot %d "
                     "but its state was %d", slot, mSlots[slot].mBufferState);
             return BAD_VALUE;
         }
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index bc75ca7..851a396 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -70,7 +70,9 @@
     mTransformHint(0),
     mIsAllocating(false),
     mIsAllocatingCondition(),
-    mAllowAllocation(true)
+    mAllowAllocation(true),
+    mBufferAge(0),
+    mGenerationNumber(0)
 {
     if (allocator == NULL) {
         sp<ISurfaceComposer> composer(ComposerService::getComposerService());
@@ -211,6 +213,7 @@
     }
     mSlots[slot].mBufferState = BufferSlot::FREE;
     mSlots[slot].mAcquireCalled = false;
+    mSlots[slot].mFrameNumber = 0;
 
     // Destroy fence as BufferQueue now takes ownership
     if (mSlots[slot].mEglFence != EGL_NO_SYNC_KHR) {
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 86e45c8..87e5b4d 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -337,10 +337,19 @@
             mSlots[found].mEglDisplay = EGL_NO_DISPLAY;
             mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
             mSlots[found].mFence = Fence::NO_FENCE;
+            mCore->mBufferAge = 0;
 
             returnFlags |= BUFFER_NEEDS_REALLOCATION;
+        } else {
+            // We add 1 because that will be the frame number when this buffer
+            // is queued
+            mCore->mBufferAge =
+                    mCore->mFrameCounter + 1 - mSlots[found].mFrameNumber;
         }
 
+        BQ_LOGV("dequeueBuffer: setting buffer age to %" PRIu64,
+                mCore->mBufferAge);
+
         if (CC_UNLIKELY(mSlots[found].mFence == NULL)) {
             BQ_LOGE("dequeueBuffer: about to return a NULL fence - "
                     "slot=%d w=%d h=%d format=%u",
@@ -374,6 +383,7 @@
                 return NO_INIT;
             }
 
+            graphicBuffer->setGenerationNumber(mCore->mGenerationNumber);
             mSlots[*outSlot].mGraphicBuffer = graphicBuffer;
         } // Autolock scope
     }
@@ -489,6 +499,13 @@
     Mutex::Autolock lock(mCore->mMutex);
     mCore->waitWhileAllocatingLocked();
 
+    if (buffer->getGenerationNumber() != mCore->mGenerationNumber) {
+        BQ_LOGE("attachBuffer: generation number mismatch [buffer %u] "
+                "[queue %u]", buffer->getGenerationNumber(),
+                mCore->mGenerationNumber);
+        return BAD_VALUE;
+    }
+
     status_t returnFlags = NO_ERROR;
     int found;
     // TODO: Should we provide an async flag to attachBuffer? It seems
@@ -784,6 +801,13 @@
         case NATIVE_WINDOW_DEFAULT_DATASPACE:
             value = static_cast<int32_t>(mCore->mDefaultBufferDataSpace);
             break;
+        case NATIVE_WINDOW_BUFFER_AGE:
+            if (mCore->mBufferAge > INT32_MAX) {
+                value = 0;
+            } else {
+                value = static_cast<int32_t>(mCore->mBufferAge);
+            }
+            break;
         default:
             return BAD_VALUE;
     }
@@ -855,6 +879,7 @@
     mCore->mBufferHasBeenQueued = false;
     mCore->mDequeueBufferCannotBlock =
             mCore->mConsumerControlledByApp && producerControlledByApp;
+    mCore->mAllowAllocation = true;
 
     return status;
 }
@@ -897,8 +922,8 @@
                     mCore->mSidebandStream.clear();
                     mCore->mDequeueCondition.broadcast();
                     listener = mCore->mConsumerListener;
-                } else {
-                    BQ_LOGE("disconnect(P): connected to another API "
+                } else if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
+                    BQ_LOGE("disconnect(P): still connected to another API "
                             "(cur=%d req=%d)", mCore->mConnectedApi, api);
                     status = BAD_VALUE;
                 }
@@ -1055,6 +1080,21 @@
     return NO_ERROR;
 }
 
+status_t BufferQueueProducer::setGenerationNumber(uint32_t generationNumber) {
+    ATRACE_CALL();
+    BQ_LOGV("setGenerationNumber: %u", generationNumber);
+
+    Mutex::Autolock lock(mCore->mMutex);
+    mCore->mGenerationNumber = generationNumber;
+    return NO_ERROR;
+}
+
+String8 BufferQueueProducer::getConsumerName() const {
+    ATRACE_CALL();
+    BQ_LOGV("getConsumerName: %s", mConsumerName.string());
+    return mConsumerName;
+}
+
 void BufferQueueProducer::binderDied(const wp<android::IBinder>& /* who */) {
     // If we're here, it means that a producer we were connected to died.
     // We're guaranteed that we are still connected to it because we remove
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index e576018..04ab06b 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -114,6 +114,21 @@
     }
 }
 
+void ConsumerBase::onFrameReplaced(const BufferItem &item) {
+    CB_LOGV("onFrameReplaced");
+
+    sp<FrameAvailableListener> listener;
+    {
+        Mutex::Autolock lock(mMutex);
+        listener = mFrameAvailableListener.promote();
+    }
+
+    if (listener != NULL) {
+        CB_LOGV("actually calling onFrameReplaced");
+        listener->onFrameReplaced(item);
+    }
+}
+
 void ConsumerBase::onBuffersReleased() {
     Mutex::Autolock lock(mMutex);
 
@@ -156,6 +171,11 @@
     mConsumer.clear();
 }
 
+bool ConsumerBase::isAbandoned() {
+    Mutex::Autolock _l(mMutex);
+    return mAbandoned;
+}
+
 void ConsumerBase::setFrameAvailableListener(
         const wp<FrameAvailableListener>& listener) {
     CB_LOGV("setFrameAvailableListener");
@@ -178,6 +198,22 @@
     return result;
 }
 
+status_t ConsumerBase::setDefaultBufferSize(uint32_t width, uint32_t height) {
+    Mutex::Autolock _l(mMutex);
+    return mConsumer->setDefaultBufferSize(width, height);
+}
+
+status_t ConsumerBase::setDefaultBufferFormat(PixelFormat defaultFormat) {
+    Mutex::Autolock _l(mMutex);
+    return mConsumer->setDefaultBufferFormat(defaultFormat);
+}
+
+status_t ConsumerBase::setDefaultBufferDataSpace(
+        android_dataspace defaultDataSpace) {
+    Mutex::Autolock _l(mMutex);
+    return mConsumer->setDefaultBufferDataSpace(defaultDataSpace);
+}
+
 void ConsumerBase::dump(String8& result) const {
     dump(result, "");
 }
@@ -196,8 +232,8 @@
 }
 
 status_t ConsumerBase::acquireBufferLocked(BufferItem *item,
-        nsecs_t presentWhen) {
-    status_t err = mConsumer->acquireBuffer(item, presentWhen);
+        nsecs_t presentWhen, uint64_t maxFrameNumber) {
+    status_t err = mConsumer->acquireBuffer(item, presentWhen, maxFrameNumber);
     if (err != NO_ERROR) {
         return err;
     }
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index eb39469..e29b740 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -56,25 +56,6 @@
     mConsumer->setConsumerName(name);
 }
 
-status_t CpuConsumer::setDefaultBufferSize(uint32_t width, uint32_t height)
-{
-    Mutex::Autolock _l(mMutex);
-    return mConsumer->setDefaultBufferSize(width, height);
-}
-
-status_t CpuConsumer::setDefaultBufferFormat(PixelFormat defaultFormat)
-{
-    Mutex::Autolock _l(mMutex);
-    return mConsumer->setDefaultBufferFormat(defaultFormat);
-}
-
-status_t CpuConsumer::setDefaultBufferDataSpace(
-        android_dataspace defaultDataSpace)
-{
-    Mutex::Autolock _l(mMutex);
-    return mConsumer->setDefaultBufferDataSpace(defaultDataSpace);
-}
-
 static bool isPossiblyYUV(PixelFormat format) {
     switch (static_cast<int>(format)) {
         case HAL_PIXEL_FORMAT_RGBA_8888:
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 96c0841..757e08a 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -344,8 +344,9 @@
 }
 
 status_t GLConsumer::acquireBufferLocked(BufferItem *item,
-        nsecs_t presentWhen) {
-    status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen);
+        nsecs_t presentWhen, uint64_t maxFrameNumber) {
+    status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen,
+            maxFrameNumber);
     if (err != NO_ERROR) {
         return err;
     }
@@ -900,14 +901,18 @@
 
         // The crop is too wide
         if (newWidth < currentWidth) {
-            uint32_t dw = (currentWidth - newWidth) / 2;
-            outCrop.left += dw;
-            outCrop.right -= dw;
+            uint32_t dw = currentWidth - newWidth;
+            auto halfdw = dw / 2;
+            outCrop.left += halfdw;
+            // Not halfdw because it would subtract 1 too few when dw is odd
+            outCrop.right -= (dw - halfdw);
         // The crop is too tall
         } else if (newHeight < currentHeight) {
-            uint32_t dh = (currentHeight - newHeight) / 2;
-            outCrop.top += dh;
-            outCrop.bottom -= dh;
+            uint32_t dh = currentHeight - newHeight;
+            auto halfdh = dh / 2;
+            outCrop.top += halfdh;
+            // Not halfdh because it would subtract 1 too few when dh is odd
+            outCrop.bottom -= (dh - halfdh);
         }
 
         GLC_LOGV("getCurrentCrop final crop [%d,%d,%d,%d]",
diff --git a/libs/gui/IGraphicBufferAlloc.cpp b/libs/gui/IGraphicBufferAlloc.cpp
index 09b63a1..3009989 100644
--- a/libs/gui/IGraphicBufferAlloc.cpp
+++ b/libs/gui/IGraphicBufferAlloc.cpp
@@ -59,6 +59,9 @@
         if (result == NO_ERROR) {
             graphicBuffer = new GraphicBuffer();
             result = reply.read(*graphicBuffer);
+            if (result != NO_ERROR) {
+                graphicBuffer.clear();
+            }
             // reply.readStrongBinder();
             // here we don't even have to read the BufferReference from
             // the parcel, it'll die with the parcel.
diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp
index 3f23c2f..b86f4c5 100644
--- a/libs/gui/IGraphicBufferConsumer.cpp
+++ b/libs/gui/IGraphicBufferConsumer.cpp
@@ -66,10 +66,12 @@
 
     virtual ~BpGraphicBufferConsumer();
 
-    virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen) {
+    virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen,
+            uint64_t maxFrameNumber) {
         Parcel data, reply;
         data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
         data.writeInt64(presentWhen);
+        data.writeUint64(maxFrameNumber);
         status_t result = remote()->transact(ACQUIRE_BUFFER, data, &reply);
         if (result != NO_ERROR) {
             return result;
@@ -295,7 +297,8 @@
             CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
             BufferItem item;
             int64_t presentWhen = data.readInt64();
-            status_t result = acquireBuffer(&item, presentWhen);
+            uint64_t maxFrameNumber = data.readUint64();
+            status_t result = acquireBuffer(&item, presentWhen, maxFrameNumber);
             status_t err = reply->write(item);
             if (err) return err;
             reply->writeInt32(result);
@@ -414,6 +417,15 @@
             reply->writeInt32(result);
             return NO_ERROR;
         }
+        case GET_SIDEBAND_STREAM: {
+            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
+            sp<NativeHandle> stream = getSidebandStream();
+            reply->writeInt32(static_cast<int32_t>(stream != NULL));
+            if (stream != NULL) {
+                reply->writeNativeHandle(stream->handle());
+            }
+            return NO_ERROR;
+        }
         case DUMP: {
             CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
             String8 result = data.readString8();
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 74a40ee..8bdbc22 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -47,6 +47,8 @@
     SET_SIDEBAND_STREAM,
     ALLOCATE_BUFFERS,
     ALLOW_ALLOCATION,
+    SET_GENERATION_NUMBER,
+    GET_CONSUMER_NAME,
 };
 
 class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -284,6 +286,28 @@
         result = reply.readInt32();
         return result;
     }
+
+    virtual status_t setGenerationNumber(uint32_t generationNumber) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
+        data.writeUint32(generationNumber);
+        status_t result = remote()->transact(SET_GENERATION_NUMBER, data, &reply);
+        if (result == NO_ERROR) {
+            result = reply.readInt32();
+        }
+        return result;
+    }
+
+    virtual String8 getConsumerName() const {
+        Parcel data, reply;
+        data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
+        status_t result = remote()->transact(GET_CONSUMER_NAME, data, &reply);
+        if (result != NO_ERROR) {
+            ALOGE("getConsumerName failed to transact: %d", result);
+            return String8("TransactFailed");
+        }
+        return reply.readString8();
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -448,6 +472,18 @@
             reply->writeInt32(result);
             return NO_ERROR;
         }
+        case SET_GENERATION_NUMBER: {
+            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
+            uint32_t generationNumber = data.readUint32();
+            status_t result = setGenerationNumber(generationNumber);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        }
+        case GET_CONSUMER_NAME: {
+            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
+            reply->writeString8(getConsumerName());
+            return NO_ERROR;
+        }
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
diff --git a/libs/gui/ISensorServer.cpp b/libs/gui/ISensorServer.cpp
index 8e09e7c..f581b5c 100644
--- a/libs/gui/ISensorServer.cpp
+++ b/libs/gui/ISensorServer.cpp
@@ -35,6 +35,7 @@
 enum {
     GET_SENSOR_LIST = IBinder::FIRST_CALL_TRANSACTION,
     CREATE_SENSOR_EVENT_CONNECTION,
+    ENABLE_DATA_INJECTION
 };
 
 class BpSensorServer : public BpInterface<ISensorServer>
@@ -47,10 +48,11 @@
 
     virtual ~BpSensorServer();
 
-    virtual Vector<Sensor> getSensorList()
+    virtual Vector<Sensor> getSensorList(const String16& opPackageName)
     {
         Parcel data, reply;
         data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor());
+        data.writeString16(opPackageName);
         remote()->transact(GET_SENSOR_LIST, data, &reply);
         Sensor s;
         Vector<Sensor> v;
@@ -63,13 +65,24 @@
         return v;
     }
 
-    virtual sp<ISensorEventConnection> createSensorEventConnection()
+    virtual sp<ISensorEventConnection> createSensorEventConnection(const String8& packageName,
+             int mode, const String16& opPackageName)
     {
         Parcel data, reply;
         data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor());
+        data.writeString8(packageName);
+        data.writeInt32(mode);
+        data.writeString16(opPackageName);
         remote()->transact(CREATE_SENSOR_EVENT_CONNECTION, data, &reply);
         return interface_cast<ISensorEventConnection>(reply.readStrongBinder());
     }
+
+    virtual int isDataInjectionEnabled() {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor());
+        remote()->transact(ENABLE_DATA_INJECTION, data, &reply);
+        return reply.readInt32();
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -86,7 +99,8 @@
     switch(code) {
         case GET_SENSOR_LIST: {
             CHECK_INTERFACE(ISensorServer, data, reply);
-            Vector<Sensor> v(getSensorList());
+            const String16& opPackageName = data.readString16();
+            Vector<Sensor> v(getSensorList(opPackageName));
             size_t n = v.size();
             reply->writeUint32(static_cast<uint32_t>(n));
             for (size_t i = 0; i < n; i++) {
@@ -96,10 +110,20 @@
         }
         case CREATE_SENSOR_EVENT_CONNECTION: {
             CHECK_INTERFACE(ISensorServer, data, reply);
-            sp<ISensorEventConnection> connection(createSensorEventConnection());
+            String8 packageName = data.readString8();
+            int32_t mode = data.readInt32();
+            const String16& opPackageName = data.readString16();
+            sp<ISensorEventConnection> connection(createSensorEventConnection(packageName, mode,
+                    opPackageName));
             reply->writeStrongBinder(IInterface::asBinder(connection));
             return NO_ERROR;
         }
+        case ENABLE_DATA_INJECTION: {
+            CHECK_INTERFACE(ISensorServer, data, reply);
+            int32_t ret = isDataInjectionEnabled();
+            reply->writeInt32(static_cast<int32_t>(ret));
+            return NO_ERROR;
+        }
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp
index 35661f2..4b3603e 100644
--- a/libs/gui/Sensor.cpp
+++ b/libs/gui/Sensor.cpp
@@ -25,6 +25,9 @@
 
 #include <hardware/sensors.h>
 
+#include <binder/AppOpsManager.h>
+#include <binder/IServiceManager.h>
+
 #include <gui/Sensor.h>
 #include <log/log.h>
 
@@ -113,11 +116,13 @@
         mStringType = SENSOR_STRING_TYPE_GYROSCOPE_UNCALIBRATED;
         mFlags |= SENSOR_FLAG_CONTINUOUS_MODE;
         break;
-    case SENSOR_TYPE_HEART_RATE:
+    case SENSOR_TYPE_HEART_RATE: {
         mStringType = SENSOR_STRING_TYPE_HEART_RATE;
         mRequiredPermission = SENSOR_PERMISSION_BODY_SENSORS;
+        AppOpsManager appOps;
+        mRequiredAppOp = appOps.permissionToOpCode(String16(SENSOR_PERMISSION_BODY_SENSORS));
         mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
-        break;
+        } break;
     case SENSOR_TYPE_LIGHT:
         mStringType = SENSOR_STRING_TYPE_LIGHT;
         mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
@@ -218,6 +223,10 @@
         }
         if (halVersion > SENSORS_DEVICE_API_VERSION_1_0 && hwSensor->requiredPermission) {
             mRequiredPermission = hwSensor->requiredPermission;
+            if (!strcmp(mRequiredPermission, SENSOR_PERMISSION_BODY_SENSORS)) {
+                AppOpsManager appOps;
+                mRequiredAppOp = appOps.permissionToOpCode(String16(SENSOR_PERMISSION_BODY_SENSORS));
+            }
         }
 
         if (halVersion >= SENSORS_DEVICE_API_VERSION_1_3) {
@@ -252,6 +261,17 @@
 
         }
     }
+
+    if (mRequiredPermission.length() > 0) {
+        // If the sensor is protected by a permission we need to know if it is
+        // a runtime one to determine whether we can use the permission cache.
+        sp<IBinder> binder = defaultServiceManager()->getService(String16("permission"));
+        if (binder != 0) {
+            sp<IPermissionController> permCtrl = interface_cast<IPermissionController>(binder);
+            mRequiredPermissionRuntime = permCtrl->isRuntimePermission(
+                    String16(mRequiredPermission));
+        }
+    }
 }
 
 Sensor::~Sensor()
@@ -318,6 +338,14 @@
     return mRequiredPermission;
 }
 
+bool Sensor::isRequiredPermissionRuntime() const {
+    return mRequiredPermissionRuntime;
+}
+
+int32_t Sensor::getRequiredAppOp() const {
+    return mRequiredAppOp;
+}
+
 int32_t Sensor::getMaxDelay() const {
     return mMaxDelay;
 }
@@ -339,7 +367,8 @@
     size_t fixedSize =
             sizeof(int32_t) * 3 +
             sizeof(float) * 4 +
-            sizeof(int32_t) * 5;
+            sizeof(int32_t) * 6 +
+            sizeof(bool);
 
     size_t variableSize =
             sizeof(uint32_t) + FlattenableUtils::align<4>(mName.length()) +
@@ -369,6 +398,8 @@
     FlattenableUtils::write(buffer, size, mFifoMaxEventCount);
     flattenString8(buffer, size, mStringType);
     flattenString8(buffer, size, mRequiredPermission);
+    FlattenableUtils::write(buffer, size, mRequiredPermissionRuntime);
+    FlattenableUtils::write(buffer, size, mRequiredAppOp);
     FlattenableUtils::write(buffer, size, mMaxDelay);
     FlattenableUtils::write(buffer, size, mFlags);
     return NO_ERROR;
@@ -407,6 +438,8 @@
     if (!unflattenString8(buffer, size, mRequiredPermission)) {
         return NO_MEMORY;
     }
+    FlattenableUtils::read(buffer, size, mRequiredPermissionRuntime);
+    FlattenableUtils::read(buffer, size, mRequiredAppOp);
     FlattenableUtils::read(buffer, size, mMaxDelay);
     FlattenableUtils::read(buffer, size, mFlags);
     return NO_ERROR;
diff --git a/libs/gui/SensorEventQueue.cpp b/libs/gui/SensorEventQueue.cpp
index 76ae470..4b7986e 100644
--- a/libs/gui/SensorEventQueue.cpp
+++ b/libs/gui/SensorEventQueue.cpp
@@ -20,6 +20,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <linux/errno.h>
 
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
@@ -149,6 +150,23 @@
     return mSensorEventConnection->setEventRate(sensor->getHandle(), ns);
 }
 
+status_t SensorEventQueue::injectSensorEvent(const ASensorEvent& event) {
+    do {
+        // Blocking call.
+        ssize_t size = ::send(mSensorChannel->getFd(), &event, sizeof(event), MSG_NOSIGNAL);
+        if (size >= 0) {
+            return NO_ERROR;
+        } else if (size < 0 && errno == EAGAIN) {
+            // If send is returning a "Try again" error, sleep for 100ms and try again. In all
+            // other cases log a failure and exit.
+            usleep(100000);
+        } else {
+            ALOGE("injectSensorEvent failure %s %zd", strerror(errno), size);
+            return INVALID_OPERATION;
+        }
+    } while (true);
+}
+
 void SensorEventQueue::sendAck(const ASensorEvent* events, int count) {
     for (int i = 0; i < count; ++i) {
         if (events[i].flags & WAKE_UP_SENSOR_EVENT_NEEDS_ACK) {
diff --git a/libs/gui/SensorManager.cpp b/libs/gui/SensorManager.cpp
index d6df404..dd37781 100644
--- a/libs/gui/SensorManager.cpp
+++ b/libs/gui/SensorManager.cpp
@@ -36,10 +36,8 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
-ANDROID_SINGLETON_STATIC_INSTANCE(SensorManager)
-
-SensorManager::SensorManager()
-    : mSensorList(0)
+SensorManager::SensorManager(const String16& opPackageName)
+    : mSensorList(0), mOpPackageName(opPackageName)
 {
     // okay we're not locked here, but it's not needed during construction
     assertStateLocked();
@@ -88,7 +86,7 @@
         mDeathObserver = new DeathObserver(*const_cast<SensorManager *>(this));
         IInterface::asBinder(mSensorServer)->linkToDeath(mDeathObserver);
 
-        mSensors = mSensorServer->getSensorList();
+        mSensors = mSensorServer->getSensorList(mOpPackageName);
         size_t count = mSensors.size();
         mSensorList =
                 static_cast<Sensor const**>(malloc(count * sizeof(Sensor*)));
@@ -100,8 +98,6 @@
     return NO_ERROR;
 }
 
-
-
 ssize_t SensorManager::getSensorList(Sensor const* const** list) const
 {
     Mutex::Autolock _l(mLock);
@@ -139,18 +135,17 @@
     return NULL;
 }
 
-sp<SensorEventQueue> SensorManager::createEventQueue()
-{
+sp<SensorEventQueue> SensorManager::createEventQueue(String8 packageName, int mode) {
     sp<SensorEventQueue> queue;
 
     Mutex::Autolock _l(mLock);
     while (assertStateLocked() == NO_ERROR) {
         sp<ISensorEventConnection> connection =
-                mSensorServer->createSensorEventConnection();
+                mSensorServer->createSensorEventConnection(packageName, mode, mOpPackageName);
         if (connection == NULL) {
-            // SensorService just died.
-            ALOGE("createEventQueue: connection is NULL. SensorService died.");
-            continue;
+            // SensorService just died or the app doesn't have required permissions.
+            ALOGE("createEventQueue: connection is NULL.");
+            return NULL;
         }
         queue = new SensorEventQueue(connection);
         break;
@@ -158,5 +153,13 @@
     return queue;
 }
 
+bool SensorManager::isDataInjectionEnabled() {
+    Mutex::Autolock _l(mLock);
+    if (assertStateLocked() == NO_ERROR) {
+        return mSensorServer->isDataInjectionEnabled();
+    }
+    return false;
+}
+
 // ----------------------------------------------------------------------------
 }; // namespace android
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index b8acad2..4b76f98 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -42,7 +42,8 @@
 Surface::Surface(
         const sp<IGraphicBufferProducer>& bufferProducer,
         bool controlledByApp)
-    : mGraphicBufferProducer(bufferProducer)
+    : mGraphicBufferProducer(bufferProducer),
+      mGenerationNumber(0)
 {
     // Initialize the ANativeWindow function pointers.
     ANativeWindow::setSwapInterval  = hook_setSwapInterval;
@@ -102,6 +103,18 @@
             reqHeight, mReqFormat, mReqUsage);
 }
 
+status_t Surface::setGenerationNumber(uint32_t generation) {
+    status_t result = mGraphicBufferProducer->setGenerationNumber(generation);
+    if (result == NO_ERROR) {
+        mGenerationNumber = generation;
+    }
+    return result;
+}
+
+String8 Surface::getConsumerName() const {
+    return mGraphicBufferProducer->getConsumerName();
+}
+
 int Surface::hook_setSwapInterval(ANativeWindow* window, int interval) {
     Surface* c = getSelf(window);
     return c->setSwapInterval(interval);
@@ -267,6 +280,9 @@
     Mutex::Autolock lock(mMutex);
     int i = getSlotFromBufferLocked(buffer);
     if (i < 0) {
+        if (fenceFd >= 0) {
+            close(fenceFd);
+        }
         return i;
     }
     sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
@@ -308,6 +324,9 @@
     }
     int i = getSlotFromBufferLocked(buffer);
     if (i < 0) {
+        if (fenceFd >= 0) {
+            close(fenceFd);
+        }
         return i;
     }
 
@@ -325,16 +344,61 @@
     if (mConnectedToCpu || mDirtyRegion.bounds() == Rect::INVALID_RECT) {
         input.setSurfaceDamage(Region::INVALID_REGION);
     } else {
-        // The surface damage was specified using the OpenGL ES convention of
-        // the origin being in the bottom-left corner. Here we flip to the
-        // convention that the rest of the system uses (top-left corner) by
-        // subtracting all top/bottom coordinates from the buffer height.
+        // Here we do two things:
+        // 1) The surface damage was specified using the OpenGL ES convention of
+        //    the origin being in the bottom-left corner. Here we flip to the
+        //    convention that the rest of the system uses (top-left corner) by
+        //    subtracting all top/bottom coordinates from the buffer height.
+        // 2) If the buffer is coming in rotated (for example, because the EGL
+        //    implementation is reacting to the transform hint coming back from
+        //    SurfaceFlinger), the surface damage needs to be rotated the
+        //    opposite direction, since it was generated assuming an unrotated
+        //    buffer (the app doesn't know that the EGL implementation is
+        //    reacting to the transform hint behind its back). The
+        //    transformations in the switch statement below apply those
+        //    complementary rotations (e.g., if 90 degrees, rotate 270 degrees).
+
+        int width = buffer->width;
+        int height = buffer->height;
+        bool rotated90 = (mTransform ^ mStickyTransform) &
+                NATIVE_WINDOW_TRANSFORM_ROT_90;
+        if (rotated90) {
+            std::swap(width, height);
+        }
+
         Region flippedRegion;
         for (auto rect : mDirtyRegion) {
-            auto top = buffer->height - rect.bottom;
-            auto bottom = buffer->height - rect.top;
-            Rect flippedRect{rect.left, top, rect.right, bottom};
-            flippedRegion.orSelf(flippedRect);
+            int left = rect.left;
+            int right = rect.right;
+            int top = height - rect.bottom; // Flip from OpenGL convention
+            int bottom = height - rect.top; // Flip from OpenGL convention
+            switch (mTransform ^ mStickyTransform) {
+                case NATIVE_WINDOW_TRANSFORM_ROT_90: {
+                    // Rotate 270 degrees
+                    Rect flippedRect{top, width - right, bottom, width - left};
+                    flippedRegion.orSelf(flippedRect);
+                    break;
+                }
+                case NATIVE_WINDOW_TRANSFORM_ROT_180: {
+                    // Rotate 180 degrees
+                    Rect flippedRect{width - right, height - bottom,
+                            width - left, height - top};
+                    flippedRegion.orSelf(flippedRect);
+                    break;
+                }
+                case NATIVE_WINDOW_TRANSFORM_ROT_270: {
+                    // Rotate 90 degrees
+                    Rect flippedRect{height - bottom, left,
+                            height - top, right};
+                    flippedRegion.orSelf(flippedRect);
+                    break;
+                }
+                default: {
+                    Rect flippedRect{left, top, right, bottom};
+                    flippedRegion.orSelf(flippedRect);
+                    break;
+                }
+            }
         }
 
         input.setSurfaceDamage(flippedRegion);
@@ -651,7 +715,7 @@
     return err;
 }
 
-int Surface::detachNextBuffer(ANativeWindowBuffer** outBuffer,
+int Surface::detachNextBuffer(sp<GraphicBuffer>* outBuffer,
         sp<Fence>* outFence) {
     ATRACE_CALL();
     ALOGV("Surface::detachNextBuffer");
@@ -670,7 +734,7 @@
         return result;
     }
 
-    *outBuffer = buffer.get();
+    *outBuffer = buffer;
     if (fence != NULL && fence->isValid()) {
         *outFence = fence;
     } else {
@@ -688,11 +752,14 @@
     Mutex::Autolock lock(mMutex);
 
     sp<GraphicBuffer> graphicBuffer(static_cast<GraphicBuffer*>(buffer));
+    uint32_t priorGeneration = graphicBuffer->mGenerationNumber;
+    graphicBuffer->mGenerationNumber = mGenerationNumber;
     int32_t attachedSlot = -1;
     status_t result = mGraphicBufferProducer->attachBuffer(
             &attachedSlot, graphicBuffer);
     if (result != NO_ERROR) {
         ALOGE("attachBuffer: IGraphicBufferProducer call failed (%d)", result);
+        graphicBuffer->mGenerationNumber = priorGeneration;
         return result;
     }
     mSlots[attachedSlot].buffer = graphicBuffer;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 707a321..6ad47d8 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -310,11 +310,10 @@
     layer_state_t* s = getLayerStateLocked(client, id);
     if (!s)
         return BAD_INDEX;
-    if (mask & layer_state_t::eLayerOpaque) {
-        s->what |= layer_state_t::eOpacityChanged;
-    }
-    if (mask & layer_state_t::eLayerHidden) {
-        s->what |= layer_state_t::eVisibilityChanged;
+    if (mask & layer_state_t::eLayerOpaque ||
+            mask & layer_state_t::eLayerHidden ||
+            mask & layer_state_t::eLayerSecure) {
+        s->what |= layer_state_t::eFlagsChanged;
     }
     s->flags &= ~mask;
     s->flags |= (flags & mask);
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 1584fef..1a54875 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -17,6 +17,8 @@
 #define LOG_TAG "BufferQueue_test"
 //#define LOG_NDEBUG 0
 
+#include "DummyConsumer.h"
+
 #include <gui/BufferItem.h>
 #include <gui/BufferQueue.h>
 #include <gui/IProducerListener.h>
@@ -67,12 +69,6 @@
     sp<IGraphicBufferConsumer> mConsumer;
 };
 
-struct DummyConsumer : public BnConsumerListener {
-    virtual void onFrameAvailable(const BufferItem& /* item */) {}
-    virtual void onBuffersReleased() {}
-    virtual void onSidebandStreamChanged() {}
-};
-
 static const uint32_t TEST_DATA = 0x12345678u;
 
 // XXX: Tests that fork a process to hold the BufferQueue must run before tests
@@ -402,4 +398,46 @@
             WIDTH * 2, HEIGHT * 2, 0, GRALLOC_USAGE_SW_WRITE_OFTEN));
 }
 
+TEST_F(BufferQueueTest, TestGenerationNumbers) {
+    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));
+
+    ASSERT_EQ(OK, mProducer->setGenerationNumber(1));
+
+    // Get one buffer to play with
+    int slot;
+    sp<Fence> fence;
+    ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
+            mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0, 0));
+
+    sp<GraphicBuffer> buffer;
+    ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
+
+    // Ensure that the generation number we set propagates to allocated buffers
+    ASSERT_EQ(1U, buffer->getGenerationNumber());
+
+    ASSERT_EQ(OK, mProducer->detachBuffer(slot));
+
+    ASSERT_EQ(OK, mProducer->setGenerationNumber(2));
+
+    // These should fail, since we've changed the generation number on the queue
+    int outSlot;
+    ASSERT_EQ(BAD_VALUE, mProducer->attachBuffer(&outSlot, buffer));
+    ASSERT_EQ(BAD_VALUE, mConsumer->attachBuffer(&outSlot, buffer));
+
+    buffer->setGenerationNumber(2);
+
+    // This should succeed now that we've changed the buffer's generation number
+    ASSERT_EQ(OK, mProducer->attachBuffer(&outSlot, buffer));
+
+    ASSERT_EQ(OK, mProducer->detachBuffer(outSlot));
+
+    // This should also succeed with the new generation number
+    ASSERT_EQ(OK, mConsumer->attachBuffer(&outSlot, buffer));
+}
+
 } // namespace android
diff --git a/libs/gui/tests/DummyConsumer.h b/libs/gui/tests/DummyConsumer.h
new file mode 100644
index 0000000..0511e16
--- /dev/null
+++ b/libs/gui/tests/DummyConsumer.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2015 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 <gui/IConsumerListener.h>
+
+namespace android {
+
+struct DummyConsumer : public BnConsumerListener {
+    virtual void onFrameAvailable(const BufferItem& /* item */) {}
+    virtual void onBuffersReleased() {}
+    virtual void onSidebandStreamChanged() {}
+};
+
+} // namespace android
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index ff58420..4ef9a69 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -299,7 +299,7 @@
     ASSERT_NO_FATAL_FAILURE(ConnectProducer());
 
     // One past the end of the last 'query' enum value. Update this if we add more enums.
-    const int NATIVE_WINDOW_QUERY_LAST_OFF_BY_ONE = NATIVE_WINDOW_DEFAULT_DATASPACE + 1;
+    const int NATIVE_WINDOW_QUERY_LAST_OFF_BY_ONE = NATIVE_WINDOW_BUFFER_AGE + 1;
 
     int value;
     // What was out of range
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index d750cd0..1a50b24 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -27,6 +27,9 @@
 #include <utils/Log.h>
 #include <utils/Thread.h>
 
+EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
+#define CROP_EXT_STR "EGL_ANDROID_image_crop"
+
 namespace android {
 
 class SurfaceTextureClientTest : public ::testing::Test {
@@ -615,6 +618,18 @@
 }
 
 TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffersWithCrop) {
+    // Query to see if the image crop extension exists
+    EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS);
+    size_t cropExtLen = strlen(CROP_EXT_STR);
+    size_t extsLen = strlen(exts);
+    bool equal = !strcmp(CROP_EXT_STR, exts);
+    bool atStart = !strncmp(CROP_EXT_STR " ", exts, cropExtLen+1);
+    bool atEnd = (cropExtLen+1) < extsLen &&
+            !strcmp(" " CROP_EXT_STR, exts + extsLen - (cropExtLen+1));
+    bool inMiddle = strstr(exts, " " CROP_EXT_STR " ");
+    bool hasEglAndroidImageCrop = equal || atStart || atEnd || inMiddle;
+
     android_native_buffer_t* buf[3];
     float mtx[16] = {};
     android_native_rect_t crop;
@@ -633,15 +648,17 @@
     ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 6)); // frees buffers
     mST->getTransformMatrix(mtx);
 
-    // This accounts for the .5 texel shrink for each edge that's included in the
-    // transform matrix to avoid texturing outside the crop region.
-    EXPECT_EQ(0.5, mtx[0]);
+    // If the egl image crop extension is not present, this accounts for the
+    // .5 texel shrink for each edge that's included in the transform matrix
+    // to avoid texturing outside the crop region. Otherwise the crop is not
+    // included in the transform matrix.
+    EXPECT_EQ(hasEglAndroidImageCrop ? 1 : 0.5, mtx[0]);
     EXPECT_EQ(0.f, mtx[1]);
     EXPECT_EQ(0.f, mtx[2]);
     EXPECT_EQ(0.f, mtx[3]);
 
     EXPECT_EQ(0.f, mtx[4]);
-    EXPECT_EQ(-0.5, mtx[5]);
+    EXPECT_EQ(hasEglAndroidImageCrop ? -1 : -0.5, mtx[5]);
     EXPECT_EQ(0.f, mtx[6]);
     EXPECT_EQ(0.f, mtx[7]);
 
@@ -650,8 +667,8 @@
     EXPECT_EQ(1.f, mtx[10]);
     EXPECT_EQ(0.f, mtx[11]);
 
-    EXPECT_EQ(0.0625f, mtx[12]);
-    EXPECT_EQ(0.5625f, mtx[13]);
+    EXPECT_EQ(hasEglAndroidImageCrop ? 0 : 0.0625f, mtx[12]);
+    EXPECT_EQ(hasEglAndroidImageCrop ? 1 : 0.5625f, mtx[13]);
     EXPECT_EQ(0.f, mtx[14]);
     EXPECT_EQ(1.f, mtx[15]);
 }
diff --git a/libs/gui/tests/SurfaceTextureGLToGL_test.cpp b/libs/gui/tests/SurfaceTextureGLToGL_test.cpp
index f4c7961..6edbfb8 100644
--- a/libs/gui/tests/SurfaceTextureGLToGL_test.cpp
+++ b/libs/gui/tests/SurfaceTextureGLToGL_test.cpp
@@ -188,10 +188,10 @@
     // This test should have the only reference to buffer 0.
     EXPECT_EQ(1, buffers[0]->getStrongCount());
 
-    // The GLConsumer should hold a single reference to buffer 1 in its
-    // mCurrentBuffer member.  All of the references in the slots should have
-    // been released.
-    EXPECT_EQ(2, buffers[1]->getStrongCount());
+    // The GLConsumer should hold one reference to buffer 1 in its
+    // mCurrentTextureImage member and another reference in mEglSlots. The third
+    // reference is in this test.
+    EXPECT_EQ(3, buffers[1]->getStrongCount());
 }
 
 TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceAfterAbandonUnrefsBuffers) {
@@ -235,14 +235,19 @@
     ASSERT_EQ(EGL_SUCCESS, eglGetError());
     mProducerEglSurface = EGL_NO_SURFACE;
 
-    EXPECT_EQ(1, buffers[0]->getStrongCount());
     EXPECT_EQ(1, buffers[1]->getStrongCount());
 
     // Depending on how lazily the GL driver dequeues buffers, we may end up
-    // with either two or three total buffers.  If there are three, make sure
-    // the last one was properly down-ref'd.
+    // with either two or three total buffers.  If there are three, each entry
+    // of the buffers array will be unique and there should only be one
+    // reference (the one in this test). If there are two the first and last
+    // element in the array will be equal meaning that buffer representing both
+    // 0 and 2 will have two references (one for 0 and one for 2).
     if (buffers[2] != buffers[0]) {
+        EXPECT_EQ(1, buffers[0]->getStrongCount());
         EXPECT_EQ(1, buffers[2]->getStrongCount());
+    } else {
+        EXPECT_EQ(2, buffers[0]->getStrongCount());
     }
 }
 
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 4f87824..3f495f8 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "DummyConsumer.h"
+
 #include <gtest/gtest.h>
 
 #include <binder/IMemory.h>
@@ -177,4 +179,53 @@
     ASSERT_EQ(TEST_DATASPACE, dataSpace);
 }
 
+TEST_F(SurfaceTest, SettingGenerationNumber) {
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1);
+    sp<Surface> surface = new Surface(producer);
+    sp<ANativeWindow> window(surface);
+
+    // Allocate a buffer with a generation number of 0
+    ANativeWindowBuffer* buffer;
+    int fenceFd;
+    ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fenceFd));
+    ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fenceFd));
+
+    // Detach the buffer and check its generation number
+    sp<GraphicBuffer> graphicBuffer;
+    sp<Fence> fence;
+    ASSERT_EQ(NO_ERROR, surface->detachNextBuffer(&graphicBuffer, &fence));
+    ASSERT_EQ(0U, graphicBuffer->getGenerationNumber());
+
+    ASSERT_EQ(NO_ERROR, surface->setGenerationNumber(1));
+    buffer = static_cast<ANativeWindowBuffer*>(graphicBuffer.get());
+
+    // This should change the generation number of the GraphicBuffer
+    ASSERT_EQ(NO_ERROR, surface->attachBuffer(buffer));
+
+    // Check that the new generation number sticks with the buffer
+    ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, -1));
+    ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fenceFd));
+    graphicBuffer = static_cast<GraphicBuffer*>(buffer);
+    ASSERT_EQ(1U, graphicBuffer->getGenerationNumber());
+}
+
+TEST_F(SurfaceTest, GetConsumerName) {
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+
+    sp<DummyConsumer> dummyConsumer(new DummyConsumer);
+    consumer->consumerConnect(dummyConsumer, false);
+    consumer->setConsumerName(String8("TestConsumer"));
+
+    sp<Surface> surface = new Surface(producer);
+    sp<ANativeWindow> window(surface);
+    native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU);
+
+    EXPECT_STREQ("TestConsumer", surface->getConsumerName().string());
+}
+
 }
diff --git a/libs/input/Android.mk b/libs/input/Android.mk
index f1921a4..944ac7f 100644
--- a/libs/input/Android.mk
+++ b/libs/input/Android.mk
@@ -27,6 +27,7 @@
 
 deviceSources := \
     $(commonSources) \
+    IInputFlinger.cpp \
     InputTransport.cpp \
     VelocityControl.cpp \
     VelocityTracker.cpp
diff --git a/libs/input/IInputFlinger.cpp b/libs/input/IInputFlinger.cpp
new file mode 100644
index 0000000..e009731
--- /dev/null
+++ b/libs/input/IInputFlinger.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2013 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 <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+
+#include <input/IInputFlinger.h>
+
+
+namespace android {
+
+class BpInputFlinger : public BpInterface<IInputFlinger> {
+public:
+    BpInputFlinger(const sp<IBinder>& impl) :
+            BpInterface<IInputFlinger>(impl) { }
+
+    virtual status_t doSomething() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor());
+        remote()->transact(BnInputFlinger::DO_SOMETHING_TRANSACTION, data, &reply);
+        return reply.readInt32();
+    }
+};
+
+IMPLEMENT_META_INTERFACE(InputFlinger, "android.input.IInputFlinger");
+
+
+status_t BnInputFlinger::onTransact(
+        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+    switch(code) {
+    case DO_SOMETHING_TRANSACTION: {
+        CHECK_INTERFACE(IInputFlinger, data, reply);
+        reply->writeInt32(0);
+        break;
+    }
+    default:
+        return BBinder::onTransact(code, data, reply, flags);
+    }
+    return NO_ERROR;
+}
+
+};
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index cd55ee5..b64cb2c 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -216,6 +216,7 @@
         int32_t deviceId,
         int32_t source,
         int32_t action,
+        int32_t actionButton,
         int32_t flags,
         int32_t edgeFlags,
         int32_t metaState,
@@ -231,6 +232,7 @@
         const PointerCoords* pointerCoords) {
     InputEvent::initialize(deviceId, source);
     mAction = action;
+    mActionButton = actionButton;
     mFlags = flags;
     mEdgeFlags = edgeFlags;
     mMetaState = metaState;
@@ -250,6 +252,7 @@
 void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) {
     InputEvent::initialize(other->mDeviceId, other->mSource);
     mAction = other->mAction;
+    mActionButton = other->mActionButton;
     mFlags = other->mFlags;
     mEdgeFlags = other->mEdgeFlags;
     mMetaState = other->mMetaState;
@@ -429,6 +432,7 @@
     mDeviceId = parcel->readInt32();
     mSource = parcel->readInt32();
     mAction = parcel->readInt32();
+    mActionButton = parcel->readInt32();
     mFlags = parcel->readInt32();
     mEdgeFlags = parcel->readInt32();
     mMetaState = parcel->readInt32();
@@ -476,6 +480,7 @@
     parcel->writeInt32(mDeviceId);
     parcel->writeInt32(mSource);
     parcel->writeInt32(mAction);
+    parcel->writeInt32(mActionButton);
     parcel->writeInt32(mFlags);
     parcel->writeInt32(mEdgeFlags);
     parcel->writeInt32(mMetaState);
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index b11110a..d755ed3 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -127,28 +127,31 @@
 // --- InputDeviceInfo ---
 
 InputDeviceInfo::InputDeviceInfo() {
-    initialize(-1, 0, -1, InputDeviceIdentifier(), String8(), false);
+    initialize(-1, 0, -1, InputDeviceIdentifier(), String8(), false, false);
 }
 
 InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) :
         mId(other.mId), mGeneration(other.mGeneration), mControllerNumber(other.mControllerNumber),
         mIdentifier(other.mIdentifier), mAlias(other.mAlias), mIsExternal(other.mIsExternal),
-        mSources(other.mSources), mKeyboardType(other.mKeyboardType),
-        mKeyCharacterMap(other.mKeyCharacterMap), mHasVibrator(other.mHasVibrator),
-        mHasButtonUnderPad(other.mHasButtonUnderPad), mMotionRanges(other.mMotionRanges) {
+        mHasMic(other.mHasMic), mSources(other.mSources),
+        mKeyboardType(other.mKeyboardType), mKeyCharacterMap(other.mKeyCharacterMap),
+        mHasVibrator(other.mHasVibrator), mHasButtonUnderPad(other.mHasButtonUnderPad),
+        mMotionRanges(other.mMotionRanges) {
 }
 
 InputDeviceInfo::~InputDeviceInfo() {
 }
 
 void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t controllerNumber,
-        const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal) {
+        const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal,
+        bool hasMic) {
     mId = id;
     mGeneration = generation;
     mControllerNumber = controllerNumber;
     mIdentifier = identifier;
     mAlias = alias;
     mIsExternal = isExternal;
+    mHasMic = hasMic;
     mSources = 0;
     mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE;
     mHasVibrator = false;
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 090ee53..0382f57 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -283,6 +283,7 @@
         int32_t deviceId,
         int32_t source,
         int32_t action,
+        int32_t actionButton,
         int32_t flags,
         int32_t edgeFlags,
         int32_t metaState,
@@ -298,12 +299,12 @@
         const PointerCoords* pointerCoords) {
 #if DEBUG_TRANSPORT_ACTIONS
     ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, "
-            "action=0x%x, flags=0x%x, edgeFlags=0x%x, metaState=0x%x, buttonState=0x%x, "
-            "xOffset=%f, yOffset=%f, "
+            "action=0x%x, actionButton=0x%08x, flags=0x%x, edgeFlags=0x%x, "
+            "metaState=0x%x, buttonState=0x%x, xOffset=%f, yOffset=%f, "
             "xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, "
             "pointerCount=%" PRIu32,
             mChannel->getName().string(), seq,
-            deviceId, source, action, flags, edgeFlags, metaState, buttonState,
+            deviceId, source, action, actionButton, flags, edgeFlags, metaState, buttonState,
             xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount);
 #endif
 
@@ -324,6 +325,7 @@
     msg.body.motion.deviceId = deviceId;
     msg.body.motion.source = source;
     msg.body.motion.action = action;
+    msg.body.motion.actionButton = actionButton;
     msg.body.motion.flags = flags;
     msg.body.motion.edgeFlags = edgeFlags;
     msg.body.motion.metaState = metaState;
@@ -907,6 +909,7 @@
             msg->body.motion.deviceId,
             msg->body.motion.source,
             msg->body.motion.action,
+            msg->body.motion.actionButton,
             msg->body.motion.flags,
             msg->body.motion.edgeFlags,
             msg->body.motion.metaState,
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index 9105ae5..3fb1c6d 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -248,7 +248,7 @@
     pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 26);
     pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 27);
     pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28);
-    event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE,
+    event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE, 0,
             AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED,
             AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY,
             X_OFFSET, Y_OFFSET, 2.0f, 2.1f,
@@ -557,7 +557,7 @@
         pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, angle);
     }
     MotionEvent event;
-    event.initialize(0, 0, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0, 0,
+    event.initialize(0, 0, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0, 0, 0,
             0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
     float originalRawX = 0 + 3;
     float originalRawY = -RADIUS + 2;
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index de192f1..8e69c9c 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -133,6 +133,7 @@
     const int32_t deviceId = 1;
     const int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
     const int32_t action = AMOTION_EVENT_ACTION_MOVE;
+    const int32_t actionButton = 0;
     const int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
     const int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_TOP;
     const int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
@@ -163,8 +164,8 @@
         pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i);
     }
 
-    status = mPublisher->publishMotionEvent(seq, deviceId, source, action, flags, edgeFlags,
-            metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision,
+    status = mPublisher->publishMotionEvent(seq, deviceId, source, action, actionButton,
+            flags, edgeFlags, metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision,
             downTime, eventTime, pointerCount,
             pointerProperties, pointerCoords);
     ASSERT_EQ(OK, status)
@@ -255,7 +256,7 @@
     PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
 
-    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(BAD_VALUE, status)
             << "publisher publishMotionEvent should return BAD_VALUE";
@@ -271,7 +272,7 @@
         pointerCoords[i].clear();
     }
 
-    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(BAD_VALUE, status)
             << "publisher publishMotionEvent should return BAD_VALUE";
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index 83bc6ae..8d73f45 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -51,10 +51,11 @@
   CHECK_OFFSET(InputMessage::Body::Motion, deviceId, 16);
   CHECK_OFFSET(InputMessage::Body::Motion, source, 20);
   CHECK_OFFSET(InputMessage::Body::Motion, action, 24);
-  CHECK_OFFSET(InputMessage::Body::Motion, flags, 28);
-  CHECK_OFFSET(InputMessage::Body::Motion, metaState, 32);
-  CHECK_OFFSET(InputMessage::Body::Motion, buttonState, 36);
-  CHECK_OFFSET(InputMessage::Body::Motion, edgeFlags, 40);
+  CHECK_OFFSET(InputMessage::Body::Motion, actionButton, 28);
+  CHECK_OFFSET(InputMessage::Body::Motion, flags, 32);
+  CHECK_OFFSET(InputMessage::Body::Motion, metaState, 36);
+  CHECK_OFFSET(InputMessage::Body::Motion, buttonState, 40);
+  CHECK_OFFSET(InputMessage::Body::Motion, edgeFlags, 44);
   CHECK_OFFSET(InputMessage::Body::Motion, downTime, 48);
   CHECK_OFFSET(InputMessage::Body::Motion, xOffset, 56);
   CHECK_OFFSET(InputMessage::Body::Motion, yOffset, 60);
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 6a42a22..e55db30 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -278,7 +278,7 @@
 }
 
 size_t GraphicBuffer::getFlattenedSize() const {
-    return static_cast<size_t>(10 + (handle ? handle->numInts : 0)) * sizeof(int);
+    return static_cast<size_t>(11 + (handle ? handle->numInts : 0)) * sizeof(int);
 }
 
 size_t GraphicBuffer::getFdCount() const {
@@ -301,15 +301,16 @@
     buf[5] = usage;
     buf[6] = static_cast<int32_t>(mId >> 32);
     buf[7] = static_cast<int32_t>(mId & 0xFFFFFFFFull);
-    buf[8] = 0;
+    buf[8] = static_cast<int32_t>(mGenerationNumber);
     buf[9] = 0;
+    buf[10] = 0;
 
     if (handle) {
-        buf[8] = handle->numFds;
-        buf[9] = handle->numInts;
+        buf[9] = handle->numFds;
+        buf[10] = handle->numInts;
         memcpy(fds, handle->data,
                 static_cast<size_t>(handle->numFds) * sizeof(int));
-        memcpy(&buf[10], handle->data + handle->numFds,
+        memcpy(&buf[11], handle->data + handle->numFds,
                 static_cast<size_t>(handle->numInts) * sizeof(int));
     }
 
@@ -325,20 +326,20 @@
 
 status_t GraphicBuffer::unflatten(
         void const*& buffer, size_t& size, int const*& fds, size_t& count) {
-    if (size < 8*sizeof(int)) return NO_MEMORY;
+    if (size < 11 * sizeof(int)) return NO_MEMORY;
 
     int const* buf = static_cast<int const*>(buffer);
     if (buf[0] != 'GBFR') return BAD_TYPE;
 
-    const size_t numFds  = static_cast<size_t>(buf[8]);
-    const size_t numInts = static_cast<size_t>(buf[9]);
+    const size_t numFds  = static_cast<size_t>(buf[9]);
+    const size_t numInts = static_cast<size_t>(buf[10]);
 
     // Limit the maxNumber to be relatively small. The number of fds or ints
     // should not come close to this number, and the number itself was simply
     // chosen to be high enough to not cause issues and low enough to prevent
     // overflow problems.
     const size_t maxNumber = 4096;
-    if (numFds >= maxNumber || numInts >= (maxNumber - 10)) {
+    if (numFds >= maxNumber || numInts >= (maxNumber - 11)) {
         width = height = stride = format = usage = 0;
         handle = NULL;
         ALOGE("unflatten: numFds or numInts is too large: %zd, %zd",
@@ -346,7 +347,7 @@
         return BAD_VALUE;
     }
 
-    const size_t sizeNeeded = (10 + numInts) * sizeof(int);
+    const size_t sizeNeeded = (11 + numInts) * sizeof(int);
     if (size < sizeNeeded) return NO_MEMORY;
 
     size_t fdCountNeeded = numFds;
@@ -372,7 +373,7 @@
             return NO_MEMORY;
         }
         memcpy(h->data, fds, numFds * sizeof(int));
-        memcpy(h->data + numFds, &buf[10], numInts * sizeof(int));
+        memcpy(h->data + numFds, &buf[11], numInts * sizeof(int));
         handle = h;
     } else {
         width = height = stride = format = usage = 0;
@@ -382,6 +383,8 @@
     mId = static_cast<uint64_t>(buf[6]) << 32;
     mId |= static_cast<uint32_t>(buf[7]);
 
+    mGenerationNumber = static_cast<uint32_t>(buf[8]);
+
     mOwner = ownHandle;
 
     if (handle != 0) {
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index 85e9675..9b265af 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -104,6 +104,9 @@
     // we have a h/w allocator and h/w buffer is requested
     status_t err;
 
+    // Filter out any usage bits that should not be passed to the gralloc module
+    usage &= GRALLOC_USAGE_ALLOC_MASK;
+
     int outStride = 0;
     err = mAllocDev->alloc(mAllocDev, static_cast<int>(width),
             static_cast<int>(height), format, static_cast<int>(usage), handle,
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index 31bfb2d..90a1c11 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -131,8 +131,10 @@
                 bounds.left, bounds.top, bounds.width(), bounds.height(),
                 vaddr, fenceFd);
     } else {
-        sync_wait(fenceFd, -1);
-        close(fenceFd);
+        if (fenceFd >= 0) {
+            sync_wait(fenceFd, -1);
+            close(fenceFd);
+        }
         err = mAllocMod->lock(mAllocMod, handle, static_cast<int>(usage),
                 bounds.left, bounds.top, bounds.width(), bounds.height(),
                 vaddr);
@@ -154,12 +156,17 @@
                 static_cast<int>(usage), bounds.left, bounds.top,
                 bounds.width(), bounds.height(), ycbcr, fenceFd);
     } else if (mAllocMod->lock_ycbcr != NULL) {
-        sync_wait(fenceFd, -1);
-        close(fenceFd);
+        if (fenceFd >= 0) {
+            sync_wait(fenceFd, -1);
+            close(fenceFd);
+        }
         err = mAllocMod->lock_ycbcr(mAllocMod, handle, static_cast<int>(usage),
                 bounds.left, bounds.top, bounds.width(), bounds.height(),
                 ycbcr);
     } else {
+        if (fenceFd >= 0) {
+            close(fenceFd);
+        }
         return -EINVAL; // do not log failure
     }
 
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 25f7607..b2abdb1 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -444,6 +444,11 @@
 #define EGL_OPENGL_ES3_BIT_KHR				    0x00000040
 #endif
 
+#ifndef EGL_KHR_create_context_no_error
+#define EGL_KHR_create_context_no_error 1
+#define EGL_CONTEXT_OPENGL_NO_ERROR_KHR   0x31B3
+#endif /* EGL_KHR_create_context_no_error */
+
 #ifndef EGL_KHR_surfaceless_context
 #define EGL_KHR_surfaceless_context 1
 /* No tokens/entry points, just relaxes an error condition */
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 1feac8b..593d0c2 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -394,7 +394,13 @@
         depth.width   = width;
         depth.height  = height;
         depth.stride  = depth.width; // use the width here
-        depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
+        uint64_t allocSize = static_cast<uint64_t>(depth.stride) *
+                static_cast<uint64_t>(depth.height) * 2;
+        if (depth.stride < 0 || depth.height > INT_MAX ||
+                allocSize > UINT32_MAX) {
+            return setError(EGL_BAD_ALLOC, EGL_FALSE);
+        }
+        depth.data    = (GGLubyte*)malloc(allocSize);
         if (depth.data == 0) {
             return setError(EGL_BAD_ALLOC, EGL_FALSE);
         }
@@ -548,7 +554,14 @@
                 depth.width   = width;
                 depth.height  = height;
                 depth.stride  = buffer->stride;
-                depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
+                uint64_t allocSize = static_cast<uint64_t>(depth.stride) *
+                        static_cast<uint64_t>(depth.height) * 2;
+                if (depth.stride < 0 || depth.height > INT_MAX ||
+                        allocSize > UINT32_MAX) {
+                    setError(EGL_BAD_ALLOC, EGL_FALSE);
+                    return EGL_FALSE;
+                }
+                depth.data    = (GGLubyte*)malloc(allocSize);
                 if (depth.data == 0) {
                     setError(EGL_BAD_ALLOC, EGL_FALSE);
                     return EGL_FALSE;
@@ -666,7 +679,14 @@
         depth.width   = pixmap->width;
         depth.height  = pixmap->height;
         depth.stride  = depth.width; // use the width here
-        depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
+        uint64_t allocSize = static_cast<uint64_t>(depth.stride) *
+                static_cast<uint64_t>(depth.height) * 2;
+        if (depth.stride < 0 || depth.height > INT_MAX ||
+                allocSize > UINT32_MAX) {
+            setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+            return;
+        }
+        depth.data    = (GGLubyte*)malloc(allocSize);
         if (depth.data == 0) {
             setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
         }
@@ -746,7 +766,14 @@
         depth.width   = pbuffer.width;
         depth.height  = pbuffer.height;
         depth.stride  = depth.width; // use the width here
-        depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
+        uint64_t allocSize = static_cast<uint64_t>(depth.stride) *
+                static_cast<uint64_t>(depth.height) * 2;
+        if (depth.stride < 0 || depth.height > INT_MAX ||
+                allocSize > UINT32_MAX) {
+            setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+            return;
+        }
+        depth.data    = (GGLubyte*)malloc(allocSize);
         if (depth.data == 0) {
             setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
             return;
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index 4da9f92..18ad300 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -86,6 +86,9 @@
 LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
 LOCAL_CFLAGS += -fvisibility=hidden
 
+# TODO: This is to work around b/20093774. Remove after root cause is fixed
+LOCAL_LDFLAGS_arm += -Wl,--hash-style,both
+
 include $(BUILD_SHARED_LIBRARY)
 
 
@@ -111,6 +114,9 @@
 LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
 LOCAL_CFLAGS += -fvisibility=hidden
 
+# TODO: This is to work around b/20093774. Remove after root cause is fixed
+LOCAL_LDFLAGS_arm += -Wl,--hash-style,both
+
 # Symlink libGLESv3.so -> libGLESv2.so
 # Platform modules should link against libGLESv2.so (-lGLESv2), but NDK apps
 # will be linked against libGLESv3.so.
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 7c70fa0..4e0e5bc 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -292,6 +292,44 @@
     return (const GLubyte *)c->gl_extensions.string();
 }
 
+const GLubyte * egl_get_string_for_current_context(GLenum name, GLuint index) {
+    // NOTE: returning NULL here will fall-back to the default
+    // implementation.
+
+    EGLContext context = egl_tls_t::getContext();
+    if (context == EGL_NO_CONTEXT)
+        return NULL;
+
+    egl_context_t const * const c = get_context(context);
+    if (c == NULL) // this should never happen, by construction
+        return NULL;
+
+    if (name != GL_EXTENSIONS)
+        return NULL;
+
+    // if index is out of bounds, assume it will be in the default
+    // implementation too, so we don't have to generate a GL error here
+    if (index >= c->tokenized_gl_extensions.size())
+        return NULL;
+
+    return (const GLubyte *)c->tokenized_gl_extensions.itemAt(index).string();
+}
+
+GLint egl_get_num_extensions_for_current_context() {
+    // NOTE: returning -1 here will fall-back to the default
+    // implementation.
+
+    EGLContext context = egl_tls_t::getContext();
+    if (context == EGL_NO_CONTEXT)
+        return -1;
+
+    egl_context_t const * const c = get_context(context);
+    if (c == NULL) // this should never happen, by construction
+        return -1;
+
+    return (GLint)c->tokenized_gl_extensions.size();
+}
+
 // ----------------------------------------------------------------------------
 
 // this mutex protects:
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index f5b90dd..8378907 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -91,11 +91,19 @@
         "EGL_KHR_gl_colorspace "
 #endif
         "EGL_KHR_gl_texture_2D_image "
+        "EGL_KHR_gl_texture_3D_image "
         "EGL_KHR_gl_texture_cubemap_image "
         "EGL_KHR_gl_renderbuffer_image "
         "EGL_KHR_reusable_sync "
         "EGL_KHR_fence_sync "
         "EGL_KHR_create_context "
+        "EGL_KHR_config_attribs "
+        "EGL_KHR_surfaceless_context "
+        "EGL_KHR_stream "
+        "EGL_KHR_stream_fifo "
+        "EGL_KHR_stream_producer_eglsurface "
+        "EGL_KHR_stream_consumer_gltexture "
+        "EGL_KHR_stream_cross_process_fd "
         "EGL_EXT_create_context_robustness "
         "EGL_NV_system_time "
         "EGL_ANDROID_image_native_buffer "      // mandatory
@@ -103,6 +111,7 @@
         "EGL_ANDROID_recordable "               // mandatory
         "EGL_KHR_partial_update "               // strongly recommended
         "EGL_EXT_buffer_age "                   // strongly recommended with partial_update
+        "EGL_KHR_create_context_no_error "
         ;
 
 // extensions not exposed to applications but used by the ANDROID system
@@ -163,6 +172,31 @@
     // EGL_KHR_partial_update
     { "eglSetDamageRegionKHR",
             (__eglMustCastToProperFunctionPointerType)&eglSetDamageRegionKHR },
+
+    { "eglCreateStreamKHR",
+            (__eglMustCastToProperFunctionPointerType)&eglCreateStreamKHR },
+    { "eglDestroyStreamKHR",
+            (__eglMustCastToProperFunctionPointerType)&eglDestroyStreamKHR },
+    { "eglStreamAttribKHR",
+            (__eglMustCastToProperFunctionPointerType)&eglStreamAttribKHR },
+    { "eglQueryStreamKHR",
+            (__eglMustCastToProperFunctionPointerType)&eglQueryStreamKHR },
+    { "eglQueryStreamu64KHR",
+            (__eglMustCastToProperFunctionPointerType)&eglQueryStreamu64KHR },
+    { "eglQueryStreamTimeKHR",
+            (__eglMustCastToProperFunctionPointerType)&eglQueryStreamTimeKHR },
+    { "eglCreateStreamProducerSurfaceKHR",
+            (__eglMustCastToProperFunctionPointerType)&eglCreateStreamProducerSurfaceKHR },
+    { "eglStreamConsumerGLTextureExternalKHR",
+            (__eglMustCastToProperFunctionPointerType)&eglStreamConsumerGLTextureExternalKHR },
+    { "eglStreamConsumerAcquireKHR",
+            (__eglMustCastToProperFunctionPointerType)&eglStreamConsumerAcquireKHR },
+    { "eglStreamConsumerReleaseKHR",
+            (__eglMustCastToProperFunctionPointerType)&eglStreamConsumerReleaseKHR },
+    { "eglGetStreamFileDescriptorKHR",
+            (__eglMustCastToProperFunctionPointerType)&eglGetStreamFileDescriptorKHR },
+    { "eglCreateStreamFromFileDescriptorKHR",
+            (__eglMustCastToProperFunctionPointerType)&eglCreateStreamFromFileDescriptorKHR },
 };
 
 /*
@@ -561,6 +595,15 @@
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
     egl_surface_t * const s = get_surface(surface);
+    ANativeWindow* window = s->win.get();
+    if (window) {
+        int result = native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+        if (result != OK) {
+            ALOGE("eglDestroySurface: native_window_api_disconnect (win=%p) "
+                  "failed (%#x)",
+                  window, result);
+        }
+    }
     EGLBoolean result = s->cnx->egl.eglDestroySurface(dp->disp.dpy, s->surface);
     if (result == EGL_TRUE) {
         _s.terminate();
@@ -1517,6 +1560,212 @@
     return result;
 }
 
+EGLStreamKHR eglCreateStreamKHR(EGLDisplay dpy, const EGLint *attrib_list)
+{
+    clearError();
+
+    const egl_display_ptr dp = validate_display(dpy);
+    if (!dp) return EGL_NO_STREAM_KHR;
+
+    EGLStreamKHR result = EGL_NO_STREAM_KHR;
+    egl_connection_t* const cnx = &gEGLImpl;
+    if (cnx->dso && cnx->egl.eglCreateStreamKHR) {
+        result = cnx->egl.eglCreateStreamKHR(
+                dp->disp.dpy, attrib_list);
+    }
+    return result;
+}
+
+EGLBoolean eglDestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream)
+{
+    clearError();
+
+    const egl_display_ptr dp = validate_display(dpy);
+    if (!dp) return EGL_FALSE;
+
+    EGLBoolean result = EGL_FALSE;
+    egl_connection_t* const cnx = &gEGLImpl;
+    if (cnx->dso && cnx->egl.eglDestroyStreamKHR) {
+        result = cnx->egl.eglDestroyStreamKHR(
+                dp->disp.dpy, stream);
+    }
+    return result;
+}
+
+EGLBoolean eglStreamAttribKHR(EGLDisplay dpy, EGLStreamKHR stream,
+        EGLenum attribute, EGLint value)
+{
+    clearError();
+
+    const egl_display_ptr dp = validate_display(dpy);
+    if (!dp) return EGL_FALSE;
+
+    EGLBoolean result = EGL_FALSE;
+    egl_connection_t* const cnx = &gEGLImpl;
+    if (cnx->dso && cnx->egl.eglStreamAttribKHR) {
+        result = cnx->egl.eglStreamAttribKHR(
+                dp->disp.dpy, stream, attribute, value);
+    }
+    return result;
+}
+
+EGLBoolean eglQueryStreamKHR(EGLDisplay dpy, EGLStreamKHR stream,
+        EGLenum attribute, EGLint *value)
+{
+    clearError();
+
+    const egl_display_ptr dp = validate_display(dpy);
+    if (!dp) return EGL_FALSE;
+
+    EGLBoolean result = EGL_FALSE;
+    egl_connection_t* const cnx = &gEGLImpl;
+    if (cnx->dso && cnx->egl.eglQueryStreamKHR) {
+        result = cnx->egl.eglQueryStreamKHR(
+                dp->disp.dpy, stream, attribute, value);
+    }
+    return result;
+}
+
+EGLBoolean eglQueryStreamu64KHR(EGLDisplay dpy, EGLStreamKHR stream,
+        EGLenum attribute, EGLuint64KHR *value)
+{
+    clearError();
+
+    const egl_display_ptr dp = validate_display(dpy);
+    if (!dp) return EGL_FALSE;
+
+    EGLBoolean result = EGL_FALSE;
+    egl_connection_t* const cnx = &gEGLImpl;
+    if (cnx->dso && cnx->egl.eglQueryStreamu64KHR) {
+        result = cnx->egl.eglQueryStreamu64KHR(
+                dp->disp.dpy, stream, attribute, value);
+    }
+    return result;
+}
+
+EGLBoolean eglQueryStreamTimeKHR(EGLDisplay dpy, EGLStreamKHR stream,
+        EGLenum attribute, EGLTimeKHR *value)
+{
+    clearError();
+
+    const egl_display_ptr dp = validate_display(dpy);
+    if (!dp) return EGL_FALSE;
+
+    EGLBoolean result = EGL_FALSE;
+    egl_connection_t* const cnx = &gEGLImpl;
+    if (cnx->dso && cnx->egl.eglQueryStreamTimeKHR) {
+        result = cnx->egl.eglQueryStreamTimeKHR(
+                dp->disp.dpy, stream, attribute, value);
+    }
+    return result;
+}
+
+EGLSurface eglCreateStreamProducerSurfaceKHR(EGLDisplay dpy, EGLConfig config,
+        EGLStreamKHR stream, const EGLint *attrib_list)
+{
+    clearError();
+
+    egl_display_ptr dp = validate_display(dpy);
+    if (!dp) return EGL_NO_SURFACE;
+
+    egl_connection_t* const cnx = &gEGLImpl;
+    if (cnx->dso && cnx->egl.eglCreateStreamProducerSurfaceKHR) {
+        EGLSurface surface = cnx->egl.eglCreateStreamProducerSurfaceKHR(
+                dp->disp.dpy, config, stream, attrib_list);
+        if (surface != EGL_NO_SURFACE) {
+            egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL,
+                    surface, cnx);
+            return s;
+        }
+    }
+    return EGL_NO_SURFACE;
+}
+
+EGLBoolean eglStreamConsumerGLTextureExternalKHR(EGLDisplay dpy,
+        EGLStreamKHR stream)
+{
+    clearError();
+
+    const egl_display_ptr dp = validate_display(dpy);
+    if (!dp) return EGL_FALSE;
+
+    EGLBoolean result = EGL_FALSE;
+    egl_connection_t* const cnx = &gEGLImpl;
+    if (cnx->dso && cnx->egl.eglStreamConsumerGLTextureExternalKHR) {
+        result = cnx->egl.eglStreamConsumerGLTextureExternalKHR(
+                dp->disp.dpy, stream);
+    }
+    return result;
+}
+
+EGLBoolean eglStreamConsumerAcquireKHR(EGLDisplay dpy,
+        EGLStreamKHR stream)
+{
+    clearError();
+
+    const egl_display_ptr dp = validate_display(dpy);
+    if (!dp) return EGL_FALSE;
+
+    EGLBoolean result = EGL_FALSE;
+    egl_connection_t* const cnx = &gEGLImpl;
+    if (cnx->dso && cnx->egl.eglStreamConsumerAcquireKHR) {
+        result = cnx->egl.eglStreamConsumerAcquireKHR(
+                dp->disp.dpy, stream);
+    }
+    return result;
+}
+
+EGLBoolean eglStreamConsumerReleaseKHR(EGLDisplay dpy,
+        EGLStreamKHR stream)
+{
+    clearError();
+
+    const egl_display_ptr dp = validate_display(dpy);
+    if (!dp) return EGL_FALSE;
+
+    EGLBoolean result = EGL_FALSE;
+    egl_connection_t* const cnx = &gEGLImpl;
+    if (cnx->dso && cnx->egl.eglStreamConsumerReleaseKHR) {
+        result = cnx->egl.eglStreamConsumerReleaseKHR(
+                dp->disp.dpy, stream);
+    }
+    return result;
+}
+
+EGLNativeFileDescriptorKHR eglGetStreamFileDescriptorKHR(
+        EGLDisplay dpy, EGLStreamKHR stream)
+{
+    clearError();
+
+    const egl_display_ptr dp = validate_display(dpy);
+    if (!dp) return EGL_NO_FILE_DESCRIPTOR_KHR;
+
+    EGLNativeFileDescriptorKHR result = EGL_NO_FILE_DESCRIPTOR_KHR;
+    egl_connection_t* const cnx = &gEGLImpl;
+    if (cnx->dso && cnx->egl.eglGetStreamFileDescriptorKHR) {
+        result = cnx->egl.eglGetStreamFileDescriptorKHR(
+                dp->disp.dpy, stream);
+    }
+    return result;
+}
+
+EGLStreamKHR eglCreateStreamFromFileDescriptorKHR(
+        EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor)
+{
+    clearError();
+
+    const egl_display_ptr dp = validate_display(dpy);
+    if (!dp) return EGL_NO_STREAM_KHR;
+
+    EGLStreamKHR result = EGL_NO_STREAM_KHR;
+    egl_connection_t* const cnx = &gEGLImpl;
+    if (cnx->dso && cnx->egl.eglCreateStreamFromFileDescriptorKHR) {
+        result = cnx->egl.eglCreateStreamFromFileDescriptorKHR(
+                dp->disp.dpy, file_descriptor);
+    }
+    return result;
+}
+
 // ----------------------------------------------------------------------------
 // EGL_EGLEXT_VERSION 15
 // ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_entries.in b/opengl/libs/EGL/egl_entries.in
index 1e27cb6..498b2fc 100644
--- a/opengl/libs/EGL/egl_entries.in
+++ b/opengl/libs/EGL/egl_entries.in
@@ -61,18 +61,18 @@
 
 /* EGL_EGLEXT_VERSION 15 */
 
-//    EGL_ENTRY(EGLStreamKHR, eglCreateStreamKHR,     EGLDisplay, const EGLint *)
-//    EGL_ENTRY(EGLBoolean,   eglDestroyStreamKHR,    EGLDisplay, EGLStreamKHR)
-//    EGL_ENTRY(EGLBoolean,   eglStreamAttribKHR,     EGLDisplay, EGLStreamKHR, EGLenum, EGLint)
-//    EGL_ENTRY(EGLBoolean,   eglQueryStreamKHR,      EGLDisplay, EGLStreamKHR, EGLenum, EGLint *)
-//    EGL_ENTRY(EGLBoolean,   eglQueryStreamu64KHR,   EGLDisplay, EGLStreamKHR, EGLenum, EGLuint64KHR *)
-//    EGL_ENTRY(EGLBoolean,   eglStreamConsumerGLTextureExternalKHR,  EGLDisplay, EGLStreamKHR)
-//    EGL_ENTRY(EGLBoolean,   eglStreamConsumerAcquireKHR,            EGLDisplay, EGLStreamKHR)
-//    EGL_ENTRY(EGLBoolean,   eglStreamConsumerReleaseKHR,            EGLDisplay, EGLStreamKHR)
-//    EGL_ENTRY(EGLSurface,   eglCreateStreamProducerSurfaceKHR,      EGLDisplay, EGLConfig, EGLStreamKHR, const EGLint *)
-//    EGL_ENTRY(EGLBoolean,   eglQueryStreamTimeKHR,  EGLDisplay, EGLStreamKHR, EGLenum, EGLTimeKHR*)
-//    EGL_ENTRY(EGLNativeFileDescriptorKHR,   eglGetStreamFileDescriptorKHR,          EGLDisplay, EGLStreamKHR)
-//    EGL_ENTRY(EGLStreamKHR, eglCreateStreamFromFileDescriptorKHR,   EGLDisplay, EGLNativeFileDescriptorKHR)
+EGL_ENTRY(EGLStreamKHR, eglCreateStreamKHR,     EGLDisplay, const EGLint *)
+EGL_ENTRY(EGLBoolean,   eglDestroyStreamKHR,    EGLDisplay, EGLStreamKHR)
+EGL_ENTRY(EGLBoolean,   eglStreamAttribKHR,     EGLDisplay, EGLStreamKHR, EGLenum, EGLint)
+EGL_ENTRY(EGLBoolean,   eglQueryStreamKHR,      EGLDisplay, EGLStreamKHR, EGLenum, EGLint *)
+EGL_ENTRY(EGLBoolean,   eglQueryStreamu64KHR,   EGLDisplay, EGLStreamKHR, EGLenum, EGLuint64KHR *)
+EGL_ENTRY(EGLBoolean,   eglStreamConsumerGLTextureExternalKHR,  EGLDisplay, EGLStreamKHR)
+EGL_ENTRY(EGLBoolean,   eglStreamConsumerAcquireKHR,            EGLDisplay, EGLStreamKHR)
+EGL_ENTRY(EGLBoolean,   eglStreamConsumerReleaseKHR,            EGLDisplay, EGLStreamKHR)
+EGL_ENTRY(EGLSurface,   eglCreateStreamProducerSurfaceKHR,      EGLDisplay, EGLConfig, EGLStreamKHR, const EGLint *)
+EGL_ENTRY(EGLBoolean,   eglQueryStreamTimeKHR,  EGLDisplay, EGLStreamKHR, EGLenum, EGLTimeKHR*)
+EGL_ENTRY(EGLNativeFileDescriptorKHR,   eglGetStreamFileDescriptorKHR,          EGLDisplay, EGLStreamKHR)
+EGL_ENTRY(EGLStreamKHR, eglCreateStreamFromFileDescriptorKHR,   EGLDisplay, EGLNativeFileDescriptorKHR)
 EGL_ENTRY(EGLint,       eglWaitSyncKHR,         EGLDisplay, EGLSyncKHR, EGLint)
 
 /* ANDROID extensions */
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index d3ee76d..918faa8 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -14,6 +14,9 @@
  ** limitations under the License.
  */
 
+#include <string>
+#include <sstream>
+
 #include <ctype.h>
 #include <stdint.h>
 #include <stdlib.h>
@@ -113,6 +116,14 @@
             temp.append(gl_extensions);
             gl_extensions.setTo(temp);
         }
+
+        // tokenize the supported extensions for the glGetStringi() wrapper
+        std::stringstream ss;
+        std::string str;
+        ss << gl_extensions.string();
+        while (ss >> str) {
+            tokenized_gl_extensions.push(String8(str.c_str()));
+        }
     }
 }
 
diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h
index 518fdec..f5a9f58 100644
--- a/opengl/libs/EGL/egl_object.h
+++ b/opengl/libs/EGL/egl_object.h
@@ -27,6 +27,7 @@
 
 #include <utils/threads.h>
 #include <utils/String8.h>
+#include <utils/Vector.h>
 
 #include <system/window.h>
 
@@ -159,6 +160,7 @@
     egl_connection_t const* cnx;
     int version;
     String8 gl_extensions;
+    Vector<String8> tokenized_gl_extensions;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp
index d5dc012..6034a8e 100644
--- a/opengl/libs/GLES2/gl2.cpp
+++ b/opengl/libs/GLES2/gl2.cpp
@@ -205,13 +205,22 @@
 #undef CALL_GL_API_RETURN
 
 /*
- * glGetString() is special because we expose some extensions in the wrapper
+ * glGetString() and glGetStringi() are special because we expose some
+ * extensions in the wrapper. Also, wrapping glGetXXX() is required because
+ * the value returned for GL_NUM_EXTENSIONS may have been altered by the
+ * injection of the additional extensions.
  */
 
-extern "C" const GLubyte * __glGetString(GLenum name);
+extern "C" {
+    const GLubyte * __glGetString(GLenum name);
+    const GLubyte * __glGetStringi(GLenum name, GLuint index);
+    void __glGetBooleanv(GLenum pname, GLboolean * data);
+    void __glGetFloatv(GLenum pname, GLfloat * data);
+    void __glGetIntegerv(GLenum pname, GLint * data);
+    void __glGetInteger64v(GLenum pname, GLint64 * data);
+}
 
-const GLubyte * glGetString(GLenum name)
-{
+const GLubyte * glGetString(GLenum name) {
     const GLubyte * ret = egl_get_string_for_current_context(name);
     if (ret == NULL) {
         gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
@@ -219,3 +228,64 @@
     }
     return ret;
 }
+
+const GLubyte * glGetStringi(GLenum name, GLuint index) {
+    const GLubyte * ret = egl_get_string_for_current_context(name, index);
+    if (ret == NULL) {
+        gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
+        if(_c) ret = _c->glGetStringi(name, index);
+    }
+    return ret;
+}
+
+void glGetBooleanv(GLenum pname, GLboolean * data) {
+    if (pname == GL_NUM_EXTENSIONS) {
+        int num_exts = egl_get_num_extensions_for_current_context();
+        if (num_exts >= 0) {
+            *data = num_exts > 0 ? GL_TRUE : GL_FALSE;
+            return;
+        }
+    }
+
+    gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
+    if (_c) _c->glGetBooleanv(pname, data);
+}
+
+void glGetFloatv(GLenum pname, GLfloat * data) {
+    if (pname == GL_NUM_EXTENSIONS) {
+        int num_exts = egl_get_num_extensions_for_current_context();
+        if (num_exts >= 0) {
+            *data = (GLfloat)num_exts;
+            return;
+        }
+    }
+
+    gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
+    if (_c) _c->glGetFloatv(pname, data);
+}
+
+void glGetIntegerv(GLenum pname, GLint * data) {
+    if (pname == GL_NUM_EXTENSIONS) {
+        int num_exts = egl_get_num_extensions_for_current_context();
+        if (num_exts >= 0) {
+            *data = (GLint)num_exts;
+            return;
+        }
+    }
+
+    gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
+    if (_c) _c->glGetIntegerv(pname, data);
+}
+
+void glGetInteger64v(GLenum pname, GLint64 * data) {
+    if (pname == GL_NUM_EXTENSIONS) {
+        int num_exts = egl_get_num_extensions_for_current_context();
+        if (num_exts >= 0) {
+            *data = (GLint64)num_exts;
+            return;
+        }
+    }
+
+    gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
+    if (_c) _c->glGetInteger64v(pname, data);
+}
diff --git a/opengl/libs/GLES2/gl2_api.in b/opengl/libs/GLES2/gl2_api.in
index 8363960..09d8b00 100644
--- a/opengl/libs/GLES2/gl2_api.in
+++ b/opengl/libs/GLES2/gl2_api.in
@@ -172,7 +172,7 @@
 GLint API_ENTRY(glGetAttribLocation)(GLuint program, const GLchar * name) {
     CALL_GL_API_RETURN(glGetAttribLocation, program, name);
 }
-void API_ENTRY(glGetBooleanv)(GLenum pname, GLboolean * data) {
+void API_ENTRY(__glGetBooleanv)(GLenum pname, GLboolean * data) {
     CALL_GL_API(glGetBooleanv, pname, data);
 }
 void API_ENTRY(glGetBufferParameteriv)(GLenum target, GLenum pname, GLint * params) {
@@ -181,13 +181,13 @@
 GLenum API_ENTRY(glGetError)(void) {
     CALL_GL_API_RETURN(glGetError);
 }
-void API_ENTRY(glGetFloatv)(GLenum pname, GLfloat * data) {
+void API_ENTRY(__glGetFloatv)(GLenum pname, GLfloat * data) {
     CALL_GL_API(glGetFloatv, pname, data);
 }
 void API_ENTRY(glGetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint * params) {
     CALL_GL_API(glGetFramebufferAttachmentParameteriv, target, attachment, pname, params);
 }
-void API_ENTRY(glGetIntegerv)(GLenum pname, GLint * data) {
+void API_ENTRY(__glGetIntegerv)(GLenum pname, GLint * data) {
     CALL_GL_API(glGetIntegerv, pname, data);
 }
 void API_ENTRY(glGetProgramiv)(GLuint program, GLenum pname, GLint * params) {
@@ -604,7 +604,7 @@
 void API_ENTRY(glClearBufferfi)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) {
     CALL_GL_API(glClearBufferfi, buffer, drawbuffer, depth, stencil);
 }
-const GLubyte * API_ENTRY(glGetStringi)(GLenum name, GLuint index) {
+const GLubyte * API_ENTRY(__glGetStringi)(GLenum name, GLuint index) {
     CALL_GL_API_RETURN(glGetStringi, name, index);
 }
 void API_ENTRY(glCopyBufferSubData)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) {
@@ -649,7 +649,7 @@
 void API_ENTRY(glWaitSync)(GLsync sync, GLbitfield flags, GLuint64 timeout) {
     CALL_GL_API(glWaitSync, sync, flags, timeout);
 }
-void API_ENTRY(glGetInteger64v)(GLenum pname, GLint64 * data) {
+void API_ENTRY(__glGetInteger64v)(GLenum pname, GLint64 * data) {
     CALL_GL_API(glGetInteger64v, pname, data);
 }
 void API_ENTRY(glGetSynciv)(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei * length, GLint * values) {
diff --git a/opengl/libs/egl_impl.h b/opengl/libs/egl_impl.h
index cb0e908..c0990ec 100644
--- a/opengl/libs/egl_impl.h
+++ b/opengl/libs/egl_impl.h
@@ -30,6 +30,9 @@
 // ----------------------------------------------------------------------------
 
 EGLAPI const GLubyte * egl_get_string_for_current_context(GLenum name);
+EGLAPI const GLubyte * egl_get_string_for_current_context(GLenum name,
+                                                          GLuint index);
+EGLAPI GLint egl_get_num_extensions_for_current_context();
 
 // ----------------------------------------------------------------------------
 }; // namespace android
diff --git a/opengl/tools/glgen/src/JType.java b/opengl/tools/glgen/src/JType.java
index c6e227e..5803a44 100644
--- a/opengl/tools/glgen/src/JType.java
+++ b/opengl/tools/glgen/src/JType.java
@@ -191,6 +191,84 @@
         (baseType.indexOf("Buffer") != -1);
     }
 
+    public JType getArrayTypeForTypedBuffer() {
+      if (!isTypedBuffer()) {
+          throw new RuntimeException("Not typed buffer type " + this);
+      }
+      switch (baseType) {
+        case "java.nio.ByteBuffer":
+          return new JType("byte", false, true);
+        case "java.nio.BooleanBuffer":
+          return new JType("boolean", false, true);
+        case "java.nio.ShortBuffer":
+          return new JType("short", false, true);
+        case "java.nio.CharBuffer":
+          return new JType("char", false, true);
+        case "java.nio.IntBuffer":
+          return new JType("int", false, true);
+        case "java.nio.LongBuffer":
+          return new JType("long", false, true);
+        case "java.nio.FloatBuffer":
+          return new JType("float", false, true);
+        case "java.nio.DoubleBuffer":
+          return new JType("double", false, true);
+        default:
+          throw new RuntimeException("Unknown typed buffer type " + this);
+      }
+    }
+
+    public String getArrayGetterForPrimitiveArray() {
+      if (!isArray() || isClass()) {
+          throw new RuntimeException("Not array type " + this);
+      }
+      switch (baseType) {
+        case "byte":
+          return "GetByteArrayElements";
+        case "boolean":
+          return "GetBooleanArrayElements";
+        case "short":
+          return "GetShortArrayElements";
+        case "char":
+          return "GetCharArrayElements";
+        case "int":
+          return "GetIntArrayElements";
+        case "long":
+          return "GetLongArrayElements";
+        case "float":
+          return "GetFloatArrayElements";
+        case "double":
+          return "GetDoubleArrayElements";
+        default:
+          throw new RuntimeException("Unknown array type " + this);
+      }
+    }
+
+    public String getArrayReleaserForPrimitiveArray() {
+      if (!isArray() || isClass()) {
+          throw new RuntimeException("Not array type " + this);
+      }
+      switch (baseType) {
+        case "byte":
+          return "ReleaseByteArrayElements";
+        case "boolean":
+          return "ReleaseBooleanArrayElements";
+        case "short":
+          return "ReleaseShortArrayElements";
+        case "char":
+          return "ReleaseCharArrayElements";
+        case "int":
+          return "ReleaseIntArrayElements";
+        case "long":
+          return "ReleaseLongArrayElements";
+        case "float":
+          return "ReleaseFloatArrayElements";
+        case "double":
+          return "ReleaseDoubleArrayElements";
+        default:
+          throw new RuntimeException("Unknown array type " + this);
+      }
+    }
+
     public boolean isEGLHandle() {
     return !isPrimitive() &&
         (baseType.startsWith("EGL"));
diff --git a/opengl/tools/glgen/src/JniCodeEmitter.java b/opengl/tools/glgen/src/JniCodeEmitter.java
index e51b7a2..1bed05b 100644
--- a/opengl/tools/glgen/src/JniCodeEmitter.java
+++ b/opengl/tools/glgen/src/JniCodeEmitter.java
@@ -812,6 +812,7 @@
         List<Integer> stringArgs = new ArrayList<Integer>();
         int numBufferArgs = 0;
         List<String> bufferArgNames = new ArrayList<String>();
+        List<JType> bufferArgTypes = new ArrayList<JType>();
 
         // Emit JNI signature (arguments)
         //
@@ -835,6 +836,7 @@
                     int cIndex = jfunc.getArgCIndex(i);
                     String cname = cfunc.getArgName(cIndex);
                     bufferArgNames.add(cname);
+                    bufferArgTypes.add(jfunc.getArgType(i));
                     numBufferArgs++;
                 }
             }
@@ -948,12 +950,25 @@
 
         // Emit a single _array or multiple _XXXArray variables
         if (numBufferArgs == 1) {
+            JType bufferType = bufferArgTypes.get(0);
+            if (bufferType.isTypedBuffer()) {
+                String typedArrayType = getJniType(bufferType.getArrayTypeForTypedBuffer());
+                out.println(indent + typedArrayType + " _array = (" + typedArrayType + ") 0;");
+            } else {
                 out.println(indent + "jarray _array = (jarray) 0;");
-                out.println(indent + "jint _bufferOffset = (jint) 0;");
+            }
+            out.println(indent + "jint _bufferOffset = (jint) 0;");
         } else {
             for (int i = 0; i < numBufferArgs; i++) {
-                out.println(indent + "jarray _" + bufferArgNames.get(i) +
-                            "Array = (jarray) 0;");
+                JType bufferType = bufferArgTypes.get(0);
+                if (bufferType.isTypedBuffer()) {
+                    String typedArrayType = getJniType(bufferType.getArrayTypeForTypedBuffer());
+                    out.println(indent + typedArrayType + " _" + bufferArgNames.get(i) +
+                                "Array = (" + typedArrayType + ") 0;");
+                } else {
+                    out.println(indent + "jarray _" + bufferArgNames.get(i) +
+                                "Array = (jarray) 0;");
+                }
                 out.println(indent + "jint _" + bufferArgNames.get(i) +
                             "BufferOffset = (jint) 0;");
             }
@@ -1135,9 +1150,10 @@
                                 "_base = (" +
                                 cfunc.getArgType(cIndex).getDeclaration() +
                                 ")");
+                    String arrayGetter = jfunc.getArgType(idx).getArrayGetterForPrimitiveArray();
                     out.println(indent + "    " +
                                 (mUseCPlusPlus ? "_env" : "(*_env)") +
-                                "->GetPrimitiveArrayCritical(" +
+                                "->" + arrayGetter + "(" +
                                 (mUseCPlusPlus ? "" : "_env, ") +
                                 jfunc.getArgName(idx) +
                                 "_ref, (jboolean *)0);");
@@ -1209,7 +1225,7 @@
                                     cfunc.getArgType(cIndex).getDeclaration() +
                                     ")getPointer(_env, " +
                                     cname +
-                                    "_buf, &" + array + ", &" + remaining + ", &" + bufferOffset +
+                                    "_buf, (jarray*)&" + array + ", &" + remaining + ", &" + bufferOffset +
                                     ");");
                     }
 
@@ -1244,9 +1260,17 @@
                 } else {
                     out.println(indent + "if (" + cname +" == NULL) {");
                 }
-                out.println(indent + indent + "char * _" + cname + "Base = (char *)_env->GetPrimitiveArrayCritical(" + array + ", (jboolean *) 0);");
-                out.println(indent + indent + cname + " = (" +cfunc.getArgType(cIndex).getDeclaration() +") (_" + cname + "Base + " + bufferOffset + ");");
-                out.println(indent + "}");
+                JType argType = jfunc.getArgType(idx);
+                if (argType.isTypedBuffer()) {
+                    String arrayGetter = argType.getArrayTypeForTypedBuffer().getArrayGetterForPrimitiveArray();
+                    out.println(indent + indent + "char * _" + cname + "Base = (char *)_env->" + arrayGetter + "(" + array + ", (jboolean *) 0);");
+                    out.println(indent + indent + cname + " = (" +cfunc.getArgType(cIndex).getDeclaration() +") (_" + cname + "Base + " + bufferOffset + ");");
+                    out.println(indent + "}");
+                } else {
+                    out.println(indent + indent + "char * _" + cname + "Base = (char *)_env->GetPrimitiveArrayCritical(" + array + ", (jboolean *) 0);");
+                    out.println(indent + indent + cname + " = (" +cfunc.getArgType(cIndex).getDeclaration() +") (_" + cname + "Base + " + bufferOffset + ");");
+                    out.println(indent + "}");
+                }
              }
         }
 
@@ -1336,12 +1360,13 @@
                     // the need to write back to the Java array
                     out.println(indent +
                                 "if (" + jfunc.getArgName(idx) + "_base) {");
+                    String arrayReleaser = jfunc.getArgType(idx).getArrayReleaserForPrimitiveArray();
                     out.println(indent + indent +
                                 (mUseCPlusPlus ? "_env" : "(*_env)") +
-                                "->ReleasePrimitiveArrayCritical(" +
+                                "->" + arrayReleaser + "(" +
                                 (mUseCPlusPlus ? "" : "_env, ") +
                                 jfunc.getArgName(idx) + "_ref, " +
-                                cfunc.getArgName(cIndex) +
+                                "(j" + jfunc.getArgType(idx).getBaseType() + "*)" + cfunc.getArgName(cIndex) +
                                 "_base,");
                     out.println(indent + indent + indent +
                                 (cfunc.getArgType(cIndex).isConst() ?
@@ -1350,17 +1375,32 @@
                     out.println(indent + "}");
                 } else if (jfunc.getArgType(idx).isBuffer()) {
                     if (! isPointerFunc) {
+                        JType argType = jfunc.getArgType(idx);
                         String array = numBufferArgs <= 1 ? "_array" :
                             "_" + cfunc.getArgName(cIndex) + "Array";
                         out.println(indent + "if (" + array + ") {");
-                        out.println(indent + indent +
-                                    "releasePointer(_env, " + array + ", " +
-                                    cfunc.getArgName(cIndex) +
-                                    ", " +
-                                    (cfunc.getArgType(cIndex).isConst() ?
-                                     "JNI_FALSE" : (emitExceptionCheck ?
-                                     "_exception ? JNI_FALSE : JNI_TRUE" : "JNI_TRUE")) +
-                                    ");");
+                        if (argType.isTypedBuffer()) {
+                            String arrayReleaser =
+                                argType.getArrayTypeForTypedBuffer().getArrayReleaserForPrimitiveArray();
+                            out.println(indent + indent +
+                                "_env->" + arrayReleaser + "(" + array + ", " +
+                                "(j" + argType.getArrayTypeForTypedBuffer().getBaseType() + "*)" +
+                                cfunc.getArgName(cIndex) +
+                                ", " +
+                                (cfunc.getArgType(cIndex).isConst() ?
+                                    "JNI_ABORT" : (emitExceptionCheck ?
+                                        "_exception ? JNI_ABORT : 0" : "0")) +
+                                ");");
+                        } else {
+                            out.println(indent + indent +
+                                "releasePointer(_env, " + array + ", " +
+                                cfunc.getArgName(cIndex) +
+                                ", " +
+                                (cfunc.getArgType(cIndex).isConst() ?
+                                    "JNI_FALSE" : (emitExceptionCheck ?
+                                        "_exception ? JNI_FALSE : JNI_TRUE" : "JNI_TRUE")) +
+                                ");");
+                        }
                         out.println(indent + "}");
                     }
                 }
diff --git a/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.cpp b/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.cpp
index f09c171..6199637 100755
--- a/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.cpp
+++ b/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.cpp
@@ -27,7 +27,7 @@
     }
     _remaining = _env->GetArrayLength(attrib_list_ref) - offset;
     attrib_list_base = (EGLint *)
-        _env->GetPrimitiveArrayCritical(attrib_list_ref, (jboolean *)0);
+        _env->GetIntArrayElements(attrib_list_ref, (jboolean *)0);
     attrib_list = attrib_list_base + offset;
     attrib_list_sentinel = false;
     for (int i = _remaining - 1; i >= 0; i--)  {
@@ -53,7 +53,7 @@
 
 exit:
     if (attrib_list_base) {
-        _env->ReleasePrimitiveArrayCritical(attrib_list_ref, attrib_list_base,
+        _env->ReleaseIntArrayElements(attrib_list_ref, attrib_list_base,
             JNI_ABORT);
     }
     if (_exception) {
@@ -71,4 +71,3 @@
     }
     return android_eglCreatePbufferFromClientBuffer(_env, _this, dpy, buftype, buffer, config, attrib_list_ref, offset);
 }
-
diff --git a/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp b/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp
index 0b6bf58..cc7b85d 100644
--- a/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp
+++ b/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp
@@ -41,7 +41,7 @@
 
     _remaining = _env->GetArrayLength(attrib_list_ref) - offset;
     attrib_list_base = (EGLint *)
-        _env->GetPrimitiveArrayCritical(attrib_list_ref, (jboolean *)0);
+        _env->GetIntArrayElements(attrib_list_ref, (jboolean *)0);
     attrib_list = attrib_list_base + offset;
     attrib_list_sentinel = 0;
     for (int i = _remaining - 1; i >= 0; i--)  {
@@ -66,7 +66,7 @@
 
 exit:
     if (attrib_list_base) {
-        _env->ReleasePrimitiveArrayCritical(attrib_list_ref, attrib_list_base,
+        _env->ReleaseIntArrayElements(attrib_list_ref, attrib_list_base,
             JNI_ABORT);
     }
     if (_exception) {
@@ -123,7 +123,7 @@
 
     _remaining = _env->GetArrayLength(attrib_list_ref) - offset;
     attrib_list_base = (EGLint *)
-        _env->GetPrimitiveArrayCritical(attrib_list_ref, (jboolean *)0);
+        _env->GetIntArrayElements(attrib_list_ref, (jboolean *)0);
     attrib_list = attrib_list_base + offset;
     attrib_list_sentinel = 0;
     for (int i = _remaining - 1; i >= 0; i--)  {
@@ -148,7 +148,7 @@
 
 exit:
     if (attrib_list_base) {
-        _env->ReleasePrimitiveArrayCritical(attrib_list_ref, attrib_list_base,
+        _env->ReleaseIntArrayElements(attrib_list_ref, attrib_list_base,
             JNI_ABORT);
     }
     if (_exception) {
diff --git a/opengl/tools/glgen/stubs/gles11/common.cpp b/opengl/tools/glgen/stubs/gles11/common.cpp
index f7bcb9d..18ec5e3 100644
--- a/opengl/tools/glgen/stubs/gles11/common.cpp
+++ b/opengl/tools/glgen/stubs/gles11/common.cpp
@@ -100,6 +100,116 @@
     return NULL;
 }
 
+class ByteArrayGetter {
+public:
+    static void* Get(JNIEnv* _env, jbyteArray array, jboolean* is_copy) {
+        return _env->GetByteArrayElements(array, is_copy);
+    }
+};
+class BooleanArrayGetter {
+public:
+    static void* Get(JNIEnv* _env, jbooleanArray array, jboolean* is_copy) {
+        return _env->GetBooleanArrayElements(array, is_copy);
+    }
+};
+class CharArrayGetter {
+public:
+    static void* Get(JNIEnv* _env, jcharArray array, jboolean* is_copy) {
+        return _env->GetCharArrayElements(array, is_copy);
+    }
+};
+class ShortArrayGetter {
+public:
+    static void* Get(JNIEnv* _env, jshortArray array, jboolean* is_copy) {
+        return _env->GetShortArrayElements(array, is_copy);
+    }
+};
+class IntArrayGetter {
+public:
+    static void* Get(JNIEnv* _env, jintArray array, jboolean* is_copy) {
+        return _env->GetIntArrayElements(array, is_copy);
+    }
+};
+class LongArrayGetter {
+public:
+    static void* Get(JNIEnv* _env, jlongArray array, jboolean* is_copy) {
+        return _env->GetLongArrayElements(array, is_copy);
+    }
+};
+class FloatArrayGetter {
+public:
+    static void* Get(JNIEnv* _env, jfloatArray array, jboolean* is_copy) {
+        return _env->GetFloatArrayElements(array, is_copy);
+    }
+};
+class DoubleArrayGetter {
+public:
+    static void* Get(JNIEnv* _env, jdoubleArray array, jboolean* is_copy) {
+        return _env->GetDoubleArrayElements(array, is_copy);
+    }
+};
+
+template<typename JTYPEARRAY, typename ARRAYGETTER>
+static void*
+getArrayPointer(JNIEnv *_env, JTYPEARRAY array, jboolean* is_copy) {
+    return ARRAYGETTER::Get(_env, array, is_copy);
+}
+
+class ByteArrayReleaser {
+public:
+    static void Release(JNIEnv* _env, jbyteArray array, jbyte* data, jboolean commit) {
+        _env->ReleaseByteArrayElements(array, data, commit ? 0 : JNI_ABORT);
+    }
+};
+class BooleanArrayReleaser {
+public:
+    static void Release(JNIEnv* _env, jbooleanArray array, jboolean* data, jboolean commit) {
+        _env->ReleaseBooleanArrayElements(array, data, commit ? 0 : JNI_ABORT);
+    }
+};
+class CharArrayReleaser {
+public:
+    static void Release(JNIEnv* _env, jcharArray array, jchar* data, jboolean commit) {
+        _env->ReleaseCharArrayElements(array, data, commit ? 0 : JNI_ABORT);
+    }
+};
+class ShortArrayReleaser {
+public:
+    static void Release(JNIEnv* _env, jshortArray array, jshort* data, jboolean commit) {
+        _env->ReleaseShortArrayElements(array, data, commit ? 0 : JNI_ABORT);
+    }
+};
+class IntArrayReleaser {
+public:
+    static void Release(JNIEnv* _env, jintArray array, jint* data, jboolean commit) {
+        _env->ReleaseIntArrayElements(array, data, commit ? 0 : JNI_ABORT);
+    }
+};
+class LongArrayReleaser {
+public:
+    static void Release(JNIEnv* _env, jlongArray array, jlong* data, jboolean commit) {
+        _env->ReleaseLongArrayElements(array, data, commit ? 0 : JNI_ABORT);
+    }
+};
+class FloatArrayReleaser {
+public:
+    static void Release(JNIEnv* _env, jfloatArray array, jfloat* data, jboolean commit) {
+        _env->ReleaseFloatArrayElements(array, data, commit ? 0 : JNI_ABORT);
+    }
+};
+class DoubleArrayReleaser {
+public:
+    static void Release(JNIEnv* _env, jdoubleArray array, jdouble* data, jboolean commit) {
+        _env->ReleaseDoubleArrayElements(array, data, commit ? 0 : JNI_ABORT);
+    }
+};
+
+template<typename JTYPEARRAY, typename NTYPEARRAY, typename ARRAYRELEASER>
+static void
+releaseArrayPointer(JNIEnv *_env, JTYPEARRAY array, NTYPEARRAY data, jboolean commit) {
+    ARRAYRELEASER::Release(_env, array, data, commit);
+}
+
 static void
 releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit)
 {
@@ -203,7 +313,8 @@
     return needed;
 }
 
-template <typename JTYPEARRAY, typename CTYPE, void GET(GLenum, CTYPE*)>
+template <typename JTYPEARRAY, typename ARRAYGETTER, typename NTYPEARRAY,
+          typename ARRAYRELEASER, typename CTYPE, void GET(GLenum, CTYPE*)>
 static void
 get
   (JNIEnv *_env, jobject _this, jint pname, JTYPEARRAY params_ref, jint offset) {
@@ -238,8 +349,8 @@
         _exceptionMessage = "length - offset < needed";
         goto exit;
     }
-    params_base = (CTYPE *)
-        _env->GetPrimitiveArrayCritical(params_ref, (jboolean *)0);
+    params_base = (CTYPE *) getArrayPointer<JTYPEARRAY, ARRAYGETTER>(
+        _env, params_ref, (jboolean *)0);
     params = params_base + offset;
 
     GET(
@@ -249,8 +360,8 @@
 
 exit:
     if (params_base) {
-        _env->ReleasePrimitiveArrayCritical(params_ref, params_base,
-            _exception ? JNI_ABORT: 0);
+        releaseArrayPointer<JTYPEARRAY, NTYPEARRAY, ARRAYRELEASER>(
+            _env, params_ref, params_base, !_exception);
     }
     if (_exception) {
         jniThrowException(_env, _exceptionType, _exceptionMessage);
@@ -258,20 +369,21 @@
 }
 
 
-template <typename CTYPE, void GET(GLenum, CTYPE*)>
+template <typename CTYPE, typename JTYPEARRAY, typename ARRAYGETTER, typename NTYPEARRAY,
+          typename ARRAYRELEASER, void GET(GLenum, CTYPE*)>
 static void
 getarray
   (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
     jint _exception = 0;
     const char * _exceptionType;
     const char * _exceptionMessage;
-    jarray _array = (jarray) 0;
+    JTYPEARRAY _array = (JTYPEARRAY) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     CTYPE *params = (CTYPE *) 0;
     int _needed = 0;
 
-    params = (CTYPE *)getPointer(_env, params_buf, &_array, &_remaining, &_bufferOffset);
+    params = (CTYPE *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     _remaining /= sizeof(CTYPE);    // convert from bytes to item count
     _needed = getNeededCount(pname);
     // if we didn't find this pname, we just assume the user passed
@@ -284,7 +396,8 @@
         goto exit;
     }
     if (params == NULL) {
-        char * _paramsBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        char * _paramsBase = (char *) getArrayPointer<JTYPEARRAY, ARRAYGETTER>(
+            _env, _array, (jboolean *) 0);
         params = (CTYPE *) (_paramsBase + _bufferOffset);
     }
     GET(
@@ -294,7 +407,8 @@
 
 exit:
     if (_array) {
-        releasePointer(_env, _array, params, _exception ? JNI_FALSE : JNI_TRUE);
+        releaseArrayPointer<JTYPEARRAY, NTYPEARRAY, ARRAYRELEASER>(
+            _env, _array, (NTYPEARRAY)params, _exception ? JNI_FALSE : JNI_TRUE);
     }
     if (_exception) {
         jniThrowException(_env, _exceptionType, _exceptionMessage);
diff --git a/opengl/tools/glgen/stubs/gles11/glDrawElementsInstanced.cpp b/opengl/tools/glgen/stubs/gles11/glDrawElementsInstanced.cpp
index d844152..86decfb 100644
--- a/opengl/tools/glgen/stubs/gles11/glDrawElementsInstanced.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glDrawElementsInstanced.cpp
@@ -36,4 +36,3 @@
         (GLsizei)instanceCount
     );
 }
-
diff --git a/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.cpp b/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.cpp
index 7d414d8..a8d63d9 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.cpp
@@ -32,7 +32,7 @@
     }
     _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset;
     length_base = (GLsizei *)
-        _env->GetPrimitiveArrayCritical(length_ref, (jboolean *)0);
+        _env->GetIntArrayElements(length_ref, (jboolean *)0);
     length = length_base + lengthOffset;
 
     if (!size_ref) {
@@ -49,7 +49,7 @@
     }
     _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset;
     size_base = (GLint *)
-        _env->GetPrimitiveArrayCritical(size_ref, (jboolean *)0);
+        _env->GetIntArrayElements(size_ref, (jboolean *)0);
     size = size_base + sizeOffset;
 
     if (!type_ref) {
@@ -66,7 +66,7 @@
     }
     _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset;
     type_base = (GLenum *)
-        _env->GetPrimitiveArrayCritical(type_ref, (jboolean *)0);
+        _env->GetIntArrayElements(type_ref, (jboolean *)0);
     type = type_base + typeOffset;
 
     if (!name_ref) {
@@ -83,7 +83,7 @@
     }
     _nameRemaining = _env->GetArrayLength(name_ref) - nameOffset;
     name_base = (char *)
-        _env->GetPrimitiveArrayCritical(name_ref, (jboolean *)0);
+        _env->GetByteArrayElements(name_ref, (jboolean *)0);
     name = name_base + nameOffset;
 
     glGetActiveAttrib(
@@ -98,19 +98,19 @@
 
 exit:
     if (name_base) {
-        _env->ReleasePrimitiveArrayCritical(name_ref, name_base,
+        _env->ReleaseByteArrayElements(name_ref, (jbyte*)name_base,
             _exception ? JNI_ABORT: 0);
     }
     if (type_base) {
-        _env->ReleasePrimitiveArrayCritical(type_ref, type_base,
+        _env->ReleaseIntArrayElements(type_ref, (jint*)type_base,
             _exception ? JNI_ABORT: 0);
     }
     if (size_base) {
-        _env->ReleasePrimitiveArrayCritical(size_ref, size_base,
+        _env->ReleaseIntArrayElements(size_ref, (jint*)size_base,
             _exception ? JNI_ABORT: 0);
     }
     if (length_base) {
-        _env->ReleasePrimitiveArrayCritical(length_ref, length_base,
+        _env->ReleaseIntArrayElements(length_ref, (jint*)length_base,
             _exception ? JNI_ABORT: 0);
     }
     if (_exception) {
@@ -122,11 +122,11 @@
 static void
 android_glGetActiveAttrib__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B
   (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jobject length_buf, jobject size_buf, jobject type_buf, jbyte name) {
-    jarray _lengthArray = (jarray) 0;
+    jintArray _lengthArray = (jintArray) 0;
     jint _lengthBufferOffset = (jint) 0;
-    jarray _sizeArray = (jarray) 0;
+    jintArray _sizeArray = (jintArray) 0;
     jint _sizeBufferOffset = (jint) 0;
-    jarray _typeArray = (jarray) 0;
+    jintArray _typeArray = (jintArray) 0;
     jint _typeBufferOffset = (jint) 0;
     jint _lengthRemaining;
     GLsizei *length = (GLsizei *) 0;
@@ -135,19 +135,19 @@
     jint _typeRemaining;
     GLenum *type = (GLenum *) 0;
 
-    length = (GLsizei *)getPointer(_env, length_buf, &_lengthArray, &_lengthRemaining, &_lengthBufferOffset);
-    size = (GLint *)getPointer(_env, size_buf, &_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
-    type = (GLenum *)getPointer(_env, type_buf, &_typeArray, &_typeRemaining, &_typeBufferOffset);
+    length = (GLsizei *)getPointer(_env, length_buf, (jarray*)&_lengthArray, &_lengthRemaining, &_lengthBufferOffset);
+    size = (GLint *)getPointer(_env, size_buf, (jarray*)&_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
+    type = (GLenum *)getPointer(_env, type_buf, (jarray*)&_typeArray, &_typeRemaining, &_typeBufferOffset);
     if (length == NULL) {
-        char * _lengthBase = (char *)_env->GetPrimitiveArrayCritical(_lengthArray, (jboolean *) 0);
+        char * _lengthBase = (char *)_env->GetIntArrayElements(_lengthArray, (jboolean *) 0);
         length = (GLsizei *) (_lengthBase + _lengthBufferOffset);
     }
     if (size == NULL) {
-        char * _sizeBase = (char *)_env->GetPrimitiveArrayCritical(_sizeArray, (jboolean *) 0);
+        char * _sizeBase = (char *)_env->GetIntArrayElements(_sizeArray, (jboolean *) 0);
         size = (GLint *) (_sizeBase + _sizeBufferOffset);
     }
     if (type == NULL) {
-        char * _typeBase = (char *)_env->GetPrimitiveArrayCritical(_typeArray, (jboolean *) 0);
+        char * _typeBase = (char *)_env->GetIntArrayElements(_typeArray, (jboolean *) 0);
         type = (GLenum *) (_typeBase + _typeBufferOffset);
     }
     glGetActiveAttrib(
@@ -160,13 +160,13 @@
         reinterpret_cast<char *>(name)
     );
     if (_typeArray) {
-        releasePointer(_env, _typeArray, type, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _typeArray, (jint*)type, JNI_TRUE);
     }
     if (_sizeArray) {
-        releasePointer(_env, _sizeArray, size, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _sizeArray, (jint*)size, JNI_TRUE);
     }
     if (_lengthArray) {
-        releasePointer(_env, _lengthArray, length, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _lengthArray, (jint*)length, JNI_TRUE);
     }
 }
 
@@ -211,7 +211,7 @@
     }
     _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset;
     size_base = (GLint *)
-        _env->GetPrimitiveArrayCritical(size_ref, (jboolean *)0);
+        _env->GetIntArrayElements(size_ref, (jboolean *)0);
     size = size_base + sizeOffset;
 
     if (!type_ref) {
@@ -228,7 +228,7 @@
     }
     _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset;
     type_base = (GLenum *)
-        _env->GetPrimitiveArrayCritical(type_ref, (jboolean *)0);
+        _env->GetIntArrayElements(type_ref, (jboolean *)0);
     type = type_base + typeOffset;
 
     glGetActiveAttrib(
@@ -242,11 +242,11 @@
     );
 exit:
     if (type_base) {
-        _env->ReleasePrimitiveArrayCritical(type_ref, type_base,
+        _env->ReleaseIntArrayElements(type_ref, (jint*)type_base,
             _exception ? JNI_ABORT: 0);
     }
     if (size_base) {
-        _env->ReleasePrimitiveArrayCritical(size_ref, size_base,
+        _env->ReleaseIntArrayElements(size_ref, (jint*)size_base,
             _exception ? JNI_ABORT: 0);
     }
     if (_exception != 1) {
@@ -269,9 +269,9 @@
 static jstring
 android_glGetActiveAttrib2
   (JNIEnv *_env, jobject _this, jint program, jint index, jobject size_buf, jobject type_buf) {
-    jarray _sizeArray = (jarray) 0;
+    jintArray _sizeArray = (jintArray) 0;
     jint _sizeBufferOffset = (jint) 0;
-    jarray _typeArray = (jarray) 0;
+    jintArray _typeArray = (jintArray) 0;
     jint _typeBufferOffset = (jint) 0;
     jint _lengthRemaining;
     GLsizei *length = (GLsizei *) 0;
@@ -294,14 +294,14 @@
         return NULL;
     }
 
-    size = (GLint *)getPointer(_env, size_buf, &_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
-    type = (GLenum *)getPointer(_env, type_buf, &_typeArray, &_typeRemaining, &_typeBufferOffset);
+    size = (GLint *)getPointer(_env, size_buf, (jarray*)&_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
+    type = (GLenum *)getPointer(_env, type_buf, (jarray*)&_typeArray, &_typeRemaining, &_typeBufferOffset);
     if (size == NULL) {
-        char * _sizeBase = (char *)_env->GetPrimitiveArrayCritical(_sizeArray, (jboolean *) 0);
+        char * _sizeBase = (char *)_env->GetIntArrayElements(_sizeArray, (jboolean *) 0);
         size = (GLint *) (_sizeBase + _sizeBufferOffset);
     }
     if (type == NULL) {
-        char * _typeBase = (char *)_env->GetPrimitiveArrayCritical(_typeArray, (jboolean *) 0);
+        char * _typeBase = (char *)_env->GetIntArrayElements(_typeArray, (jboolean *) 0);
         type = (GLenum *) (_typeBase + _typeBufferOffset);
     }
     glGetActiveAttrib(
@@ -315,10 +315,10 @@
     );
 
     if (_typeArray) {
-        releasePointer(_env, _typeArray, type, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _typeArray, (jint*)type, JNI_TRUE);
     }
     if (_sizeArray) {
-        releasePointer(_env, _sizeArray, size, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _sizeArray, (jint*)size, JNI_TRUE);
     }
     result = _env->NewStringUTF(buf);
     if (buf) {
diff --git a/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.cpp b/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.cpp
index a7376ba..68e8389 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.cpp
@@ -32,7 +32,7 @@
     }
     _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset;
     length_base = (GLsizei *)
-        _env->GetPrimitiveArrayCritical(length_ref, (jboolean *)0);
+        _env->GetIntArrayElements(length_ref, (jboolean *)0);
     length = length_base + lengthOffset;
 
     if (!size_ref) {
@@ -49,7 +49,7 @@
     }
     _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset;
     size_base = (GLint *)
-        _env->GetPrimitiveArrayCritical(size_ref, (jboolean *)0);
+        _env->GetIntArrayElements(size_ref, (jboolean *)0);
     size = size_base + sizeOffset;
 
     if (!type_ref) {
@@ -66,7 +66,7 @@
     }
     _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset;
     type_base = (GLenum *)
-        _env->GetPrimitiveArrayCritical(type_ref, (jboolean *)0);
+        _env->GetIntArrayElements(type_ref, (jboolean *)0);
     type = type_base + typeOffset;
 
     if (!name_ref) {
@@ -83,7 +83,7 @@
     }
     _nameRemaining = _env->GetArrayLength(name_ref) - nameOffset;
     name_base = (char *)
-        _env->GetPrimitiveArrayCritical(name_ref, (jboolean *)0);
+        _env->GetByteArrayElements(name_ref, (jboolean *)0);
     name = name_base + nameOffset;
 
     glGetActiveUniform(
@@ -98,19 +98,19 @@
 
 exit:
     if (name_base) {
-        _env->ReleasePrimitiveArrayCritical(name_ref, name_base,
+        _env->ReleaseByteArrayElements(name_ref, (jbyte*)name_base,
             _exception ? JNI_ABORT: 0);
     }
     if (type_base) {
-        _env->ReleasePrimitiveArrayCritical(type_ref, type_base,
+        _env->ReleaseIntArrayElements(type_ref, (jint*)type_base,
             _exception ? JNI_ABORT: 0);
     }
     if (size_base) {
-        _env->ReleasePrimitiveArrayCritical(size_ref, size_base,
+        _env->ReleaseIntArrayElements(size_ref, (jint*)size_base,
             _exception ? JNI_ABORT: 0);
     }
     if (length_base) {
-        _env->ReleasePrimitiveArrayCritical(length_ref, length_base,
+        _env->ReleaseIntArrayElements(length_ref, (jint*)length_base,
             _exception ? JNI_ABORT: 0);
     }
     if (_exception) {
@@ -122,11 +122,11 @@
 static void
 android_glGetActiveUniform__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B
   (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jobject length_buf, jobject size_buf, jobject type_buf, jbyte name) {
-    jarray _lengthArray = (jarray) 0;
+    jintArray _lengthArray = (jintArray) 0;
     jint _lengthBufferOffset = (jint) 0;
-    jarray _sizeArray = (jarray) 0;
+    jintArray _sizeArray = (jintArray) 0;
     jint _sizeBufferOffset = (jint) 0;
-    jarray _typeArray = (jarray) 0;
+    jintArray _typeArray = (jintArray) 0;
     jint _typeBufferOffset = (jint) 0;
     jint _lengthRemaining;
     GLsizei *length = (GLsizei *) 0;
@@ -135,19 +135,19 @@
     jint _typeRemaining;
     GLenum *type = (GLenum *) 0;
 
-    length = (GLsizei *)getPointer(_env, length_buf, &_lengthArray, &_lengthRemaining, &_lengthBufferOffset);
-    size = (GLint *)getPointer(_env, size_buf, &_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
-    type = (GLenum *)getPointer(_env, type_buf, &_typeArray, &_typeRemaining, &_typeBufferOffset);
+    length = (GLsizei *)getPointer(_env, length_buf, (jarray*)&_lengthArray, &_lengthRemaining, &_lengthBufferOffset);
+    size = (GLint *)getPointer(_env, size_buf, (jarray*)&_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
+    type = (GLenum *)getPointer(_env, type_buf, (jarray*)&_typeArray, &_typeRemaining, &_typeBufferOffset);
     if (length == NULL) {
-        char * _lengthBase = (char *)_env->GetPrimitiveArrayCritical(_lengthArray, (jboolean *) 0);
+        char * _lengthBase = (char *)_env->GetIntArrayElements(_lengthArray, (jboolean *) 0);
         length = (GLsizei *) (_lengthBase + _lengthBufferOffset);
     }
     if (size == NULL) {
-        char * _sizeBase = (char *)_env->GetPrimitiveArrayCritical(_sizeArray, (jboolean *) 0);
+        char * _sizeBase = (char *)_env->GetIntArrayElements(_sizeArray, (jboolean *) 0);
         size = (GLint *) (_sizeBase + _sizeBufferOffset);
     }
     if (type == NULL) {
-        char * _typeBase = (char *)_env->GetPrimitiveArrayCritical(_typeArray, (jboolean *) 0);
+        char * _typeBase = (char *)_env->GetIntArrayElements(_typeArray, (jboolean *) 0);
         type = (GLenum *) (_typeBase + _typeBufferOffset);
     }
     glGetActiveUniform(
@@ -160,13 +160,13 @@
         reinterpret_cast<char *>(name)
     );
     if (_typeArray) {
-        releasePointer(_env, _typeArray, type, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _typeArray, (jint*)type, JNI_TRUE);
     }
     if (_sizeArray) {
-        releasePointer(_env, _sizeArray, size, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _sizeArray, (jint*)size, JNI_TRUE);
     }
     if (_lengthArray) {
-        releasePointer(_env, _lengthArray, length, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _lengthArray, (jint*)length, JNI_TRUE);
     }
 }
 
@@ -214,7 +214,7 @@
     }
     _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset;
     size_base = (GLint *)
-        _env->GetPrimitiveArrayCritical(size_ref, (jboolean *)0);
+        _env->GetIntArrayElements(size_ref, (jboolean *)0);
     size = size_base + sizeOffset;
 
     if (!type_ref) {
@@ -231,7 +231,7 @@
     }
     _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset;
     type_base = (GLenum *)
-        _env->GetPrimitiveArrayCritical(type_ref, (jboolean *)0);
+        _env->GetIntArrayElements(type_ref, (jboolean *)0);
     type = type_base + typeOffset;
 
     glGetActiveUniform(
@@ -246,11 +246,11 @@
 
 exit:
     if (type_base) {
-        _env->ReleasePrimitiveArrayCritical(type_ref, type_base,
+        _env->ReleaseIntArrayElements(type_ref, (jint*)type_base,
             _exception ? JNI_ABORT: 0);
     }
     if (size_base) {
-        _env->ReleasePrimitiveArrayCritical(size_ref, size_base,
+        _env->ReleaseIntArrayElements(size_ref, (jint*)size_base,
             _exception ? JNI_ABORT: 0);
     }
     if (_exception != 1) {
@@ -272,9 +272,9 @@
 static jstring
 android_glGetActiveUniform2
   (JNIEnv *_env, jobject _this, jint program, jint index, jobject size_buf, jobject type_buf) {
-    jarray _sizeArray = (jarray) 0;
+    jintArray _sizeArray = (jintArray) 0;
     jint _sizeBufferOffset = (jint) 0;
-    jarray _typeArray = (jarray) 0;
+    jintArray _typeArray = (jintArray) 0;
     jint _typeBufferOffset = (jint) 0;
     jint _sizeRemaining;
     GLint *size = (GLint *) 0;
@@ -294,15 +294,15 @@
         return NULL;
     }
 
-    size = (GLint *)getPointer(_env, size_buf, &_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
-    type = (GLenum *)getPointer(_env, type_buf, &_typeArray, &_typeRemaining, &_typeBufferOffset);
+    size = (GLint *)getPointer(_env, size_buf, (jarray*)&_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
+    type = (GLenum *)getPointer(_env, type_buf, (jarray*)&_typeArray, &_typeRemaining, &_typeBufferOffset);
 
     if (size == NULL) {
-        char * _sizeBase = (char *)_env->GetPrimitiveArrayCritical(_sizeArray, (jboolean *) 0);
+        char * _sizeBase = (char *)_env->GetIntArrayElements(_sizeArray, (jboolean *) 0);
         size = (GLint *) (_sizeBase + _sizeBufferOffset);
     }
     if (type == NULL) {
-        char * _typeBase = (char *)_env->GetPrimitiveArrayCritical(_typeArray, (jboolean *) 0);
+        char * _typeBase = (char *)_env->GetIntArrayElements(_typeArray, (jboolean *) 0);
         type = (GLenum *) (_typeBase + _typeBufferOffset);
     }
     glGetActiveUniform(
@@ -316,10 +316,10 @@
     );
 
     if (_typeArray) {
-        releasePointer(_env, _typeArray, type, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _typeArray, (jint*)type, JNI_TRUE);
     }
     if (_sizeArray) {
-        releasePointer(_env, _sizeArray, size, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _sizeArray, (jint*)size, JNI_TRUE);
     }
     result = _env->NewStringUTF(buf);
     if (buf) {
diff --git a/opengl/tools/glgen/stubs/gles11/glGetActiveUniformBlockName.cpp b/opengl/tools/glgen/stubs/gles11/glGetActiveUniformBlockName.cpp
index bb6ae7c..6104c84 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetActiveUniformBlockName.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetActiveUniformBlockName.cpp
@@ -25,7 +25,7 @@
         goto exit;
     }
     _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset;
-    _length_base = (GLsizei*)_env->GetPrimitiveArrayCritical(
+    _length_base = (GLsizei*)_env->GetIntArrayElements(
             length_ref, (jboolean*)0);
     _length = _length_base + lengthOffset;
 
@@ -42,7 +42,7 @@
         goto exit;
     }
     _nameRemaining = _env->GetArrayLength(name_ref) - nameOffset;
-    _name_base = (GLchar*)_env->GetPrimitiveArrayCritical(
+    _name_base = (GLchar*)_env->GetByteArrayElements(
             name_ref, (jboolean*)0);
     _name = _name_base + nameOffset;
 
@@ -56,11 +56,11 @@
 
 exit:
     if (_name_base) {
-        _env->ReleasePrimitiveArrayCritical(name_ref, _name_base,
+        _env->ReleaseByteArrayElements(name_ref, (jbyte*)_name_base,
             _exception ? JNI_ABORT: 0);
     }
     if (_length_base) {
-        _env->ReleasePrimitiveArrayCritical(length_ref, _length_base,
+        _env->ReleaseIntArrayElements(length_ref, (jint*)_length_base,
             _exception ? JNI_ABORT: 0);
     }
     if (_exception) {
@@ -124,4 +124,3 @@
     free(name);
     return result;
 }
-
diff --git a/opengl/tools/glgen/stubs/gles11/glGetBooleanv.cpp b/opengl/tools/glgen/stubs/gles11/glGetBooleanv.cpp
index 00c52af..7874bd8 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetBooleanv.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetBooleanv.cpp
@@ -2,12 +2,14 @@
 static void
 android_glGetBooleanv__I_3ZI
   (JNIEnv *_env, jobject _this, jint pname, jbooleanArray params_ref, jint offset) {
-    get<jbooleanArray, GLboolean, glGetBooleanv>(_env, _this, pname, params_ref, offset);
+    get<jbooleanArray, BooleanArrayGetter, jboolean*, BooleanArrayReleaser, GLboolean, glGetBooleanv>(
+        _env, _this, pname, params_ref, offset);
 }
 
 /* void glGetBooleanv ( GLenum pname, GLboolean *params ) */
 static void
 android_glGetBooleanv__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
-    getarray<GLboolean, glGetBooleanv>(_env, _this, pname, params_buf);
+    getarray<GLboolean, jintArray, IntArrayGetter, jint*, IntArrayReleaser, glGetBooleanv>(
+        _env, _this, pname, params_buf);
 }
diff --git a/opengl/tools/glgen/stubs/gles11/glGetFloatv.cpp b/opengl/tools/glgen/stubs/gles11/glGetFloatv.cpp
index 71c399d..2f41fd1 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetFloatv.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetFloatv.cpp
@@ -2,12 +2,14 @@
 static void
 android_glGetFloatv__I_3FI
   (JNIEnv *_env, jobject _this, jint pname, jfloatArray params_ref, jint offset) {
-    get<jfloatArray, GLfloat, glGetFloatv>(_env, _this, pname, params_ref, offset);
+    get<jfloatArray, FloatArrayGetter, jfloat*, FloatArrayReleaser, GLfloat, glGetFloatv>(
+        _env, _this, pname, params_ref, offset);
 }
 
 /* void glGetFloatv ( GLenum pname, GLfloat *params ) */
 static void
 android_glGetFloatv__ILjava_nio_FloatBuffer_2
   (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
-    getarray<GLfloat, glGetFloatv>(_env, _this, pname, params_buf);
+    getarray<GLfloat, jfloatArray, FloatArrayGetter, jfloat*, FloatArrayReleaser, glGetFloatv>(
+        _env, _this, pname, params_buf);
 }
diff --git a/opengl/tools/glgen/stubs/gles11/glGetIntegerv.cpp b/opengl/tools/glgen/stubs/gles11/glGetIntegerv.cpp
index 9000ece..c960f31 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetIntegerv.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetIntegerv.cpp
@@ -2,13 +2,14 @@
 static void
 android_glGetIntegerv__I_3II
   (JNIEnv *_env, jobject _this, jint pname, jintArray params_ref, jint offset) {
-    get<jintArray, GLint, glGetIntegerv>(_env, _this, pname, params_ref, offset);
+    get<jintArray, IntArrayGetter, jint*, IntArrayReleaser, GLint, glGetIntegerv>(
+        _env, _this, pname, params_ref, offset);
 }
 
 /* void glGetIntegerv ( GLenum pname, GLint *params ) */
 static void
 android_glGetIntegerv__ILjava_nio_IntBuffer_2
   (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
-    getarray<GLint, glGetIntegerv>(_env, _this, pname, params_buf);
+    getarray<GLint, jintArray, IntArrayGetter, jint*, IntArrayReleaser, glGetIntegerv>(
+        _env, _this, pname, params_buf);
 }
-
diff --git a/opengl/tools/glgen/stubs/gles11/glGetShaderSource.cpp b/opengl/tools/glgen/stubs/gles11/glGetShaderSource.cpp
index c995d9c..d9808ef 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetShaderSource.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetShaderSource.cpp
@@ -26,7 +26,7 @@
     }
     _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset;
     length_base = (GLsizei *)
-        _env->GetPrimitiveArrayCritical(length_ref, (jboolean *)0);
+        _env->GetIntArrayElements(length_ref, (jboolean *)0);
     length = length_base + lengthOffset;
 
     if (!source_ref) {
@@ -43,7 +43,7 @@
     }
     _sourceRemaining = _env->GetArrayLength(source_ref) - sourceOffset;
     source_base = (char *)
-        _env->GetPrimitiveArrayCritical(source_ref, (jboolean *)0);
+        _env->GetByteArrayElements(source_ref, (jboolean *)0);
     source = source_base + sourceOffset;
 
     glGetShaderSource(
@@ -55,11 +55,11 @@
 
 exit:
     if (source_base) {
-        _env->ReleasePrimitiveArrayCritical(source_ref, source_base,
+        _env->ReleaseByteArrayElements(source_ref, (jbyte*)source_base,
             _exception ? JNI_ABORT: 0);
     }
     if (length_base) {
-        _env->ReleasePrimitiveArrayCritical(length_ref, length_base,
+        _env->ReleaseIntArrayElements(length_ref, (jint*)length_base,
             _exception ? JNI_ABORT: 0);
     }
     if (_exception) {
@@ -71,14 +71,14 @@
 static void
 android_glGetShaderSource__IILjava_nio_IntBuffer_2B
   (JNIEnv *_env, jobject _this, jint shader, jint bufsize, jobject length_buf, jbyte source) {
-    jarray _array = (jarray) 0;
+    jintArray _array = (jintArray) 0;
     jint _bufferOffset = (jint) 0;
     jint _remaining;
     GLsizei *length = (GLsizei *) 0;
 
-    length = (GLsizei *)getPointer(_env, length_buf, &_array, &_remaining, &_bufferOffset);
+    length = (GLsizei *)getPointer(_env, length_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
     if (length == NULL) {
-        char * _lengthBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+        char * _lengthBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
         length = (GLsizei *) (_lengthBase + _bufferOffset);
     }
     glGetShaderSource(
@@ -88,7 +88,7 @@
         reinterpret_cast<char *>(source)
     );
     if (_array) {
-        releasePointer(_env, _array, length, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _array, (jint*)length, JNI_TRUE);
     }
 }
 
diff --git a/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.cpp b/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.cpp
index a977693..cb656c8 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.cpp
@@ -32,7 +32,7 @@
     }
     _lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset;
     length_base = (GLsizei *)
-        _env->GetPrimitiveArrayCritical(length_ref, (jboolean *)0);
+        _env->GetIntArrayElements(length_ref, (jboolean *)0);
     length = length_base + lengthOffset;
 
     if (!size_ref) {
@@ -49,7 +49,7 @@
     }
     _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset;
     size_base = (GLint *)
-        _env->GetPrimitiveArrayCritical(size_ref, (jboolean *)0);
+        _env->GetIntArrayElements(size_ref, (jboolean *)0);
     size = size_base + sizeOffset;
 
     if (!type_ref) {
@@ -66,7 +66,7 @@
     }
     _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset;
     type_base = (GLenum *)
-        _env->GetPrimitiveArrayCritical(type_ref, (jboolean *)0);
+        _env->GetIntArrayElements(type_ref, (jboolean *)0);
     type = type_base + typeOffset;
 
     if (!name_ref) {
@@ -83,7 +83,7 @@
     }
     _nameRemaining = _env->GetArrayLength(name_ref) - nameOffset;
     name_base = (char *)
-        _env->GetPrimitiveArrayCritical(name_ref, (jboolean *)0);
+        _env->GetByteArrayElements(name_ref, (jboolean *)0);
     name = name_base + nameOffset;
 
     glGetTransformFeedbackVarying(
@@ -98,19 +98,19 @@
 
 exit:
     if (name_base) {
-        _env->ReleasePrimitiveArrayCritical(name_ref, name_base,
+        _env->ReleaseByteArrayElements(name_ref, (jbyte*)name_base,
             _exception ? JNI_ABORT: 0);
     }
     if (type_base) {
-        _env->ReleasePrimitiveArrayCritical(type_ref, type_base,
+        _env->ReleaseIntArrayElements(type_ref, (jint*)type_base,
             _exception ? JNI_ABORT: 0);
     }
     if (size_base) {
-        _env->ReleasePrimitiveArrayCritical(size_ref, size_base,
+        _env->ReleaseIntArrayElements(size_ref, (jint*)size_base,
             _exception ? JNI_ABORT: 0);
     }
     if (length_base) {
-        _env->ReleasePrimitiveArrayCritical(length_ref, length_base,
+        _env->ReleaseIntArrayElements(length_ref, (jint*)length_base,
             _exception ? JNI_ABORT: 0);
     }
     if (_exception) {
@@ -122,11 +122,11 @@
 static void
 android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B
   (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jobject length_buf, jobject size_buf, jobject type_buf, jbyte name) {
-    jarray _lengthArray = (jarray) 0;
+    jintArray _lengthArray = (jintArray) 0;
     jint _lengthBufferOffset = (jint) 0;
-    jarray _sizeArray = (jarray) 0;
+    jintArray _sizeArray = (jintArray) 0;
     jint _sizeBufferOffset = (jint) 0;
-    jarray _typeArray = (jarray) 0;
+    jintArray _typeArray = (jintArray) 0;
     jint _typeBufferOffset = (jint) 0;
     jint _lengthRemaining;
     GLsizei *length = (GLsizei *) 0;
@@ -135,19 +135,19 @@
     jint _typeRemaining;
     GLenum *type = (GLenum *) 0;
 
-    length = (GLsizei *)getPointer(_env, length_buf, &_lengthArray, &_lengthRemaining, &_lengthBufferOffset);
-    size = (GLint *)getPointer(_env, size_buf, &_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
-    type = (GLenum *)getPointer(_env, type_buf, &_typeArray, &_typeRemaining, &_typeBufferOffset);
+    length = (GLsizei *)getPointer(_env, length_buf, (jarray*)&_lengthArray, &_lengthRemaining, &_lengthBufferOffset);
+    size = (GLint *)getPointer(_env, size_buf, (jarray*)&_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
+    type = (GLenum *)getPointer(_env, type_buf, (jarray*)&_typeArray, &_typeRemaining, &_typeBufferOffset);
     if (length == NULL) {
-        char * _lengthBase = (char *)_env->GetPrimitiveArrayCritical(_lengthArray, (jboolean *) 0);
+        char * _lengthBase = (char *)_env->GetIntArrayElements(_lengthArray, (jboolean *) 0);
         length = (GLsizei *) (_lengthBase + _lengthBufferOffset);
     }
     if (size == NULL) {
-        char * _sizeBase = (char *)_env->GetPrimitiveArrayCritical(_sizeArray, (jboolean *) 0);
+        char * _sizeBase = (char *)_env->GetIntArrayElements(_sizeArray, (jboolean *) 0);
         size = (GLint *) (_sizeBase + _sizeBufferOffset);
     }
     if (type == NULL) {
-        char * _typeBase = (char *)_env->GetPrimitiveArrayCritical(_typeArray, (jboolean *) 0);
+        char * _typeBase = (char *)_env->GetIntArrayElements(_typeArray, (jboolean *) 0);
         type = (GLenum *) (_typeBase + _typeBufferOffset);
     }
     glGetTransformFeedbackVarying(
@@ -164,13 +164,13 @@
         (char *)static_cast<uintptr_t>(name)
     );
     if (_typeArray) {
-        releasePointer(_env, _typeArray, type, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _typeArray, (jint*)type, JNI_TRUE);
     }
     if (_sizeArray) {
-        releasePointer(_env, _sizeArray, size, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _sizeArray, (jint*)size, JNI_TRUE);
     }
     if (_lengthArray) {
-        releasePointer(_env, _lengthArray, length, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _lengthArray, (jint*)length, JNI_TRUE);
     }
 }
 
@@ -215,7 +215,7 @@
     }
     _sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset;
     size_base = (GLint *)
-        _env->GetPrimitiveArrayCritical(size_ref, (jboolean *)0);
+        _env->GetIntArrayElements(size_ref, (jboolean *)0);
     size = size_base + sizeOffset;
 
     if (!type_ref) {
@@ -232,7 +232,7 @@
     }
     _typeRemaining = _env->GetArrayLength(type_ref) - typeOffset;
     type_base = (GLenum *)
-        _env->GetPrimitiveArrayCritical(type_ref, (jboolean *)0);
+        _env->GetIntArrayElements(type_ref, (jboolean *)0);
     type = type_base + typeOffset;
 
     glGetTransformFeedbackVarying(
@@ -246,11 +246,11 @@
     );
 exit:
     if (type_base) {
-        _env->ReleasePrimitiveArrayCritical(type_ref, type_base,
+        _env->ReleaseIntArrayElements(type_ref, (jint*)type_base,
             _exception ? JNI_ABORT: 0);
     }
     if (size_base) {
-        _env->ReleasePrimitiveArrayCritical(size_ref, size_base,
+        _env->ReleaseIntArrayElements(size_ref, (jint*)size_base,
             _exception ? JNI_ABORT: 0);
     }
     if (_exception != 1) {
@@ -273,9 +273,9 @@
 static jstring
 android_glGetTransformFeedbackVarying2
   (JNIEnv *_env, jobject _this, jint program, jint index, jobject size_buf, jobject type_buf) {
-    jarray _sizeArray = (jarray) 0;
+    jintArray _sizeArray = (jintArray) 0;
     jint _sizeBufferOffset = (jint) 0;
-    jarray _typeArray = (jarray) 0;
+    jintArray _typeArray = (jintArray) 0;
     jint _typeBufferOffset = (jint) 0;
     jint _lengthRemaining;
     GLsizei *length = (GLsizei *) 0;
@@ -298,14 +298,14 @@
         return NULL;
     }
 
-    size = (GLint *)getPointer(_env, size_buf, &_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
-    type = (GLenum *)getPointer(_env, type_buf, &_typeArray, &_typeRemaining, &_typeBufferOffset);
+    size = (GLint *)getPointer(_env, size_buf, (jarray*)&_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
+    type = (GLenum *)getPointer(_env, type_buf, (jarray*)&_typeArray, &_typeRemaining, &_typeBufferOffset);
     if (size == NULL) {
-        char * _sizeBase = (char *)_env->GetPrimitiveArrayCritical(_sizeArray, (jboolean *) 0);
+        char * _sizeBase = (char *)_env->GetIntArrayElements(_sizeArray, (jboolean *) 0);
         size = (GLint *) (_sizeBase + _sizeBufferOffset);
     }
     if (type == NULL) {
-        char * _typeBase = (char *)_env->GetPrimitiveArrayCritical(_typeArray, (jboolean *) 0);
+        char * _typeBase = (char *)_env->GetIntArrayElements(_typeArray, (jboolean *) 0);
         type = (GLenum *) (_typeBase + _typeBufferOffset);
     }
     glGetTransformFeedbackVarying(
@@ -319,10 +319,10 @@
     );
 
     if (_typeArray) {
-        releasePointer(_env, _typeArray, type, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _typeArray, (jint*)type, JNI_TRUE);
     }
     if (_sizeArray) {
-        releasePointer(_env, _sizeArray, size, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _sizeArray, (jint*)size, JNI_TRUE);
     }
     result = _env->NewStringUTF(buf);
     if (buf) {
diff --git a/opengl/tools/glgen/stubs/gles11/glGetUniformIndices.cpp b/opengl/tools/glgen/stubs/gles11/glGetUniformIndices.cpp
index fb137ab..13ef01e 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetUniformIndices.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetUniformIndices.cpp
@@ -49,7 +49,7 @@
         _exceptionMessage = "not enough space in uniformIndices";
         goto exit;
     }
-    _indices_base = (GLuint*)_env->GetPrimitiveArrayCritical(
+    _indices_base = (GLuint*)_env->GetIntArrayElements(
             uniformIndices_ref, 0);
     _indices = _indices_base + uniformIndicesOffset;
 
@@ -57,8 +57,8 @@
 
 exit:
     if (_indices_base) {
-        _env->ReleasePrimitiveArrayCritical(uniformIndices_ref, _indices_base,
-                _exception ? JNI_ABORT : 0);
+        _env->ReleaseIntArrayElements(uniformIndices_ref, (jint*)_indices_base,
+            _exception ? JNI_ABORT : 0);
     }
     for (_i = _count - 1; _i >= 0; _i--) {
         if (_names[_i]) {
@@ -85,7 +85,7 @@
     jint _count = 0;
     jint _i;
     const char** _names = NULL;
-    jarray _uniformIndicesArray = (jarray)0;
+    jintArray _uniformIndicesArray = (jintArray)0;
     jint _uniformIndicesRemaining;
     jint _uniformIndicesOffset = 0;
     GLuint* _indices = NULL;
@@ -118,11 +118,11 @@
     }
 
     _indices = (GLuint*)getPointer(_env, uniformIndices_buf,
-            &_uniformIndicesArray, &_uniformIndicesRemaining,
+            (jarray*)&_uniformIndicesArray, &_uniformIndicesRemaining,
             &_uniformIndicesOffset);
     if (!_indices) {
-        _indicesBase = (char*)_env->GetPrimitiveArrayCritical(
-                _uniformIndicesArray, 0);
+        _indicesBase = (char*)_env->GetIntArrayElements(
+            _uniformIndicesArray, 0);
         _indices = (GLuint*)(_indicesBase + _uniformIndicesOffset);
     }
     if (_uniformIndicesRemaining < _count) {
@@ -136,7 +136,8 @@
 
 exit:
     if (_uniformIndicesArray) {
-        releasePointer(_env, _uniformIndicesArray, _indicesBase, JNI_TRUE);
+        releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(
+            _env, _uniformIndicesArray, (jint*)_indicesBase, JNI_TRUE);
     }
     for (_i = _count - 1; _i >= 0; _i--) {
         if (_names[_i]) {
@@ -151,4 +152,3 @@
         jniThrowException(_env, _exceptionType, _exceptionMessage);
     }
 }
-
diff --git a/opengl/tools/glgen2/glgen.py b/opengl/tools/glgen2/glgen.py
index ed6b451..9b30fd1 100755
--- a/opengl/tools/glgen2/glgen.py
+++ b/opengl/tools/glgen2/glgen.py
@@ -86,11 +86,25 @@
     return ', '.join(['"%s", %s' % (p[0], p[1]) for p in params])
 
 
-def overrideSymbolName(sym):
-    # The wrapper intercepts glGetString and (sometimes) calls the generated
-    # __glGetString thunk which dispatches to the driver's glGetString
-    if sym == 'glGetString':
-        return '__glGetString'
+def overrideSymbolName(sym, apiname):
+    # The wrapper intercepts various glGet and glGetString functions and
+    # (sometimes) calls the generated thunk which dispatches to the
+    # driver's implementation
+    wrapped_get_syms = {
+        'gles1' : [
+            'glGetString'
+        ],
+        'gles2' : [
+            'glGetString',
+            'glGetStringi',
+            'glGetBooleanv',
+            'glGetFloatv',
+            'glGetIntegerv',
+            'glGetInteger64v',
+        ],
+    }
+    if sym in wrapped_get_syms.get(apiname):
+        return '__' + sym
     else:
         return sym
 
@@ -115,8 +129,8 @@
         print('%s API_ENTRY(%s)(%s) {\n'
               '    %s(%s%s%s);\n'
               '}'
-              % (rtype, overrideSymbolName(fname), fmtParams(params),
-                 call, fname,
+              % (rtype, overrideSymbolName(fname, self.genOpts.apiname),
+                 fmtParams(params), call, fname,
                  ', ' if len(params) > 0 else '',
                  fmtArgs(params)),
               file=self.outFile)
diff --git a/services/inputflinger/Android.mk b/services/inputflinger/Android.mk
index 1af59a3..ed867d8 100644
--- a/services/inputflinger/Android.mk
+++ b/services/inputflinger/Android.mk
@@ -45,3 +45,5 @@
 LOCAL_MODULE := libinputflinger
 
 include $(BUILD_SHARED_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index 93ce010..6b60c7c 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -131,6 +131,13 @@
         }
     }
 
+    // External stylus gets the pressure axis
+    if (deviceClasses & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
+        if (axis == ABS_PRESSURE) {
+            return INPUT_DEVICE_CLASS_EXTERNAL_STYLUS;
+        }
+    }
+
     // Joystick devices get the rest.
     return deviceClasses & INPUT_DEVICE_CLASS_JOYSTICK;
 }
@@ -1185,6 +1192,16 @@
             && test_bit(ABS_X, device->absBitmask)
             && test_bit(ABS_Y, device->absBitmask)) {
         device->classes |= INPUT_DEVICE_CLASS_TOUCH;
+    // Is this a BT stylus?
+    } else if ((test_bit(ABS_PRESSURE, device->absBitmask) ||
+                test_bit(BTN_TOUCH, device->keyBitmask))
+            && !test_bit(ABS_X, device->absBitmask)
+            && !test_bit(ABS_Y, device->absBitmask)) {
+        device->classes |= INPUT_DEVICE_CLASS_EXTERNAL_STYLUS;
+        // Keyboard will try to claim some of the buttons but we really want to reserve those so we
+        // can fuse it with the touch screen data, so just take them back. Note this means an
+        // external stylus cannot also be a keyboard device.
+        device->classes &= ~INPUT_DEVICE_CLASS_KEYBOARD;
     }
 
     // See if this device is a joystick.
@@ -1279,6 +1296,11 @@
         return -1;
     }
 
+    // Determine whether the device has a mic.
+    if (deviceHasMicLocked(device)) {
+        device->classes |= INPUT_DEVICE_CLASS_MIC;
+    }
+
     // Determine whether the device is external or internal.
     if (isExternalDeviceLocked(device)) {
         device->classes |= INPUT_DEVICE_CLASS_EXTERNAL;
@@ -1293,7 +1315,10 @@
     // Register with epoll.
     struct epoll_event eventItem;
     memset(&eventItem, 0, sizeof(eventItem));
-    eventItem.events = mUsingEpollWakeup ? EPOLLIN : EPOLLIN | EPOLLWAKEUP;
+    eventItem.events = EPOLLIN;
+    if (mUsingEpollWakeup) {
+        eventItem.events |= EPOLLWAKEUP;
+    }
     eventItem.data.u32 = deviceId;
     if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
         ALOGE("Could not add device fd to epoll instance.  errno=%d", errno);
@@ -1412,6 +1437,16 @@
     return device->identifier.bus == BUS_USB || device->identifier.bus == BUS_BLUETOOTH;
 }
 
+bool EventHub::deviceHasMicLocked(Device* device) {
+    if (device->configuration) {
+        bool value;
+        if (device->configuration->tryGetProperty(String8("audio.mic"), value)) {
+            return value;
+        }
+    }
+    return false;
+}
+
 int32_t EventHub::getNextControllerNumberLocked(Device* device) {
     if (mControllerNumbers.isFull()) {
         ALOGI("Maximum number of controllers reached, assigning controller number 0 to device %s",
diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h
index 20179ae..3ec4910 100644
--- a/services/inputflinger/EventHub.h
+++ b/services/inputflinger/EventHub.h
@@ -131,6 +131,12 @@
     /* The input device has a vibrator (supports FF_RUMBLE). */
     INPUT_DEVICE_CLASS_VIBRATOR      = 0x00000200,
 
+    /* The input device has a microphone. */
+    INPUT_DEVICE_CLASS_MIC           = 0x00000400,
+
+    /* The input device is an external stylus (has data we want to fuse with touch data). */
+    INPUT_DEVICE_CLASS_EXTERNAL_STYLUS = 0x00000800,
+
     /* The input device is virtual (not a real device, not part of UI configuration). */
     INPUT_DEVICE_CLASS_VIRTUAL       = 0x40000000,
 
@@ -394,6 +400,7 @@
     status_t loadKeyMapLocked(Device* device);
 
     bool isExternalDeviceLocked(Device* device);
+    bool deviceHasMicLocked(Device* device);
 
     int32_t getNextControllerNumberLocked(Device* device);
     void releaseControllerNumberLocked(Device* device);
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 9157bc1..0fba1bf 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -119,7 +119,7 @@
     return true;
 }
 
-static bool isValidMotionAction(int32_t action, size_t pointerCount) {
+static bool isValidMotionAction(int32_t action, int32_t actionButton, int32_t pointerCount) {
     switch (action & AMOTION_EVENT_ACTION_MASK) {
     case AMOTION_EVENT_ACTION_DOWN:
     case AMOTION_EVENT_ACTION_UP:
@@ -136,14 +136,17 @@
         int32_t index = getMotionEventActionPointerIndex(action);
         return index >= 0 && size_t(index) < pointerCount;
     }
+    case AMOTION_EVENT_ACTION_BUTTON_PRESS:
+    case AMOTION_EVENT_ACTION_BUTTON_RELEASE:
+        return actionButton != 0;
     default:
         return false;
     }
 }
 
-static bool validateMotionEvent(int32_t action, size_t pointerCount,
+static bool validateMotionEvent(int32_t action, int32_t actionButton, size_t pointerCount,
         const PointerProperties* pointerProperties) {
-    if (! isValidMotionAction(action, pointerCount)) {
+    if (! isValidMotionAction(action, actionButton, pointerCount)) {
         ALOGE("Motion event has invalid action code 0x%x", action);
         return false;
     }
@@ -198,7 +201,8 @@
 
 InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
     mPolicy(policy),
-    mPendingEvent(NULL), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
+    mPendingEvent(NULL), mLastDropReason(DROP_REASON_NOT_DROPPED),
+    mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
     mNextUnblockedEvent(NULL),
     mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false),
     mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
@@ -394,6 +398,7 @@
         if (dropReason != DROP_REASON_NOT_DROPPED) {
             dropInboundEventLocked(mPendingEvent, dropReason);
         }
+        mLastDropReason = dropReason;
 
         releasePendingEventLocked();
         *nextWakeupTime = LONG_LONG_MIN;  // force next poll to wake up immediately
@@ -503,7 +508,9 @@
         reason = "inbound event was dropped because the policy consumed it";
         break;
     case DROP_REASON_DISABLED:
-        ALOGI("Dropped event because input dispatch is disabled.");
+        if (mLastDropReason != DROP_REASON_DISABLED) {
+            ALOGI("Dropped event because input dispatch is disabled.");
+        }
         reason = "inbound event was dropped because input dispatch is disabled";
         break;
     case DROP_REASON_APP_SWITCH:
@@ -852,6 +859,13 @@
 
     setInjectionResultLocked(entry, injectionResult);
     if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
+        if (injectionResult != INPUT_EVENT_INJECTION_PERMISSION_DENIED) {
+            CancelationOptions::Mode mode(isPointerEvent ?
+                    CancelationOptions::CANCEL_POINTER_EVENTS :
+                    CancelationOptions::CANCEL_NON_POINTER_EVENTS);
+            CancelationOptions options(mode, "input event injection failed");
+            synthesizeCancelationEventsForMonitorsLocked(options);
+        }
         return true;
     }
 
@@ -874,12 +888,12 @@
 void InputDispatcher::logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry) {
 #if DEBUG_OUTBOUND_EVENT_DETAILS
     ALOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, "
-            "action=0x%x, flags=0x%x, "
-            "metaState=0x%x, buttonState=0x%x, "
+            "action=0x%x, actionButton=0x%x, flags=0x%x, "
+            "metaState=0x%x, buttonState=0x%x,"
             "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld",
             prefix,
             entry->eventTime, entry->deviceId, entry->source, entry->policyFlags,
-            entry->action, entry->flags,
+            entry->action, entry->actionButton, entry->flags,
             entry->metaState, entry->buttonState,
             entry->edgeFlags, entry->xPrecision, entry->yPrecision,
             entry->downTime);
@@ -1981,10 +1995,10 @@
             // Publish the motion event.
             status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
                     motionEntry->deviceId, motionEntry->source,
-                    dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
-                    motionEntry->edgeFlags, motionEntry->metaState, motionEntry->buttonState,
-                    xOffset, yOffset,
-                    motionEntry->xPrecision, motionEntry->yPrecision,
+                    dispatchEntry->resolvedAction, motionEntry->actionButton,
+                    dispatchEntry->resolvedFlags, motionEntry->edgeFlags,
+                    motionEntry->metaState, motionEntry->buttonState,
+                    xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision,
                     motionEntry->downTime, motionEntry->eventTime,
                     motionEntry->pointerCount, motionEntry->pointerProperties,
                     usingCoords);
@@ -2160,6 +2174,13 @@
     }
 }
 
+void InputDispatcher::synthesizeCancelationEventsForMonitorsLocked(
+        const CancelationOptions& options) {
+    for (size_t i = 0; i < mMonitoringChannels.size(); i++) {
+        synthesizeCancelationEventsForInputChannelLocked(mMonitoringChannels[i], options);
+    }
+}
+
 void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked(
         const sp<InputChannel>& channel, const CancelationOptions& options) {
     ssize_t index = getConnectionIndexLocked(channel);
@@ -2298,6 +2319,7 @@
             originalMotionEntry->source,
             originalMotionEntry->policyFlags,
             action,
+            originalMotionEntry->actionButton,
             originalMotionEntry->flags,
             originalMotionEntry->metaState,
             originalMotionEntry->buttonState,
@@ -2432,10 +2454,10 @@
 void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
 #if DEBUG_INBOUND_EVENT_DETAILS
     ALOGD("notifyMotion - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, "
-            "action=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, edgeFlags=0x%x, "
-            "xPrecision=%f, yPrecision=%f, downTime=%lld",
+            "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x,"
+            "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld",
             args->eventTime, args->deviceId, args->source, args->policyFlags,
-            args->action, args->flags, args->metaState, args->buttonState,
+            args->action, args->actionButton, args->flags, args->metaState, args->buttonState,
             args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime);
     for (uint32_t i = 0; i < args->pointerCount; i++) {
         ALOGD("  Pointer %d: id=%d, toolType=%d, "
@@ -2455,7 +2477,8 @@
                 args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
     }
 #endif
-    if (!validateMotionEvent(args->action, args->pointerCount, args->pointerProperties)) {
+    if (!validateMotionEvent(args->action, args->actionButton,
+                args->pointerCount, args->pointerProperties)) {
         return;
     }
 
@@ -2471,9 +2494,9 @@
             mLock.unlock();
 
             MotionEvent event;
-            event.initialize(args->deviceId, args->source, args->action, args->flags,
-                    args->edgeFlags, args->metaState, args->buttonState, 0, 0,
-                    args->xPrecision, args->yPrecision,
+            event.initialize(args->deviceId, args->source, args->action, args->actionButton,
+                    args->flags, args->edgeFlags, args->metaState, args->buttonState,
+                    0, 0, args->xPrecision, args->yPrecision,
                     args->downTime, args->eventTime,
                     args->pointerCount, args->pointerProperties, args->pointerCoords);
 
@@ -2488,7 +2511,8 @@
         // Just enqueue a new motion event.
         MotionEntry* newEntry = new MotionEntry(args->eventTime,
                 args->deviceId, args->source, policyFlags,
-                args->action, args->flags, args->metaState, args->buttonState,
+                args->action, args->actionButton, args->flags,
+                args->metaState, args->buttonState,
                 args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime,
                 args->displayId,
                 args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0);
@@ -2589,7 +2613,8 @@
         int32_t action = motionEvent->getAction();
         size_t pointerCount = motionEvent->getPointerCount();
         const PointerProperties* pointerProperties = motionEvent->getPointerProperties();
-        if (! validateMotionEvent(action, pointerCount, pointerProperties)) {
+        int32_t actionButton = motionEvent->getActionButton();
+        if (! validateMotionEvent(action, actionButton, pointerCount, pointerProperties)) {
             return INPUT_EVENT_INJECTION_FAILED;
         }
 
@@ -2603,7 +2628,7 @@
         const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords();
         firstInjectedEntry = new MotionEntry(*sampleEventTimes,
                 motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags,
-                action, motionEvent->getFlags(),
+                action, actionButton, motionEvent->getFlags(),
                 motionEvent->getMetaState(), motionEvent->getButtonState(),
                 motionEvent->getEdgeFlags(),
                 motionEvent->getXPrecision(), motionEvent->getYPrecision(),
@@ -2616,7 +2641,7 @@
             samplePointerCoords += pointerCount;
             MotionEntry* nextInjectedEntry = new MotionEntry(*sampleEventTimes,
                     motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags,
-                    action, motionEvent->getFlags(),
+                    action, actionButton, motionEvent->getFlags(),
                     motionEvent->getMetaState(), motionEvent->getButtonState(),
                     motionEvent->getEdgeFlags(),
                     motionEvent->getXPrecision(), motionEvent->getYPrecision(),
@@ -3907,18 +3932,18 @@
 
 // --- InputDispatcher::MotionEntry ---
 
-InputDispatcher::MotionEntry::MotionEntry(nsecs_t eventTime,
-        int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags,
-        int32_t metaState, int32_t buttonState,
-        int32_t edgeFlags, float xPrecision, float yPrecision,
-        nsecs_t downTime, int32_t displayId, uint32_t pointerCount,
+InputDispatcher::MotionEntry::MotionEntry(nsecs_t eventTime, int32_t deviceId,
+        uint32_t source, uint32_t policyFlags, int32_t action, int32_t actionButton,
+        int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
+        float xPrecision, float yPrecision, nsecs_t downTime,
+        int32_t displayId, uint32_t pointerCount,
         const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
         float xOffset, float yOffset) :
         EventEntry(TYPE_MOTION, eventTime, policyFlags),
         eventTime(eventTime),
-        deviceId(deviceId), source(source), action(action), flags(flags),
-        metaState(metaState), buttonState(buttonState), edgeFlags(edgeFlags),
-        xPrecision(xPrecision), yPrecision(yPrecision),
+        deviceId(deviceId), source(source), action(action), actionButton(actionButton),
+        flags(flags), metaState(metaState), buttonState(buttonState),
+        edgeFlags(edgeFlags), xPrecision(xPrecision), yPrecision(yPrecision),
         downTime(downTime), displayId(displayId), pointerCount(pointerCount) {
     for (uint32_t i = 0; i < pointerCount; i++) {
         this->pointerProperties[i].copyFrom(pointerProperties[i]);
@@ -3933,10 +3958,10 @@
 }
 
 void InputDispatcher::MotionEntry::appendDescription(String8& msg) const {
-    msg.appendFormat("MotionEvent(deviceId=%d, source=0x%08x, action=%d, "
-            "flags=0x%08x, metaState=0x%08x, buttonState=0x%08x, edgeFlags=0x%08x, "
-            "xPrecision=%.1f, yPrecision=%.1f, displayId=%d, pointers=[",
-            deviceId, source, action, flags, metaState, buttonState, edgeFlags,
+    msg.appendFormat("MotionEvent(deviceId=%d, source=0x%08x, action=%d, actionButton=0x%08x, "
+            "flags=0x%08x, metaState=0x%08x, buttonState=0x%08x, "
+            "edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, displayId=%d, pointers=[",
+            deviceId, source, action, actionButton, flags, metaState, buttonState, edgeFlags,
             xPrecision, yPrecision, displayId);
     for (uint32_t i = 0; i < pointerCount; i++) {
         if (i) {
@@ -4237,7 +4262,7 @@
                     memento.hovering
                             ? AMOTION_EVENT_ACTION_HOVER_EXIT
                             : AMOTION_EVENT_ACTION_CANCEL,
-                    memento.flags, 0, 0, 0,
+                    memento.flags, 0, 0, 0, 0,
                     memento.xPrecision, memento.yPrecision, memento.downTime,
                     memento.displayId,
                     memento.pointerCount, memento.pointerProperties, memento.pointerCoords,
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 8c78a44..98355c6 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -504,6 +504,7 @@
         int32_t deviceId;
         uint32_t source;
         int32_t action;
+        int32_t actionButton;
         int32_t flags;
         int32_t metaState;
         int32_t buttonState;
@@ -518,10 +519,10 @@
 
         MotionEntry(nsecs_t eventTime,
                 int32_t deviceId, uint32_t source, uint32_t policyFlags,
-                int32_t action, int32_t flags,
+                int32_t action, int32_t actionButton, int32_t flags,
                 int32_t metaState, int32_t buttonState, int32_t edgeFlags,
-                float xPrecision, float yPrecision,
-                nsecs_t downTime, int32_t displayId, uint32_t pointerCount,
+                float xPrecision, float yPrecision, nsecs_t downTime,
+                int32_t displayId, uint32_t pointerCount,
                 const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
                 float xOffset, float yOffset);
         virtual void appendDescription(String8& msg) const;
@@ -856,6 +857,8 @@
     Queue<EventEntry> mRecentQueue;
     Queue<CommandEntry> mCommandQueue;
 
+    DropReason mLastDropReason;
+
     void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime);
 
     // Enqueues an inbound event.  Returns true if mLooper->wake() should be called.
@@ -1073,6 +1076,7 @@
 
     void synthesizeCancelationEventsForAllConnectionsLocked(
             const CancelationOptions& options);
+    void synthesizeCancelationEventsForMonitorsLocked(const CancelationOptions& options);
     void synthesizeCancelationEventsForInputChannelLocked(const sp<InputChannel>& channel,
             const CancelationOptions& options);
     void synthesizeCancelationEventsForConnectionLocked(const sp<Connection>& connection,
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index 85bb0ed..dded47d 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -68,12 +68,13 @@
 
 NotifyMotionArgs::NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source,
         uint32_t policyFlags,
-        int32_t action, int32_t flags, int32_t metaState, int32_t buttonState,
-        int32_t edgeFlags, int32_t displayId, uint32_t pointerCount,
+        int32_t action, int32_t actionButton, int32_t flags, int32_t metaState,
+        int32_t buttonState, int32_t edgeFlags, int32_t displayId, uint32_t pointerCount,
         const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
         float xPrecision, float yPrecision, nsecs_t downTime) :
         eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags),
-        action(action), flags(flags), metaState(metaState), buttonState(buttonState),
+        action(action), actionButton(actionButton),
+        flags(flags), metaState(metaState), buttonState(buttonState),
         edgeFlags(edgeFlags), displayId(displayId), pointerCount(pointerCount),
         xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime) {
     for (uint32_t i = 0; i < pointerCount; i++) {
@@ -85,10 +86,9 @@
 NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other) :
         eventTime(other.eventTime), deviceId(other.deviceId), source(other.source),
         policyFlags(other.policyFlags),
-        action(other.action), flags(other.flags),
+        action(other.action), actionButton(other.actionButton), flags(other.flags),
         metaState(other.metaState), buttonState(other.buttonState),
-        edgeFlags(other.edgeFlags), displayId(other.displayId),
-        pointerCount(other.pointerCount),
+        edgeFlags(other.edgeFlags), displayId(other.displayId), pointerCount(other.pointerCount),
         xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime) {
     for (uint32_t i = 0; i < pointerCount; i++) {
         pointerProperties[i].copyFrom(other.pointerProperties[i]);
diff --git a/services/inputflinger/InputListener.h b/services/inputflinger/InputListener.h
index 78ae10f..1ec09ce 100644
--- a/services/inputflinger/InputListener.h
+++ b/services/inputflinger/InputListener.h
@@ -84,6 +84,7 @@
     uint32_t source;
     uint32_t policyFlags;
     int32_t action;
+    int32_t actionButton;
     int32_t flags;
     int32_t metaState;
     int32_t buttonState;
@@ -99,7 +100,8 @@
     inline NotifyMotionArgs() { }
 
     NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags,
-            int32_t action, int32_t flags, int32_t metaState, int32_t buttonState,
+            int32_t action, int32_t actionButton, int32_t flags,
+            int32_t metaState, int32_t buttonState,
             int32_t edgeFlags, int32_t displayId, uint32_t pointerCount,
             const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
             float xPrecision, float yPrecision, nsecs_t downTime);
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index ccf8ced..bd74b02 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -39,12 +39,16 @@
 // Log debug messages about the vibrator.
 #define DEBUG_VIBRATOR 0
 
+// Log debug messages about fusing stylus data.
+#define DEBUG_STYLUS_FUSION 0
+
 #include "InputReader.h"
 
 #include <cutils/log.h>
 #include <input/Keyboard.h>
 #include <input/VirtualKeyMap.h>
 
+#include <inttypes.h>
 #include <stddef.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -65,6 +69,17 @@
 // Maximum number of slots supported when using the slot-based Multitouch Protocol B.
 static const size_t MAX_SLOTS = 32;
 
+// Maximum amount of latency to add to touch events while waiting for data from an
+// external stylus.
+static const nsecs_t EXTERNAL_STYLUS_DATA_TIMEOUT = ms2ns(72);
+
+// Maximum amount of time to wait on touch data before pushing out new pressure data.
+static const nsecs_t TOUCH_DATA_TIMEOUT = ms2ns(20);
+
+// Artificial latency on synthetic events created from stylus data without corresponding touch
+// data.
+static const nsecs_t STYLUS_DATA_LATENCY = ms2ns(10);
+
 // --- Static Functions ---
 
 template<typename T>
@@ -381,6 +396,10 @@
 
     mDevices.add(deviceId, device);
     bumpGenerationLocked();
+
+    if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
+        notifyExternalStylusPresenceChanged();
+    }
 }
 
 void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) {
@@ -403,6 +422,10 @@
                 device->getId(), device->getName().string(), device->getSources());
     }
 
+    if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
+        notifyExternalStylusPresenceChanged();
+    }
+
     device->reset(when);
     delete device;
 }
@@ -417,6 +440,11 @@
         device->setExternal(true);
     }
 
+    // Devices with mics.
+    if (classes & INPUT_DEVICE_CLASS_MIC) {
+        device->setMic(true);
+    }
+
     // Switch-like devices.
     if (classes & INPUT_DEVICE_CLASS_SWITCH) {
         device->addMapper(new SwitchInputMapper(device));
@@ -464,6 +492,11 @@
         device->addMapper(new JoystickInputMapper(device));
     }
 
+    // External stylus-like devices.
+    if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
+        device->addMapper(new ExternalStylusInputMapper(device));
+    }
+
     return device;
 }
 
@@ -534,6 +567,27 @@
     return mGlobalMetaState;
 }
 
+void InputReader::notifyExternalStylusPresenceChanged() {
+    refreshConfigurationLocked(InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE);
+}
+
+void InputReader::getExternalStylusDevicesLocked(Vector<InputDeviceInfo>& outDevices) {
+    for (size_t i = 0; i < mDevices.size(); i++) {
+        InputDevice* device = mDevices.valueAt(i);
+        if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS && !device->isIgnored()) {
+            outDevices.push();
+            device->getDeviceInfo(&outDevices.editTop());
+        }
+    }
+}
+
+void InputReader::dispatchExternalStylusState(const StylusState& state) {
+    for (size_t i = 0; i < mDevices.size(); i++) {
+        InputDevice* device = mDevices.valueAt(i);
+        device->updateExternalStylusState(state);
+    }
+}
+
 void InputReader::disableVirtualKeysUntilLocked(nsecs_t time) {
     mDisableVirtualKeysTimeout = time;
 }
@@ -824,6 +878,15 @@
     return mReader->bumpGenerationLocked();
 }
 
+void InputReader::ContextImpl::getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices) {
+    // lock is already held by whatever called refreshConfigurationLocked
+    mReader->getExternalStylusDevicesLocked(outDevices);
+}
+
+void InputReader::ContextImpl::dispatchExternalStylusState(const StylusState& state) {
+    mReader->dispatchExternalStylusState(state);
+}
+
 InputReaderPolicyInterface* InputReader::ContextImpl::getPolicy() {
     return mReader->mPolicy.get();
 }
@@ -858,7 +921,7 @@
         int32_t controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes) :
         mContext(context), mId(id), mGeneration(generation), mControllerNumber(controllerNumber),
         mIdentifier(identifier), mClasses(classes),
-        mSources(0), mIsExternal(false), mDropUntilNextSync(false) {
+        mSources(0), mIsExternal(false), mHasMic(false), mDropUntilNextSync(false) {
 }
 
 InputDevice::~InputDevice() {
@@ -877,6 +940,7 @@
             deviceInfo.getDisplayName().string());
     dump.appendFormat(INDENT2 "Generation: %d\n", mGeneration);
     dump.appendFormat(INDENT2 "IsExternal: %s\n", toString(mIsExternal));
+    dump.appendFormat(INDENT2 "HasMic:     %s\n", toString(mHasMic));
     dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources());
     dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType());
 
@@ -1006,10 +1070,17 @@
     }
 }
 
+void InputDevice::updateExternalStylusState(const StylusState& state) {
+    size_t numMappers = mMappers.size();
+    for (size_t i = 0; i < numMappers; i++) {
+        InputMapper* mapper = mMappers[i];
+        mapper->updateExternalStylusState(state);
+    }
+}
+
 void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) {
     outDeviceInfo->initialize(mId, mGeneration, mControllerNumber, mIdentifier, mAlias,
-            mIsExternal);
-
+            mIsExternal, mHasMic);
     size_t numMappers = mMappers.size();
     for (size_t i = 0; i < numMappers; i++) {
         InputMapper* mapper = mMappers[i];
@@ -1285,7 +1356,9 @@
 void TouchButtonAccumulator::reset(InputDevice* device) {
     mBtnTouch = device->isKeyPressed(BTN_TOUCH);
     mBtnStylus = device->isKeyPressed(BTN_STYLUS);
-    mBtnStylus2 = device->isKeyPressed(BTN_STYLUS);
+    // BTN_0 is what gets mapped for the HID usage Digitizers.SecondaryBarrelSwitch
+    mBtnStylus2 =
+            device->isKeyPressed(BTN_STYLUS2) || device->isKeyPressed(BTN_0);
     mBtnToolFinger = device->isKeyPressed(BTN_TOOL_FINGER);
     mBtnToolPen = device->isKeyPressed(BTN_TOOL_PEN);
     mBtnToolRubber = device->isKeyPressed(BTN_TOOL_RUBBER);
@@ -1326,6 +1399,7 @@
             mBtnStylus = rawEvent->value;
             break;
         case BTN_STYLUS2:
+        case BTN_0:// BTN_0 is what gets mapped for the HID usage Digitizers.SecondaryBarrelSwitch
             mBtnStylus2 = rawEvent->value;
             break;
         case BTN_TOOL_FINGER:
@@ -1368,10 +1442,10 @@
 uint32_t TouchButtonAccumulator::getButtonState() const {
     uint32_t result = 0;
     if (mBtnStylus) {
-        result |= AMOTION_EVENT_BUTTON_SECONDARY;
+        result |= AMOTION_EVENT_BUTTON_STYLUS_PRIMARY;
     }
     if (mBtnStylus2) {
-        result |= AMOTION_EVENT_BUTTON_TERTIARY;
+        result |= AMOTION_EVENT_BUTTON_STYLUS_SECONDARY;
     }
     return result;
 }
@@ -1801,6 +1875,10 @@
     return 0;
 }
 
+void InputMapper::updateExternalStylusState(const StylusState& state) {
+
+}
+
 void InputMapper::fadePointer() {
 }
 
@@ -1822,6 +1900,12 @@
     }
 }
 
+void InputMapper::dumpStylusState(String8& dump, const StylusState& state) {
+    dump.appendFormat(INDENT4 "When: %" PRId64 "\n", state.when);
+    dump.appendFormat(INDENT4 "Pressure: %f\n", state.pressure);
+    dump.appendFormat(INDENT4 "Button State: 0x%08x\n", state.buttons);
+    dump.appendFormat(INDENT4 "Tool Type: %" PRId32 "\n", state.toolType);
+}
 
 // --- SwitchInputMapper ---
 
@@ -2463,7 +2547,8 @@
     }
     nsecs_t downTime = mDownTime;
     bool buttonsChanged = currentButtonState != lastButtonState;
-    bool buttonsPressed = currentButtonState & ~lastButtonState;
+    int32_t buttonsPressed = currentButtonState & ~lastButtonState;
+    int32_t buttonsReleased = lastButtonState & ~currentButtonState;
 
     float deltaX = mCursorMotionAccumulator.getRelativeX() * mXScale;
     float deltaY = mCursorMotionAccumulator.getRelativeY() * mYScale;
@@ -2539,6 +2624,7 @@
     // Send motion event.
     if (downChanged || moved || scrolled || buttonsChanged) {
         int32_t metaState = mContext->getGlobalMetaState();
+        int32_t buttonState = lastButtonState;
         int32_t motionEventAction;
         if (downChanged) {
             motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
@@ -2548,17 +2634,48 @@
             motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE;
         }
 
+        if (buttonsReleased) {
+            BitSet32 released(buttonsReleased);
+            while (!released.isEmpty()) {
+                int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit());
+                buttonState &= ~actionButton;
+                NotifyMotionArgs releaseArgs(when, getDeviceId(), mSource, policyFlags,
+                        AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
+                        metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+                        displayId, 1, &pointerProperties, &pointerCoords,
+                        mXPrecision, mYPrecision, downTime);
+                getListener()->notifyMotion(&releaseArgs);
+            }
+        }
+
         NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
-                motionEventAction, 0, metaState, currentButtonState, 0,
+                motionEventAction, 0, 0, metaState, currentButtonState,
+                AMOTION_EVENT_EDGE_FLAG_NONE,
                 displayId, 1, &pointerProperties, &pointerCoords,
                 mXPrecision, mYPrecision, downTime);
         getListener()->notifyMotion(&args);
 
+        if (buttonsPressed) {
+            BitSet32 pressed(buttonsPressed);
+            while (!pressed.isEmpty()) {
+                int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit());
+                buttonState |= actionButton;
+                NotifyMotionArgs pressArgs(when, getDeviceId(), mSource, policyFlags,
+                        AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0,
+                        metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+                        displayId, 1, &pointerProperties, &pointerCoords,
+                        mXPrecision, mYPrecision, downTime);
+                getListener()->notifyMotion(&pressArgs);
+            }
+        }
+
+        ALOG_ASSERT(buttonState == currentButtonState);
+
         // Send hover move after UP to tell the application that the mouse is hovering now.
         if (motionEventAction == AMOTION_EVENT_ACTION_UP
                 && mPointerController != NULL) {
             NotifyMotionArgs hoverArgs(when, getDeviceId(), mSource, policyFlags,
-                    AMOTION_EVENT_ACTION_HOVER_MOVE, 0,
+                    AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
                     metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE,
                     displayId, 1, &pointerProperties, &pointerCoords,
                     mXPrecision, mYPrecision, downTime);
@@ -2571,7 +2688,7 @@
             pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
 
             NotifyMotionArgs scrollArgs(when, getDeviceId(), mSource, policyFlags,
-                    AMOTION_EVENT_ACTION_SCROLL, 0, metaState, currentButtonState,
+                    AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, currentButtonState,
                     AMOTION_EVENT_EDGE_FLAG_NONE,
                     displayId, 1, &pointerProperties, &pointerCoords,
                     mXPrecision, mYPrecision, downTime);
@@ -2703,12 +2820,11 @@
     dump.appendFormat(INDENT4 "TiltYCenter: %0.3f\n", mTiltYCenter);
     dump.appendFormat(INDENT4 "TiltYScale: %0.3f\n", mTiltYScale);
 
-    dump.appendFormat(INDENT3 "Last Button State: 0x%08x\n", mLastButtonState);
-
+    dump.appendFormat(INDENT3 "Last Raw Button State: 0x%08x\n", mLastRawState.buttonState);
     dump.appendFormat(INDENT3 "Last Raw Touch: pointerCount=%d\n",
-            mLastRawPointerData.pointerCount);
-    for (uint32_t i = 0; i < mLastRawPointerData.pointerCount; i++) {
-        const RawPointerData::Pointer& pointer = mLastRawPointerData.pointers[i];
+            mLastRawState.rawPointerData.pointerCount);
+    for (uint32_t i = 0; i < mLastRawState.rawPointerData.pointerCount; i++) {
+        const RawPointerData::Pointer& pointer = mLastRawState.rawPointerData.pointers[i];
         dump.appendFormat(INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, "
                 "touchMajor=%d, touchMinor=%d, toolMajor=%d, toolMinor=%d, "
                 "orientation=%d, tiltX=%d, tiltY=%d, distance=%d, "
@@ -2720,11 +2836,13 @@
                 pointer.toolType, toString(pointer.isHovering));
     }
 
+    dump.appendFormat(INDENT3 "Last Cooked Button State: 0x%08x\n", mLastCookedState.buttonState);
     dump.appendFormat(INDENT3 "Last Cooked Touch: pointerCount=%d\n",
-            mLastCookedPointerData.pointerCount);
-    for (uint32_t i = 0; i < mLastCookedPointerData.pointerCount; i++) {
-        const PointerProperties& pointerProperties = mLastCookedPointerData.pointerProperties[i];
-        const PointerCoords& pointerCoords = mLastCookedPointerData.pointerCoords[i];
+            mLastCookedState.cookedPointerData.pointerCount);
+    for (uint32_t i = 0; i < mLastCookedState.cookedPointerData.pointerCount; i++) {
+        const PointerProperties& pointerProperties =
+                mLastCookedState.cookedPointerData.pointerProperties[i];
+        const PointerCoords& pointerCoords = mLastCookedState.cookedPointerData.pointerCoords[i];
         dump.appendFormat(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, pressure=%0.3f, "
                 "touchMajor=%0.3f, touchMinor=%0.3f, toolMajor=%0.3f, toolMinor=%0.3f, "
                 "orientation=%0.3f, tilt=%0.3f, distance=%0.3f, "
@@ -2741,9 +2859,18 @@
                 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TILT),
                 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE),
                 pointerProperties.toolType,
-                toString(mLastCookedPointerData.isHovering(i)));
+                toString(mLastCookedState.cookedPointerData.isHovering(i)));
     }
 
+    dump.append(INDENT3 "Stylus Fusion:\n");
+    dump.appendFormat(INDENT4 "ExternalStylusConnected: %s\n",
+            toString(mExternalStylusConnected));
+    dump.appendFormat(INDENT4 "External Stylus ID: %" PRId64 "\n", mExternalStylusId);
+    dump.appendFormat(INDENT4 "External Stylus Data Timeout: %" PRId64 "\n",
+            mExternalStylusFusionTimeout);
+    dump.append(INDENT3 "External Stylus State:\n");
+    dumpStylusState(dump, mExternalStylusState);
+
     if (mDeviceMode == DEVICE_MODE_POINTER) {
         dump.appendFormat(INDENT3 "Pointer Gesture Detector:\n");
         dump.appendFormat(INDENT4 "XMovementScale: %0.3f\n",
@@ -2781,7 +2908,7 @@
         resolveCalibration();
     }
 
-    if (!changes || (changes & InputReaderConfiguration::TOUCH_AFFINE_TRANSFORMATION)) {
+    if (!changes || (changes & InputReaderConfiguration::CHANGE_TOUCH_AFFINE_TRANSFORMATION)) {
         // Update location calibration to reflect current settings
         updateAffineTransformation();
     }
@@ -2796,7 +2923,8 @@
     bool resetNeeded = false;
     if (!changes || (changes & (InputReaderConfiguration::CHANGE_DISPLAY_INFO
             | InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT
-            | InputReaderConfiguration::CHANGE_SHOW_TOUCHES))) {
+            | InputReaderConfiguration::CHANGE_SHOW_TOUCHES
+            | InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE))) {
         // Configure device sources, surface dimensions, orientation and
         // scaling factors.
         configureSurface(when, &resetNeeded);
@@ -2809,6 +2937,16 @@
     }
 }
 
+void TouchInputMapper::resolveExternalStylusPresence() {
+    Vector<InputDeviceInfo> devices;
+    mContext->getExternalStylusDevices(devices);
+    mExternalStylusConnected = !devices.isEmpty();
+
+    if (!mExternalStylusConnected) {
+        resetExternalStylus();
+    }
+}
+
 void TouchInputMapper::configureParameters() {
     // Use the pointer presentation mode for devices that do not support distinct
     // multitouch.  The spot-based presentation relies on being able to accurately
@@ -2945,9 +3083,15 @@
     dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.slot, "Slot");
 }
 
+bool TouchInputMapper::hasExternalStylus() const {
+    return mExternalStylusConnected;
+}
+
 void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
     int32_t oldDeviceMode = mDeviceMode;
 
+    resolveExternalStylusPresence();
+
     // Determine device mode.
     if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER
             && mConfig.pointerGesturesEnabled) {
@@ -2963,6 +3107,9 @@
         if (hasStylus()) {
             mSource |= AINPUT_SOURCE_STYLUS;
         }
+        if (hasExternalStylus()) {
+            mSource |= AINPUT_SOURCE_BLUETOOTH_STYLUS;
+        }
     } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_NAVIGATION) {
         mSource = AINPUT_SOURCE_TOUCH_NAVIGATION;
         mDeviceMode = DEVICE_MODE_NAVIGATION;
@@ -3705,28 +3852,22 @@
     mWheelXVelocityControl.reset();
     mWheelYVelocityControl.reset();
 
-    mCurrentRawPointerData.clear();
-    mLastRawPointerData.clear();
-    mCurrentCookedPointerData.clear();
-    mLastCookedPointerData.clear();
-    mCurrentButtonState = 0;
-    mLastButtonState = 0;
-    mCurrentRawVScroll = 0;
-    mCurrentRawHScroll = 0;
-    mCurrentFingerIdBits.clear();
-    mLastFingerIdBits.clear();
-    mCurrentStylusIdBits.clear();
-    mLastStylusIdBits.clear();
-    mCurrentMouseIdBits.clear();
-    mLastMouseIdBits.clear();
+    mRawStatesPending.clear();
+    mCurrentRawState.clear();
+    mCurrentCookedState.clear();
+    mLastRawState.clear();
+    mLastCookedState.clear();
     mPointerUsage = POINTER_USAGE_NONE;
     mSentHoverEnter = false;
+    mHavePointerIds = false;
+    mCurrentMotionAborted = false;
     mDownTime = 0;
 
     mCurrentVirtualKey.down = false;
 
     mPointerGesture.reset();
     mPointerSimple.reset();
+    resetExternalStylus();
 
     if (mPointerController != NULL) {
         mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
@@ -3736,6 +3877,18 @@
     InputMapper::reset(when);
 }
 
+void TouchInputMapper::resetExternalStylus() {
+    mExternalStylusState.clear();
+    mExternalStylusId = -1;
+    mExternalStylusFusionTimeout = LLONG_MAX;
+    mExternalStylusDataPending = false;
+}
+
+void TouchInputMapper::clearStylusDataPendingFlags() {
+    mExternalStylusDataPending = false;
+    mExternalStylusFusionTimeout = LLONG_MAX;
+}
+
 void TouchInputMapper::process(const RawEvent* rawEvent) {
     mCursorButtonAccumulator.process(rawEvent);
     mCursorScrollAccumulator.process(rawEvent);
@@ -3747,155 +3900,288 @@
 }
 
 void TouchInputMapper::sync(nsecs_t when) {
+    const RawState* last = mRawStatesPending.isEmpty() ?
+            &mCurrentRawState : &mRawStatesPending.top();
+
+    // Push a new state.
+    mRawStatesPending.push();
+    RawState* next = &mRawStatesPending.editTop();
+    next->clear();
+    next->when = when;
+
     // Sync button state.
-    mCurrentButtonState = mTouchButtonAccumulator.getButtonState()
+    next->buttonState = mTouchButtonAccumulator.getButtonState()
             | mCursorButtonAccumulator.getButtonState();
 
-    // Sync scroll state.
-    mCurrentRawVScroll = mCursorScrollAccumulator.getRelativeVWheel();
-    mCurrentRawHScroll = mCursorScrollAccumulator.getRelativeHWheel();
+    // Sync scroll
+    next->rawVScroll = mCursorScrollAccumulator.getRelativeVWheel();
+    next->rawHScroll = mCursorScrollAccumulator.getRelativeHWheel();
     mCursorScrollAccumulator.finishSync();
 
-    // Sync touch state.
-    bool havePointerIds = true;
-    mCurrentRawPointerData.clear();
-    syncTouch(when, &havePointerIds);
+    // Sync touch
+    syncTouch(when, next);
+
+    // Assign pointer ids.
+    if (!mHavePointerIds) {
+        assignPointerIds(last, next);
+    }
 
 #if DEBUG_RAW_EVENTS
-    if (!havePointerIds) {
-        ALOGD("syncTouch: pointerCount %d -> %d, no pointer ids",
-                mLastRawPointerData.pointerCount,
-                mCurrentRawPointerData.pointerCount);
-    } else {
-        ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, "
-                "hovering ids 0x%08x -> 0x%08x",
-                mLastRawPointerData.pointerCount,
-                mCurrentRawPointerData.pointerCount,
-                mLastRawPointerData.touchingIdBits.value,
-                mCurrentRawPointerData.touchingIdBits.value,
-                mLastRawPointerData.hoveringIdBits.value,
-                mCurrentRawPointerData.hoveringIdBits.value);
-    }
+    ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, "
+            "hovering ids 0x%08x -> 0x%08x",
+            last->rawPointerData.pointerCount,
+            next->rawPointerData.pointerCount,
+            last->rawPointerData.touchingIdBits.value,
+            next->rawPointerData.touchingIdBits.value,
+            last->rawPointerData.hoveringIdBits.value,
+            next->rawPointerData.hoveringIdBits.value);
 #endif
 
-    // Reset state that we will compute below.
-    mCurrentFingerIdBits.clear();
-    mCurrentStylusIdBits.clear();
-    mCurrentMouseIdBits.clear();
-    mCurrentCookedPointerData.clear();
+    processRawTouches(false /*timeout*/);
+}
 
+void TouchInputMapper::processRawTouches(bool timeout) {
     if (mDeviceMode == DEVICE_MODE_DISABLED) {
         // Drop all input if the device is disabled.
-        mCurrentRawPointerData.clear();
-        mCurrentButtonState = 0;
+        mCurrentRawState.clear();
+        mRawStatesPending.clear();
+        return;
+    }
+
+    // Drain any pending touch states. The invariant here is that the mCurrentRawState is always
+    // valid and must go through the full cook and dispatch cycle. This ensures that anything
+    // touching the current state will only observe the events that have been dispatched to the
+    // rest of the pipeline.
+    const size_t N = mRawStatesPending.size();
+    size_t count;
+    for(count = 0; count < N; count++) {
+        const RawState& next = mRawStatesPending[count];
+
+        // A failure to assign the stylus id means that we're waiting on stylus data
+        // and so should defer the rest of the pipeline.
+        if (assignExternalStylusId(next, timeout)) {
+            break;
+        }
+
+        // All ready to go.
+        clearStylusDataPendingFlags();
+        mCurrentRawState.copyFrom(next);
+        if (mCurrentRawState.when < mLastRawState.when) {
+            mCurrentRawState.when = mLastRawState.when;
+        }
+        cookAndDispatch(mCurrentRawState.when);
+    }
+    if (count != 0) {
+        mRawStatesPending.removeItemsAt(0, count);
+    }
+
+    if (mExternalStylusDataPending) {
+        if (timeout) {
+            nsecs_t when = mExternalStylusFusionTimeout - STYLUS_DATA_LATENCY;
+            clearStylusDataPendingFlags();
+            mCurrentRawState.copyFrom(mLastRawState);
+#if DEBUG_STYLUS_FUSION
+            ALOGD("Timeout expired, synthesizing event with new stylus data");
+#endif
+            cookAndDispatch(when);
+        } else if (mExternalStylusFusionTimeout == LLONG_MAX) {
+            mExternalStylusFusionTimeout = mExternalStylusState.when + TOUCH_DATA_TIMEOUT;
+            getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout);
+        }
+    }
+}
+
+void TouchInputMapper::cookAndDispatch(nsecs_t when) {
+    // Always start with a clean state.
+    mCurrentCookedState.clear();
+
+    // Apply stylus buttons to current raw state.
+    applyExternalStylusButtonState(when);
+
+    // Handle policy on initial down or hover events.
+    bool initialDown = mLastRawState.rawPointerData.pointerCount == 0
+            && mCurrentRawState.rawPointerData.pointerCount != 0;
+
+    uint32_t policyFlags = 0;
+    bool buttonsPressed = mCurrentRawState.buttonState & ~mLastRawState.buttonState;
+    if (initialDown || buttonsPressed) {
+        // If this is a touch screen, hide the pointer on an initial down.
+        if (mDeviceMode == DEVICE_MODE_DIRECT) {
+            getContext()->fadePointer();
+        }
+
+        if (mParameters.wake) {
+            policyFlags |= POLICY_FLAG_WAKE;
+        }
+    }
+
+    // Consume raw off-screen touches before cooking pointer data.
+    // If touches are consumed, subsequent code will not receive any pointer data.
+    if (consumeRawTouches(when, policyFlags)) {
+        mCurrentRawState.rawPointerData.clear();
+    }
+
+    // Cook pointer data.  This call populates the mCurrentCookedState.cookedPointerData structure
+    // with cooked pointer data that has the same ids and indices as the raw data.
+    // The following code can use either the raw or cooked data, as needed.
+    cookPointerData();
+
+    // Apply stylus pressure to current cooked state.
+    applyExternalStylusTouchState(when);
+
+    // Synthesize key down from raw buttons if needed.
+    synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource,
+            policyFlags, mLastCookedState.buttonState, mCurrentCookedState.buttonState);
+
+    // Dispatch the touches either directly or by translation through a pointer on screen.
+    if (mDeviceMode == DEVICE_MODE_POINTER) {
+        for (BitSet32 idBits(mCurrentRawState.rawPointerData.touchingIdBits);
+                !idBits.isEmpty(); ) {
+            uint32_t id = idBits.clearFirstMarkedBit();
+            const RawPointerData::Pointer& pointer =
+                    mCurrentRawState.rawPointerData.pointerForId(id);
+            if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS
+                    || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
+                mCurrentCookedState.stylusIdBits.markBit(id);
+            } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER
+                    || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
+                mCurrentCookedState.fingerIdBits.markBit(id);
+            } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) {
+                mCurrentCookedState.mouseIdBits.markBit(id);
+            }
+        }
+        for (BitSet32 idBits(mCurrentRawState.rawPointerData.hoveringIdBits);
+                !idBits.isEmpty(); ) {
+            uint32_t id = idBits.clearFirstMarkedBit();
+            const RawPointerData::Pointer& pointer =
+                    mCurrentRawState.rawPointerData.pointerForId(id);
+            if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS
+                    || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
+                mCurrentCookedState.stylusIdBits.markBit(id);
+            }
+        }
+
+        // Stylus takes precedence over all tools, then mouse, then finger.
+        PointerUsage pointerUsage = mPointerUsage;
+        if (!mCurrentCookedState.stylusIdBits.isEmpty()) {
+            mCurrentCookedState.mouseIdBits.clear();
+            mCurrentCookedState.fingerIdBits.clear();
+            pointerUsage = POINTER_USAGE_STYLUS;
+        } else if (!mCurrentCookedState.mouseIdBits.isEmpty()) {
+            mCurrentCookedState.fingerIdBits.clear();
+            pointerUsage = POINTER_USAGE_MOUSE;
+        } else if (!mCurrentCookedState.fingerIdBits.isEmpty() ||
+                isPointerDown(mCurrentRawState.buttonState)) {
+            pointerUsage = POINTER_USAGE_GESTURES;
+        }
+
+        dispatchPointerUsage(when, policyFlags, pointerUsage);
     } else {
-        // Preprocess pointer data.
-        if (!havePointerIds) {
-            assignPointerIds();
+        if (mDeviceMode == DEVICE_MODE_DIRECT
+                && mConfig.showTouches && mPointerController != NULL) {
+            mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
+            mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
+
+            mPointerController->setButtonState(mCurrentRawState.buttonState);
+            mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords,
+                    mCurrentCookedState.cookedPointerData.idToIndex,
+                    mCurrentCookedState.cookedPointerData.touchingIdBits);
         }
 
-        // Handle policy on initial down or hover events.
-        uint32_t policyFlags = 0;
-        bool initialDown = mLastRawPointerData.pointerCount == 0
-                && mCurrentRawPointerData.pointerCount != 0;
-        bool buttonsPressed = mCurrentButtonState & ~mLastButtonState;
-        if (initialDown || buttonsPressed) {
-            // If this is a touch screen, hide the pointer on an initial down.
-            if (mDeviceMode == DEVICE_MODE_DIRECT) {
-                getContext()->fadePointer();
-            }
-
-            if (mParameters.wake) {
-                policyFlags |= POLICY_FLAG_WAKE;
-            }
-        }
-
-        // Synthesize key down from raw buttons if needed.
-        synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource,
-                policyFlags, mLastButtonState, mCurrentButtonState);
-
-        // Consume raw off-screen touches before cooking pointer data.
-        // If touches are consumed, subsequent code will not receive any pointer data.
-        if (consumeRawTouches(when, policyFlags)) {
-            mCurrentRawPointerData.clear();
-        }
-
-        // Cook pointer data.  This call populates the mCurrentCookedPointerData structure
-        // with cooked pointer data that has the same ids and indices as the raw data.
-        // The following code can use either the raw or cooked data, as needed.
-        cookPointerData();
-
-        // Dispatch the touches either directly or by translation through a pointer on screen.
-        if (mDeviceMode == DEVICE_MODE_POINTER) {
-            for (BitSet32 idBits(mCurrentRawPointerData.touchingIdBits); !idBits.isEmpty(); ) {
-                uint32_t id = idBits.clearFirstMarkedBit();
-                const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
-                if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS
-                        || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
-                    mCurrentStylusIdBits.markBit(id);
-                } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER
-                        || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
-                    mCurrentFingerIdBits.markBit(id);
-                } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) {
-                    mCurrentMouseIdBits.markBit(id);
-                }
-            }
-            for (BitSet32 idBits(mCurrentRawPointerData.hoveringIdBits); !idBits.isEmpty(); ) {
-                uint32_t id = idBits.clearFirstMarkedBit();
-                const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
-                if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS
-                        || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
-                    mCurrentStylusIdBits.markBit(id);
-                }
-            }
-
-            // Stylus takes precedence over all tools, then mouse, then finger.
-            PointerUsage pointerUsage = mPointerUsage;
-            if (!mCurrentStylusIdBits.isEmpty()) {
-                mCurrentMouseIdBits.clear();
-                mCurrentFingerIdBits.clear();
-                pointerUsage = POINTER_USAGE_STYLUS;
-            } else if (!mCurrentMouseIdBits.isEmpty()) {
-                mCurrentFingerIdBits.clear();
-                pointerUsage = POINTER_USAGE_MOUSE;
-            } else if (!mCurrentFingerIdBits.isEmpty() || isPointerDown(mCurrentButtonState)) {
-                pointerUsage = POINTER_USAGE_GESTURES;
-            }
-
-            dispatchPointerUsage(when, policyFlags, pointerUsage);
-        } else {
-            if (mDeviceMode == DEVICE_MODE_DIRECT
-                    && mConfig.showTouches && mPointerController != NULL) {
-                mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
-                mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
-
-                mPointerController->setButtonState(mCurrentButtonState);
-                mPointerController->setSpots(mCurrentCookedPointerData.pointerCoords,
-                        mCurrentCookedPointerData.idToIndex,
-                        mCurrentCookedPointerData.touchingIdBits);
-            }
-
+        if (!mCurrentMotionAborted) {
+            dispatchButtonRelease(when, policyFlags);
             dispatchHoverExit(when, policyFlags);
             dispatchTouches(when, policyFlags);
             dispatchHoverEnterAndMove(when, policyFlags);
+            dispatchButtonPress(when, policyFlags);
         }
 
-        // Synthesize key up from raw buttons if needed.
-        synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,
-                policyFlags, mLastButtonState, mCurrentButtonState);
+        if (mCurrentCookedState.cookedPointerData.pointerCount == 0) {
+            mCurrentMotionAborted = false;
+        }
     }
 
-    // Copy current touch to last touch in preparation for the next cycle.
-    mLastRawPointerData.copyFrom(mCurrentRawPointerData);
-    mLastCookedPointerData.copyFrom(mCurrentCookedPointerData);
-    mLastButtonState = mCurrentButtonState;
-    mLastFingerIdBits = mCurrentFingerIdBits;
-    mLastStylusIdBits = mCurrentStylusIdBits;
-    mLastMouseIdBits = mCurrentMouseIdBits;
+    // Synthesize key up from raw buttons if needed.
+    synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,
+            policyFlags, mLastCookedState.buttonState, mCurrentCookedState.buttonState);
 
     // Clear some transient state.
-    mCurrentRawVScroll = 0;
-    mCurrentRawHScroll = 0;
+    mCurrentRawState.rawVScroll = 0;
+    mCurrentRawState.rawHScroll = 0;
+
+    // Copy current touch to last touch in preparation for the next cycle.
+    mLastRawState.copyFrom(mCurrentRawState);
+    mLastCookedState.copyFrom(mCurrentCookedState);
+}
+
+void TouchInputMapper::applyExternalStylusButtonState(nsecs_t when) {
+    if (mDeviceMode == DEVICE_MODE_DIRECT && hasExternalStylus() && mExternalStylusId != -1) {
+        mCurrentRawState.buttonState |= mExternalStylusState.buttons;
+    }
+}
+
+void TouchInputMapper::applyExternalStylusTouchState(nsecs_t when) {
+    CookedPointerData& currentPointerData = mCurrentCookedState.cookedPointerData;
+    const CookedPointerData& lastPointerData = mLastCookedState.cookedPointerData;
+
+    if (mExternalStylusId != -1 && currentPointerData.isTouching(mExternalStylusId)) {
+        float pressure = mExternalStylusState.pressure;
+        if (pressure == 0.0f && lastPointerData.isTouching(mExternalStylusId)) {
+            const PointerCoords& coords = lastPointerData.pointerCoordsForId(mExternalStylusId);
+            pressure = coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE);
+        }
+        PointerCoords& coords = currentPointerData.editPointerCoordsWithId(mExternalStylusId);
+        coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure);
+
+        PointerProperties& properties =
+                currentPointerData.editPointerPropertiesWithId(mExternalStylusId);
+        if (mExternalStylusState.toolType != AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
+            properties.toolType = mExternalStylusState.toolType;
+        }
+    }
+}
+
+bool TouchInputMapper::assignExternalStylusId(const RawState& state, bool timeout) {
+    if (mDeviceMode != DEVICE_MODE_DIRECT || !hasExternalStylus()) {
+        return false;
+    }
+
+    const bool initialDown = mLastRawState.rawPointerData.pointerCount == 0
+            && state.rawPointerData.pointerCount != 0;
+    if (initialDown) {
+        if (mExternalStylusState.pressure != 0.0f) {
+#if DEBUG_STYLUS_FUSION
+            ALOGD("Have both stylus and touch data, beginning fusion");
+#endif
+            mExternalStylusId = state.rawPointerData.touchingIdBits.firstMarkedBit();
+        } else if (timeout) {
+#if DEBUG_STYLUS_FUSION
+            ALOGD("Timeout expired, assuming touch is not a stylus.");
+#endif
+            resetExternalStylus();
+        } else {
+            if (mExternalStylusFusionTimeout == LLONG_MAX) {
+                mExternalStylusFusionTimeout = state.when + EXTERNAL_STYLUS_DATA_TIMEOUT;
+            }
+#if DEBUG_STYLUS_FUSION
+            ALOGD("No stylus data but stylus is connected, requesting timeout "
+                    "(%" PRId64 "ms)", mExternalStylusFusionTimeout);
+#endif
+            getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout);
+            return true;
+        }
+    }
+
+    // Check if the stylus pointer has gone up.
+    if (mExternalStylusId != -1 &&
+            !state.rawPointerData.touchingIdBits.hasBit(mExternalStylusId)) {
+#if DEBUG_STYLUS_FUSION
+            ALOGD("Stylus pointer is going up");
+#endif
+        mExternalStylusId = -1;
+    }
+
+    return false;
 }
 
 void TouchInputMapper::timeoutExpired(nsecs_t when) {
@@ -3903,13 +4189,30 @@
         if (mPointerUsage == POINTER_USAGE_GESTURES) {
             dispatchPointerGestures(when, 0 /*policyFlags*/, true /*isTimeout*/);
         }
+    } else if (mDeviceMode == DEVICE_MODE_DIRECT) {
+        if (mExternalStylusFusionTimeout < when) {
+            processRawTouches(true /*timeout*/);
+        } else if (mExternalStylusFusionTimeout != LLONG_MAX) {
+            getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout);
+        }
+    }
+}
+
+void TouchInputMapper::updateExternalStylusState(const StylusState& state) {
+    mExternalStylusState.copyFrom(state);
+    if (mExternalStylusId != -1 || mExternalStylusFusionTimeout != LLONG_MAX) {
+        // We're either in the middle of a fused stream of data or we're waiting on data before
+        // dispatching the initial down, so go ahead and dispatch now that we have fresh stylus
+        // data.
+        mExternalStylusDataPending = true;
+        processRawTouches(false /*timeout*/);
     }
 }
 
 bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) {
     // Check for release of a virtual key.
     if (mCurrentVirtualKey.down) {
-        if (mCurrentRawPointerData.touchingIdBits.isEmpty()) {
+        if (mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) {
             // Pointer went up while virtual key was down.
             mCurrentVirtualKey.down = false;
             if (!mCurrentVirtualKey.ignored) {
@@ -3924,9 +4227,10 @@
             return true;
         }
 
-        if (mCurrentRawPointerData.touchingIdBits.count() == 1) {
-            uint32_t id = mCurrentRawPointerData.touchingIdBits.firstMarkedBit();
-            const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
+        if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) {
+            uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit();
+            const RawPointerData::Pointer& pointer =
+                    mCurrentRawState.rawPointerData.pointerForId(id);
             const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y);
             if (virtualKey && virtualKey->keyCode == mCurrentVirtualKey.keyCode) {
                 // Pointer is still within the space of the virtual key.
@@ -3951,15 +4255,15 @@
         }
     }
 
-    if (mLastRawPointerData.touchingIdBits.isEmpty()
-            && !mCurrentRawPointerData.touchingIdBits.isEmpty()) {
+    if (mLastRawState.rawPointerData.touchingIdBits.isEmpty()
+            && !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) {
         // Pointer just went down.  Check for virtual key press or off-screen touches.
-        uint32_t id = mCurrentRawPointerData.touchingIdBits.firstMarkedBit();
-        const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
+        uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit();
+        const RawPointerData::Pointer& pointer = mCurrentRawState.rawPointerData.pointerForId(id);
         if (!isPointInsideSurface(pointer.x, pointer.y)) {
             // If exactly one pointer went down, check for virtual key hit.
             // Otherwise we will drop the entire stroke.
-            if (mCurrentRawPointerData.touchingIdBits.count() == 1) {
+            if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) {
                 const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y);
                 if (virtualKey) {
                     mCurrentVirtualKey.down = true;
@@ -3999,7 +4303,8 @@
     //    area and accidentally triggers a virtual key.  This often happens when virtual keys
     //    are layed out below the screen near to where the on screen keyboard's space bar
     //    is displayed.
-    if (mConfig.virtualKeyQuietTime > 0 && !mCurrentRawPointerData.touchingIdBits.isEmpty()) {
+    if (mConfig.virtualKeyQuietTime > 0 &&
+            !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) {
         mContext->disableVirtualKeysUntil(when + mConfig.virtualKeyQuietTime);
     }
     return false;
@@ -4018,22 +4323,38 @@
     getListener()->notifyKey(&args);
 }
 
+void TouchInputMapper::abortTouches(nsecs_t when, uint32_t policyFlags) {
+    BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits;
+    if (!currentIdBits.isEmpty()) {
+        int32_t metaState = getContext()->getGlobalMetaState();
+        int32_t buttonState = mCurrentCookedState.buttonState;
+        dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0,
+                metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+                mCurrentCookedState.cookedPointerData.pointerProperties,
+                mCurrentCookedState.cookedPointerData.pointerCoords,
+                mCurrentCookedState.cookedPointerData.idToIndex,
+                currentIdBits, -1,
+                mOrientedXPrecision, mOrientedYPrecision, mDownTime);
+        mCurrentMotionAborted = true;
+    }
+}
+
 void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
-    BitSet32 currentIdBits = mCurrentCookedPointerData.touchingIdBits;
-    BitSet32 lastIdBits = mLastCookedPointerData.touchingIdBits;
+    BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits;
+    BitSet32 lastIdBits = mLastCookedState.cookedPointerData.touchingIdBits;
     int32_t metaState = getContext()->getGlobalMetaState();
-    int32_t buttonState = mCurrentButtonState;
+    int32_t buttonState = mCurrentCookedState.buttonState;
 
     if (currentIdBits == lastIdBits) {
         if (!currentIdBits.isEmpty()) {
             // No pointer id changes so this is a move event.
             // The listener takes care of batching moves so we don't have to deal with that here.
             dispatchMotion(when, policyFlags, mSource,
-                    AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState,
+                    AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState,
                     AMOTION_EVENT_EDGE_FLAG_NONE,
-                    mCurrentCookedPointerData.pointerProperties,
-                    mCurrentCookedPointerData.pointerCoords,
-                    mCurrentCookedPointerData.idToIndex,
+                    mCurrentCookedState.cookedPointerData.pointerProperties,
+                    mCurrentCookedState.cookedPointerData.pointerCoords,
+                    mCurrentCookedState.cookedPointerData.idToIndex,
                     currentIdBits, -1,
                     mOrientedXPrecision, mOrientedYPrecision, mDownTime);
         }
@@ -4048,14 +4369,14 @@
         // Update last coordinates of pointers that have moved so that we observe the new
         // pointer positions at the same time as other pointers that have just gone up.
         bool moveNeeded = updateMovedPointers(
-                mCurrentCookedPointerData.pointerProperties,
-                mCurrentCookedPointerData.pointerCoords,
-                mCurrentCookedPointerData.idToIndex,
-                mLastCookedPointerData.pointerProperties,
-                mLastCookedPointerData.pointerCoords,
-                mLastCookedPointerData.idToIndex,
+                mCurrentCookedState.cookedPointerData.pointerProperties,
+                mCurrentCookedState.cookedPointerData.pointerCoords,
+                mCurrentCookedState.cookedPointerData.idToIndex,
+                mLastCookedState.cookedPointerData.pointerProperties,
+                mLastCookedState.cookedPointerData.pointerCoords,
+                mLastCookedState.cookedPointerData.idToIndex,
                 moveIdBits);
-        if (buttonState != mLastButtonState) {
+        if (buttonState != mLastCookedState.buttonState) {
             moveNeeded = true;
         }
 
@@ -4064,27 +4385,25 @@
             uint32_t upId = upIdBits.clearFirstMarkedBit();
 
             dispatchMotion(when, policyFlags, mSource,
-                    AMOTION_EVENT_ACTION_POINTER_UP, 0, metaState, buttonState, 0,
-                    mLastCookedPointerData.pointerProperties,
-                    mLastCookedPointerData.pointerCoords,
-                    mLastCookedPointerData.idToIndex,
-                    dispatchedIdBits, upId,
-                    mOrientedXPrecision, mOrientedYPrecision, mDownTime);
+                    AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, metaState, buttonState, 0,
+                    mLastCookedState.cookedPointerData.pointerProperties,
+                    mLastCookedState.cookedPointerData.pointerCoords,
+                    mLastCookedState.cookedPointerData.idToIndex,
+                    dispatchedIdBits, upId, mOrientedXPrecision, mOrientedYPrecision, mDownTime);
             dispatchedIdBits.clearBit(upId);
         }
 
         // Dispatch move events if any of the remaining pointers moved from their old locations.
         // Although applications receive new locations as part of individual pointer up
         // events, they do not generally handle them except when presented in a move event.
-        if (moveNeeded) {
+        if (moveNeeded && !moveIdBits.isEmpty()) {
             ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value);
             dispatchMotion(when, policyFlags, mSource,
-                    AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, 0,
-                    mCurrentCookedPointerData.pointerProperties,
-                    mCurrentCookedPointerData.pointerCoords,
-                    mCurrentCookedPointerData.idToIndex,
-                    dispatchedIdBits, -1,
-                    mOrientedXPrecision, mOrientedYPrecision, mDownTime);
+                    AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, 0,
+                    mCurrentCookedState.cookedPointerData.pointerProperties,
+                    mCurrentCookedState.cookedPointerData.pointerCoords,
+                    mCurrentCookedState.cookedPointerData.idToIndex,
+                    dispatchedIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime);
         }
 
         // Dispatch pointer down events using the new pointer locations.
@@ -4098,69 +4417,119 @@
             }
 
             dispatchMotion(when, policyFlags, mSource,
-                    AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0,
-                    mCurrentCookedPointerData.pointerProperties,
-                    mCurrentCookedPointerData.pointerCoords,
-                    mCurrentCookedPointerData.idToIndex,
-                    dispatchedIdBits, downId,
-                    mOrientedXPrecision, mOrientedYPrecision, mDownTime);
+                    AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0,
+                    mCurrentCookedState.cookedPointerData.pointerProperties,
+                    mCurrentCookedState.cookedPointerData.pointerCoords,
+                    mCurrentCookedState.cookedPointerData.idToIndex,
+                    dispatchedIdBits, downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime);
         }
     }
 }
 
 void TouchInputMapper::dispatchHoverExit(nsecs_t when, uint32_t policyFlags) {
     if (mSentHoverEnter &&
-            (mCurrentCookedPointerData.hoveringIdBits.isEmpty()
-                    || !mCurrentCookedPointerData.touchingIdBits.isEmpty())) {
+            (mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty()
+                    || !mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty())) {
         int32_t metaState = getContext()->getGlobalMetaState();
         dispatchMotion(when, policyFlags, mSource,
-                AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastButtonState, 0,
-                mLastCookedPointerData.pointerProperties,
-                mLastCookedPointerData.pointerCoords,
-                mLastCookedPointerData.idToIndex,
-                mLastCookedPointerData.hoveringIdBits, -1,
+                AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastCookedState.buttonState, 0,
+                mLastCookedState.cookedPointerData.pointerProperties,
+                mLastCookedState.cookedPointerData.pointerCoords,
+                mLastCookedState.cookedPointerData.idToIndex,
+                mLastCookedState.cookedPointerData.hoveringIdBits, -1,
                 mOrientedXPrecision, mOrientedYPrecision, mDownTime);
         mSentHoverEnter = false;
     }
 }
 
 void TouchInputMapper::dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags) {
-    if (mCurrentCookedPointerData.touchingIdBits.isEmpty()
-            && !mCurrentCookedPointerData.hoveringIdBits.isEmpty()) {
+    if (mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty()
+            && !mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty()) {
         int32_t metaState = getContext()->getGlobalMetaState();
         if (!mSentHoverEnter) {
-            dispatchMotion(when, policyFlags, mSource,
-                    AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, mCurrentButtonState, 0,
-                    mCurrentCookedPointerData.pointerProperties,
-                    mCurrentCookedPointerData.pointerCoords,
-                    mCurrentCookedPointerData.idToIndex,
-                    mCurrentCookedPointerData.hoveringIdBits, -1,
+            dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_ENTER,
+                    0, 0, metaState, mCurrentRawState.buttonState, 0,
+                    mCurrentCookedState.cookedPointerData.pointerProperties,
+                    mCurrentCookedState.cookedPointerData.pointerCoords,
+                    mCurrentCookedState.cookedPointerData.idToIndex,
+                    mCurrentCookedState.cookedPointerData.hoveringIdBits, -1,
                     mOrientedXPrecision, mOrientedYPrecision, mDownTime);
             mSentHoverEnter = true;
         }
 
         dispatchMotion(when, policyFlags, mSource,
-                AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, mCurrentButtonState, 0,
-                mCurrentCookedPointerData.pointerProperties,
-                mCurrentCookedPointerData.pointerCoords,
-                mCurrentCookedPointerData.idToIndex,
-                mCurrentCookedPointerData.hoveringIdBits, -1,
+                AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
+                mCurrentRawState.buttonState, 0,
+                mCurrentCookedState.cookedPointerData.pointerProperties,
+                mCurrentCookedState.cookedPointerData.pointerCoords,
+                mCurrentCookedState.cookedPointerData.idToIndex,
+                mCurrentCookedState.cookedPointerData.hoveringIdBits, -1,
                 mOrientedXPrecision, mOrientedYPrecision, mDownTime);
     }
 }
 
-void TouchInputMapper::cookPointerData() {
-    uint32_t currentPointerCount = mCurrentRawPointerData.pointerCount;
+void TouchInputMapper::dispatchButtonRelease(nsecs_t when, uint32_t policyFlags) {
+    BitSet32 releasedButtons(mLastCookedState.buttonState & ~mCurrentCookedState.buttonState);
+    const BitSet32& idBits = findActiveIdBits(mLastCookedState.cookedPointerData);
+    const int32_t metaState = getContext()->getGlobalMetaState();
+    int32_t buttonState = mLastCookedState.buttonState;
+    while (!releasedButtons.isEmpty()) {
+        int32_t actionButton = BitSet32::valueForBit(releasedButtons.clearFirstMarkedBit());
+        buttonState &= ~actionButton;
+        dispatchMotion(when, policyFlags, mSource,
+                    AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton,
+                    0, metaState, buttonState, 0,
+                    mCurrentCookedState.cookedPointerData.pointerProperties,
+                    mCurrentCookedState.cookedPointerData.pointerCoords,
+                    mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1,
+                    mOrientedXPrecision, mOrientedYPrecision, mDownTime);
+    }
+}
 
-    mCurrentCookedPointerData.clear();
-    mCurrentCookedPointerData.pointerCount = currentPointerCount;
-    mCurrentCookedPointerData.hoveringIdBits = mCurrentRawPointerData.hoveringIdBits;
-    mCurrentCookedPointerData.touchingIdBits = mCurrentRawPointerData.touchingIdBits;
+void TouchInputMapper::dispatchButtonPress(nsecs_t when, uint32_t policyFlags) {
+    BitSet32 pressedButtons(mCurrentCookedState.buttonState & ~mLastCookedState.buttonState);
+    const BitSet32& idBits = findActiveIdBits(mCurrentCookedState.cookedPointerData);
+    const int32_t metaState = getContext()->getGlobalMetaState();
+    int32_t buttonState = mLastCookedState.buttonState;
+    while (!pressedButtons.isEmpty()) {
+        int32_t actionButton = BitSet32::valueForBit(pressedButtons.clearFirstMarkedBit());
+        buttonState |= actionButton;
+        dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton,
+                    0, metaState, buttonState, 0,
+                    mCurrentCookedState.cookedPointerData.pointerProperties,
+                    mCurrentCookedState.cookedPointerData.pointerCoords,
+                    mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1,
+                    mOrientedXPrecision, mOrientedYPrecision, mDownTime);
+    }
+}
+
+const BitSet32& TouchInputMapper::findActiveIdBits(const CookedPointerData& cookedPointerData) {
+    if (!cookedPointerData.touchingIdBits.isEmpty()) {
+        return cookedPointerData.touchingIdBits;
+    }
+    return cookedPointerData.hoveringIdBits;
+}
+
+void TouchInputMapper::cookPointerData() {
+    uint32_t currentPointerCount = mCurrentRawState.rawPointerData.pointerCount;
+
+    mCurrentCookedState.cookedPointerData.clear();
+    mCurrentCookedState.cookedPointerData.pointerCount = currentPointerCount;
+    mCurrentCookedState.cookedPointerData.hoveringIdBits =
+            mCurrentRawState.rawPointerData.hoveringIdBits;
+    mCurrentCookedState.cookedPointerData.touchingIdBits =
+            mCurrentRawState.rawPointerData.touchingIdBits;
+
+    if (mCurrentCookedState.cookedPointerData.pointerCount == 0) {
+        mCurrentCookedState.buttonState = 0;
+    } else {
+        mCurrentCookedState.buttonState = mCurrentRawState.buttonState;
+    }
 
     // Walk through the the active pointers and map device coordinates onto
     // surface coordinates and adjust for display orientation.
     for (uint32_t i = 0; i < currentPointerCount; i++) {
-        const RawPointerData::Pointer& in = mCurrentRawPointerData.pointers[i];
+        const RawPointerData::Pointer& in = mCurrentRawState.rawPointerData.pointers[i];
 
         // Size
         float touchMajor, touchMinor, toolMajor, toolMinor, size;
@@ -4199,7 +4568,8 @@
             }
 
             if (mCalibration.haveSizeIsSummed && mCalibration.sizeIsSummed) {
-                uint32_t touchingCount = mCurrentRawPointerData.touchingIdBits.count();
+                uint32_t touchingCount =
+                        mCurrentRawState.rawPointerData.touchingIdBits.count();
                 if (touchingCount > 1) {
                     touchMajor /= touchingCount;
                     touchMinor /= touchingCount;
@@ -4368,7 +4738,7 @@
         }
 
         // Write output coords.
-        PointerCoords& out = mCurrentCookedPointerData.pointerCoords[i];
+        PointerCoords& out = mCurrentCookedState.cookedPointerData.pointerCoords[i];
         out.clear();
         out.setAxisValue(AMOTION_EVENT_AXIS_X, x);
         out.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
@@ -4390,14 +4760,15 @@
         }
 
         // Write output properties.
-        PointerProperties& properties = mCurrentCookedPointerData.pointerProperties[i];
+        PointerProperties& properties =
+                mCurrentCookedState.cookedPointerData.pointerProperties[i];
         uint32_t id = in.id;
         properties.clear();
         properties.id = id;
         properties.toolType = in.toolType;
 
         // Write id index.
-        mCurrentCookedPointerData.idToIndex[id] = i;
+        mCurrentCookedState.cookedPointerData.idToIndex[id] = i;
     }
 }
 
@@ -4501,7 +4872,7 @@
 
     // Send events!
     int32_t metaState = getContext()->getGlobalMetaState();
-    int32_t buttonState = mCurrentButtonState;
+    int32_t buttonState = mCurrentCookedState.buttonState;
 
     // Update last coordinates of pointers that have moved so that we observe the new
     // pointer positions at the same time as other pointers that have just gone up.
@@ -4522,7 +4893,7 @@
                 mPointerGesture.lastGestureProperties,
                 mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
                 movedGestureIdBits);
-        if (buttonState != mLastButtonState) {
+        if (buttonState != mLastCookedState.buttonState) {
             moveNeeded = true;
         }
     }
@@ -4532,12 +4903,12 @@
     if (!dispatchedGestureIdBits.isEmpty()) {
         if (cancelPreviousGesture) {
             dispatchMotion(when, policyFlags, mSource,
-                    AMOTION_EVENT_ACTION_CANCEL, 0, metaState, buttonState,
+                    AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState,
                     AMOTION_EVENT_EDGE_FLAG_NONE,
                     mPointerGesture.lastGestureProperties,
                     mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
-                    dispatchedGestureIdBits, -1,
-                    0, 0, mPointerGesture.downTime);
+                    dispatchedGestureIdBits, -1, 0,
+                    0, mPointerGesture.downTime);
 
             dispatchedGestureIdBits.clear();
         } else {
@@ -4552,7 +4923,7 @@
                 uint32_t id = upGestureIdBits.clearFirstMarkedBit();
 
                 dispatchMotion(when, policyFlags, mSource,
-                        AMOTION_EVENT_ACTION_POINTER_UP, 0,
+                        AMOTION_EVENT_ACTION_POINTER_UP, 0, 0,
                         metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
                         mPointerGesture.lastGestureProperties,
                         mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
@@ -4567,7 +4938,8 @@
     // Send motion events for all pointers that moved.
     if (moveNeeded) {
         dispatchMotion(when, policyFlags, mSource,
-                AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+                AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState,
+                AMOTION_EVENT_EDGE_FLAG_NONE,
                 mPointerGesture.currentGestureProperties,
                 mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
                 dispatchedGestureIdBits, -1,
@@ -4587,7 +4959,7 @@
             }
 
             dispatchMotion(when, policyFlags, mSource,
-                    AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0,
+                    AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0,
                     mPointerGesture.currentGestureProperties,
                     mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
                     dispatchedGestureIdBits, id,
@@ -4598,7 +4970,7 @@
     // Send motion events for hover.
     if (mPointerGesture.currentGestureMode == PointerGesture::HOVER) {
         dispatchMotion(when, policyFlags, mSource,
-                AMOTION_EVENT_ACTION_HOVER_MOVE, 0,
+                AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
                 metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
                 mPointerGesture.currentGestureProperties,
                 mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
@@ -4624,7 +4996,7 @@
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
 
         NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
-                AMOTION_EVENT_ACTION_HOVER_MOVE, 0,
+                AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
                 metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
                 mViewport.displayId, 1, &pointerProperties, &pointerCoords,
                 0, 0, mPointerGesture.downTime);
@@ -4653,9 +5025,9 @@
     // Cancel previously dispatches pointers.
     if (!mPointerGesture.lastGestureIdBits.isEmpty()) {
         int32_t metaState = getContext()->getGlobalMetaState();
-        int32_t buttonState = mCurrentButtonState;
+        int32_t buttonState = mCurrentRawState.buttonState;
         dispatchMotion(when, policyFlags, mSource,
-                AMOTION_EVENT_ACTION_CANCEL, 0, metaState, buttonState,
+                AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState,
                 AMOTION_EVENT_EDGE_FLAG_NONE,
                 mPointerGesture.lastGestureProperties,
                 mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
@@ -4710,21 +5082,22 @@
         return false;
     }
 
-    const uint32_t currentFingerCount = mCurrentFingerIdBits.count();
-    const uint32_t lastFingerCount = mLastFingerIdBits.count();
+    const uint32_t currentFingerCount = mCurrentCookedState.fingerIdBits.count();
+    const uint32_t lastFingerCount = mLastCookedState.fingerIdBits.count();
 
     // Update the velocity tracker.
     {
         VelocityTracker::Position positions[MAX_POINTERS];
         uint32_t count = 0;
-        for (BitSet32 idBits(mCurrentFingerIdBits); !idBits.isEmpty(); count++) {
+        for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty(); count++) {
             uint32_t id = idBits.clearFirstMarkedBit();
-            const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id);
+            const RawPointerData::Pointer& pointer =
+                    mCurrentRawState.rawPointerData.pointerForId(id);
             positions[count].x = pointer.x * mPointerXMovementScale;
             positions[count].y = pointer.y * mPointerYMovementScale;
         }
         mPointerGesture.velocityTracker.addMovement(when,
-                mCurrentFingerIdBits, positions);
+                mCurrentCookedState.fingerIdBits, positions);
     }
 
     // If the gesture ever enters a mode other than TAP, HOVER or TAP_DRAG, without first returning
@@ -4744,17 +5117,17 @@
     int32_t lastActiveTouchId = mPointerGesture.activeTouchId;
     int32_t activeTouchId = lastActiveTouchId;
     if (activeTouchId < 0) {
-        if (!mCurrentFingerIdBits.isEmpty()) {
+        if (!mCurrentCookedState.fingerIdBits.isEmpty()) {
             activeTouchChanged = true;
             activeTouchId = mPointerGesture.activeTouchId =
-                    mCurrentFingerIdBits.firstMarkedBit();
+                    mCurrentCookedState.fingerIdBits.firstMarkedBit();
             mPointerGesture.firstTouchTime = when;
         }
-    } else if (!mCurrentFingerIdBits.hasBit(activeTouchId)) {
+    } else if (!mCurrentCookedState.fingerIdBits.hasBit(activeTouchId)) {
         activeTouchChanged = true;
-        if (!mCurrentFingerIdBits.isEmpty()) {
+        if (!mCurrentCookedState.fingerIdBits.isEmpty()) {
             activeTouchId = mPointerGesture.activeTouchId =
-                    mCurrentFingerIdBits.firstMarkedBit();
+                    mCurrentCookedState.fingerIdBits.firstMarkedBit();
         } else {
             activeTouchId = mPointerGesture.activeTouchId = -1;
         }
@@ -4777,7 +5150,7 @@
                 isQuietTime = true;
             } else if (mPointerGesture.lastGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG
                     && currentFingerCount >= 2
-                    && !isPointerDown(mCurrentButtonState)) {
+                    && !isPointerDown(mCurrentRawState.buttonState)) {
                 // Enter quiet time when releasing the button and there are still two or more
                 // fingers down.  This may indicate that one finger was used to press the button
                 // but it has not gone up yet.
@@ -4805,7 +5178,7 @@
         mPointerGesture.currentGestureIdBits.clear();
 
         mPointerVelocityControl.reset();
-    } else if (isPointerDown(mCurrentButtonState)) {
+    } else if (isPointerDown(mCurrentRawState.buttonState)) {
         // Case 2: Button is pressed. (BUTTON_CLICK_OR_DRAG)
         // The pointer follows the active touch point.
         // Emit DOWN, MOVE, UP events at the pointer location.
@@ -4834,7 +5207,7 @@
         if (activeTouchId >= 0 && currentFingerCount > 1) {
             int32_t bestId = -1;
             float bestSpeed = mConfig.pointerGestureDragMinSwitchSpeed;
-            for (BitSet32 idBits(mCurrentFingerIdBits); !idBits.isEmpty(); ) {
+            for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty(); ) {
                 uint32_t id = idBits.clearFirstMarkedBit();
                 float vx, vy;
                 if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) {
@@ -4855,11 +5228,11 @@
             }
         }
 
-        if (activeTouchId >= 0 && mLastFingerIdBits.hasBit(activeTouchId)) {
+        if (activeTouchId >= 0 && mLastCookedState.fingerIdBits.hasBit(activeTouchId)) {
             const RawPointerData::Pointer& currentPointer =
-                    mCurrentRawPointerData.pointerForId(activeTouchId);
+                    mCurrentRawState.rawPointerData.pointerForId(activeTouchId);
             const RawPointerData::Pointer& lastPointer =
-                    mLastRawPointerData.pointerForId(activeTouchId);
+                    mLastRawState.rawPointerData.pointerForId(activeTouchId);
             float deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale;
             float deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale;
 
@@ -4995,11 +5368,11 @@
             mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG;
         }
 
-        if (mLastFingerIdBits.hasBit(activeTouchId)) {
+        if (mLastCookedState.fingerIdBits.hasBit(activeTouchId)) {
             const RawPointerData::Pointer& currentPointer =
-                    mCurrentRawPointerData.pointerForId(activeTouchId);
+                    mCurrentRawState.rawPointerData.pointerForId(activeTouchId);
             const RawPointerData::Pointer& lastPointer =
-                    mLastRawPointerData.pointerForId(activeTouchId);
+                    mLastRawState.rawPointerData.pointerForId(activeTouchId);
             float deltaX = (currentPointer.x - lastPointer.x)
                     * mPointerXMovementScale;
             float deltaY = (currentPointer.y - lastPointer.y)
@@ -5104,7 +5477,7 @@
                             + mConfig.pointerGestureMultitouchSettleInterval - when)
                             * 0.000001f);
 #endif
-            mCurrentRawPointerData.getCentroidOfTouchingPointers(
+            mCurrentRawState.rawPointerData.getCentroidOfTouchingPointers(
                     &mPointerGesture.referenceTouchX,
                     &mPointerGesture.referenceTouchY);
             mPointerController->getPosition(&mPointerGesture.referenceGestureX,
@@ -5112,23 +5485,23 @@
         }
 
         // Clear the reference deltas for fingers not yet included in the reference calculation.
-        for (BitSet32 idBits(mCurrentFingerIdBits.value
+        for (BitSet32 idBits(mCurrentCookedState.fingerIdBits.value
                 & ~mPointerGesture.referenceIdBits.value); !idBits.isEmpty(); ) {
             uint32_t id = idBits.clearFirstMarkedBit();
             mPointerGesture.referenceDeltas[id].dx = 0;
             mPointerGesture.referenceDeltas[id].dy = 0;
         }
-        mPointerGesture.referenceIdBits = mCurrentFingerIdBits;
+        mPointerGesture.referenceIdBits = mCurrentCookedState.fingerIdBits;
 
         // Add delta for all fingers and calculate a common movement delta.
         float commonDeltaX = 0, commonDeltaY = 0;
-        BitSet32 commonIdBits(mLastFingerIdBits.value
-                & mCurrentFingerIdBits.value);
+        BitSet32 commonIdBits(mLastCookedState.fingerIdBits.value
+                & mCurrentCookedState.fingerIdBits.value);
         for (BitSet32 idBits(commonIdBits); !idBits.isEmpty(); ) {
             bool first = (idBits == commonIdBits);
             uint32_t id = idBits.clearFirstMarkedBit();
-            const RawPointerData::Pointer& cpd = mCurrentRawPointerData.pointerForId(id);
-            const RawPointerData::Pointer& lpd = mLastRawPointerData.pointerForId(id);
+            const RawPointerData::Pointer& cpd = mCurrentRawState.rawPointerData.pointerForId(id);
+            const RawPointerData::Pointer& lpd = mLastRawState.rawPointerData.pointerForId(id);
             PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id];
             delta.dx += cpd.x - lpd.x;
             delta.dy += cpd.y - lpd.y;
@@ -5169,11 +5542,13 @@
                     mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
                 } else {
                     // There are exactly two pointers.
-                    BitSet32 idBits(mCurrentFingerIdBits);
+                    BitSet32 idBits(mCurrentCookedState.fingerIdBits);
                     uint32_t id1 = idBits.clearFirstMarkedBit();
                     uint32_t id2 = idBits.firstMarkedBit();
-                    const RawPointerData::Pointer& p1 = mCurrentRawPointerData.pointerForId(id1);
-                    const RawPointerData::Pointer& p2 = mCurrentRawPointerData.pointerForId(id2);
+                    const RawPointerData::Pointer& p1 =
+                            mCurrentRawState.rawPointerData.pointerForId(id1);
+                    const RawPointerData::Pointer& p2 =
+                            mCurrentRawState.rawPointerData.pointerForId(id2);
                     float mutualDistance = distance(p1.x, p1.y, p2.x, p2.y);
                     if (mutualDistance > mPointerGestureMaxSwipeWidth) {
                         // There are two pointers but they are too far apart for a SWIPE,
@@ -5319,14 +5694,14 @@
             } else {
                 // Otherwise, assume we mapped all touches from the previous frame.
                 // Reuse all mappings that are still applicable.
-                mappedTouchIdBits.value = mLastFingerIdBits.value
-                        & mCurrentFingerIdBits.value;
+                mappedTouchIdBits.value = mLastCookedState.fingerIdBits.value
+                        & mCurrentCookedState.fingerIdBits.value;
                 usedGestureIdBits = mPointerGesture.lastGestureIdBits;
 
                 // Check whether we need to choose a new active gesture id because the
                 // current went went up.
-                for (BitSet32 upTouchIdBits(mLastFingerIdBits.value
-                        & ~mCurrentFingerIdBits.value);
+                for (BitSet32 upTouchIdBits(mLastCookedState.fingerIdBits.value
+                        & ~mCurrentCookedState.fingerIdBits.value);
                         !upTouchIdBits.isEmpty(); ) {
                     uint32_t upTouchId = upTouchIdBits.clearFirstMarkedBit();
                     uint32_t upGestureId = mPointerGesture.freeformTouchToGestureIdMap[upTouchId];
@@ -5345,7 +5720,7 @@
                     mPointerGesture.activeGestureId);
 #endif
 
-            BitSet32 idBits(mCurrentFingerIdBits);
+            BitSet32 idBits(mCurrentCookedState.fingerIdBits);
             for (uint32_t i = 0; i < currentFingerCount; i++) {
                 uint32_t touchId = idBits.clearFirstMarkedBit();
                 uint32_t gestureId;
@@ -5369,7 +5744,7 @@
                 mPointerGesture.currentGestureIdToIndex[gestureId] = i;
 
                 const RawPointerData::Pointer& pointer =
-                        mCurrentRawPointerData.pointerForId(touchId);
+                        mCurrentRawState.rawPointerData.pointerForId(touchId);
                 float deltaX = (pointer.x - mPointerGesture.referenceTouchX)
                         * mPointerXZoomScale;
                 float deltaY = (pointer.y - mPointerGesture.referenceTouchY)
@@ -5400,7 +5775,7 @@
         }
     }
 
-    mPointerController->setButtonState(mCurrentButtonState);
+    mPointerController->setButtonState(mCurrentRawState.buttonState);
 
 #if DEBUG_GESTURES
     ALOGD("Gestures: finishPreviousGesture=%s, cancelPreviousGesture=%s, "
@@ -5442,23 +5817,24 @@
     mPointerSimple.currentProperties.clear();
 
     bool down, hovering;
-    if (!mCurrentStylusIdBits.isEmpty()) {
-        uint32_t id = mCurrentStylusIdBits.firstMarkedBit();
-        uint32_t index = mCurrentCookedPointerData.idToIndex[id];
-        float x = mCurrentCookedPointerData.pointerCoords[index].getX();
-        float y = mCurrentCookedPointerData.pointerCoords[index].getY();
+    if (!mCurrentCookedState.stylusIdBits.isEmpty()) {
+        uint32_t id = mCurrentCookedState.stylusIdBits.firstMarkedBit();
+        uint32_t index = mCurrentCookedState.cookedPointerData.idToIndex[id];
+        float x = mCurrentCookedState.cookedPointerData.pointerCoords[index].getX();
+        float y = mCurrentCookedState.cookedPointerData.pointerCoords[index].getY();
         mPointerController->setPosition(x, y);
 
-        hovering = mCurrentCookedPointerData.hoveringIdBits.hasBit(id);
+        hovering = mCurrentCookedState.cookedPointerData.hoveringIdBits.hasBit(id);
         down = !hovering;
 
         mPointerController->getPosition(&x, &y);
-        mPointerSimple.currentCoords.copyFrom(mCurrentCookedPointerData.pointerCoords[index]);
+        mPointerSimple.currentCoords.copyFrom(
+                mCurrentCookedState.cookedPointerData.pointerCoords[index]);
         mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
         mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
         mPointerSimple.currentProperties.id = 0;
         mPointerSimple.currentProperties.toolType =
-                mCurrentCookedPointerData.pointerProperties[index].toolType;
+                mCurrentCookedState.cookedPointerData.pointerProperties[index].toolType;
     } else {
         down = false;
         hovering = false;
@@ -5476,16 +5852,16 @@
     mPointerSimple.currentProperties.clear();
 
     bool down, hovering;
-    if (!mCurrentMouseIdBits.isEmpty()) {
-        uint32_t id = mCurrentMouseIdBits.firstMarkedBit();
-        uint32_t currentIndex = mCurrentRawPointerData.idToIndex[id];
-        if (mLastMouseIdBits.hasBit(id)) {
-            uint32_t lastIndex = mCurrentRawPointerData.idToIndex[id];
-            float deltaX = (mCurrentRawPointerData.pointers[currentIndex].x
-                    - mLastRawPointerData.pointers[lastIndex].x)
+    if (!mCurrentCookedState.mouseIdBits.isEmpty()) {
+        uint32_t id = mCurrentCookedState.mouseIdBits.firstMarkedBit();
+        uint32_t currentIndex = mCurrentRawState.rawPointerData.idToIndex[id];
+        if (mLastCookedState.mouseIdBits.hasBit(id)) {
+            uint32_t lastIndex = mCurrentRawState.rawPointerData.idToIndex[id];
+            float deltaX = (mCurrentRawState.rawPointerData.pointers[currentIndex].x
+                    - mLastRawState.rawPointerData.pointers[lastIndex].x)
                     * mPointerXMovementScale;
-            float deltaY = (mCurrentRawPointerData.pointers[currentIndex].y
-                    - mLastRawPointerData.pointers[lastIndex].y)
+            float deltaY = (mCurrentRawState.rawPointerData.pointers[currentIndex].y
+                    - mLastRawState.rawPointerData.pointers[lastIndex].y)
                     * mPointerYMovementScale;
 
             rotateDelta(mSurfaceOrientation, &deltaX, &deltaY);
@@ -5496,20 +5872,20 @@
             mPointerVelocityControl.reset();
         }
 
-        down = isPointerDown(mCurrentButtonState);
+        down = isPointerDown(mCurrentRawState.buttonState);
         hovering = !down;
 
         float x, y;
         mPointerController->getPosition(&x, &y);
         mPointerSimple.currentCoords.copyFrom(
-                mCurrentCookedPointerData.pointerCoords[currentIndex]);
+                mCurrentCookedState.cookedPointerData.pointerCoords[currentIndex]);
         mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
         mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
         mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE,
                 hovering ? 0.0f : 1.0f);
         mPointerSimple.currentProperties.id = 0;
         mPointerSimple.currentProperties.toolType =
-                mCurrentCookedPointerData.pointerProperties[currentIndex].toolType;
+                mCurrentCookedState.cookedPointerData.pointerProperties[currentIndex].toolType;
     } else {
         mPointerVelocityControl.reset();
 
@@ -5534,7 +5910,7 @@
         if (down || hovering) {
             mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
             mPointerController->clearSpots();
-            mPointerController->setButtonState(mCurrentButtonState);
+            mPointerController->setButtonState(mCurrentRawState.buttonState);
             mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
         } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) {
             mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
@@ -5546,7 +5922,7 @@
 
         // Send up.
         NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
-                 AMOTION_EVENT_ACTION_UP, 0, metaState, mLastButtonState, 0,
+                 AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, 0,
                  mViewport.displayId,
                  1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
                  mOrientedXPrecision, mOrientedYPrecision,
@@ -5559,7 +5935,7 @@
 
         // Send hover exit.
         NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
-                AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastButtonState, 0,
+                AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState, 0,
                 mViewport.displayId,
                 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
@@ -5574,7 +5950,7 @@
 
             // Send down.
             NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
-                    AMOTION_EVENT_ACTION_DOWN, 0, metaState, mCurrentButtonState, 0,
+                    AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState, 0,
                     mViewport.displayId,
                     1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                     mOrientedXPrecision, mOrientedYPrecision,
@@ -5584,7 +5960,7 @@
 
         // Send move.
         NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
-                AMOTION_EVENT_ACTION_MOVE, 0, metaState, mCurrentButtonState, 0,
+                AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, 0,
                 mViewport.displayId,
                 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
@@ -5598,7 +5974,8 @@
 
             // Send hover enter.
             NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
-                    AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, mCurrentButtonState, 0,
+                    AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState,
+                    mCurrentRawState.buttonState, 0,
                     mViewport.displayId,
                     1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                     mOrientedXPrecision, mOrientedYPrecision,
@@ -5608,7 +5985,8 @@
 
         // Send hover move.
         NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
-                AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, mCurrentButtonState, 0,
+                AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
+                mCurrentRawState.buttonState, 0,
                 mViewport.displayId,
                 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
@@ -5616,9 +5994,9 @@
         getListener()->notifyMotion(&args);
     }
 
-    if (mCurrentRawVScroll || mCurrentRawHScroll) {
-        float vscroll = mCurrentRawVScroll;
-        float hscroll = mCurrentRawHScroll;
+    if (mCurrentRawState.rawVScroll || mCurrentRawState.rawHScroll) {
+        float vscroll = mCurrentRawState.rawVScroll;
+        float hscroll = mCurrentRawState.rawHScroll;
         mWheelYVelocityControl.move(when, NULL, &vscroll);
         mWheelXVelocityControl.move(when, &hscroll, NULL);
 
@@ -5629,7 +6007,7 @@
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
 
         NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
-                AMOTION_EVENT_ACTION_SCROLL, 0, metaState, mCurrentButtonState, 0,
+                AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState, 0,
                 mViewport.displayId,
                 1, &mPointerSimple.currentProperties, &pointerCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
@@ -5654,10 +6032,11 @@
 }
 
 void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
-        int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
+        int32_t action, int32_t actionButton, int32_t flags,
+        int32_t metaState, int32_t buttonState, int32_t edgeFlags,
         const PointerProperties* properties, const PointerCoords* coords,
-        const uint32_t* idToIndex, BitSet32 idBits,
-        int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) {
+        const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId,
+        float xPrecision, float yPrecision, nsecs_t downTime) {
     PointerCoords pointerCoords[MAX_POINTERS];
     PointerProperties pointerProperties[MAX_POINTERS];
     uint32_t pointerCount = 0;
@@ -5691,7 +6070,7 @@
     }
 
     NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
-            action, flags, metaState, buttonState, edgeFlags,
+            action, actionButton, flags, metaState, buttonState, edgeFlags,
             mViewport.displayId, pointerCount, pointerProperties, pointerCoords,
             xPrecision, yPrecision, downTime);
     getListener()->notifyMotion(&args);
@@ -5733,6 +6112,7 @@
 
 void TouchInputMapper::cancelTouch(nsecs_t when) {
     abortPointerUsage(when, 0 /*policyFlags*/);
+    abortTouches(when, 0 /* policyFlags*/);
 }
 
 bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) {
@@ -5763,11 +6143,11 @@
     return NULL;
 }
 
-void TouchInputMapper::assignPointerIds() {
-    uint32_t currentPointerCount = mCurrentRawPointerData.pointerCount;
-    uint32_t lastPointerCount = mLastRawPointerData.pointerCount;
+void TouchInputMapper::assignPointerIds(const RawState* last, RawState* current) {
+    uint32_t currentPointerCount = current->rawPointerData.pointerCount;
+    uint32_t lastPointerCount = last->rawPointerData.pointerCount;
 
-    mCurrentRawPointerData.clearIdBits();
+    current->rawPointerData.clearIdBits();
 
     if (currentPointerCount == 0) {
         // No pointers to assign.
@@ -5778,21 +6158,21 @@
         // All pointers are new.
         for (uint32_t i = 0; i < currentPointerCount; i++) {
             uint32_t id = i;
-            mCurrentRawPointerData.pointers[i].id = id;
-            mCurrentRawPointerData.idToIndex[id] = i;
-            mCurrentRawPointerData.markIdBit(id, mCurrentRawPointerData.isHovering(i));
+            current->rawPointerData.pointers[i].id = id;
+            current->rawPointerData.idToIndex[id] = i;
+            current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(i));
         }
         return;
     }
 
     if (currentPointerCount == 1 && lastPointerCount == 1
-            && mCurrentRawPointerData.pointers[0].toolType
-                    == mLastRawPointerData.pointers[0].toolType) {
+            && current->rawPointerData.pointers[0].toolType
+                    == last->rawPointerData.pointers[0].toolType) {
         // Only one pointer and no change in count so it must have the same id as before.
-        uint32_t id = mLastRawPointerData.pointers[0].id;
-        mCurrentRawPointerData.pointers[0].id = id;
-        mCurrentRawPointerData.idToIndex[id] = 0;
-        mCurrentRawPointerData.markIdBit(id, mCurrentRawPointerData.isHovering(0));
+        uint32_t id = last->rawPointerData.pointers[0].id;
+        current->rawPointerData.pointers[0].id = id;
+        current->rawPointerData.idToIndex[id] = 0;
+        current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(0));
         return;
     }
 
@@ -5810,9 +6190,9 @@
         for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount;
                 lastPointerIndex++) {
             const RawPointerData::Pointer& currentPointer =
-                    mCurrentRawPointerData.pointers[currentPointerIndex];
+                    current->rawPointerData.pointers[currentPointerIndex];
             const RawPointerData::Pointer& lastPointer =
-                    mLastRawPointerData.pointers[lastPointerIndex];
+                    last->rawPointerData.pointers[lastPointerIndex];
             if (currentPointer.toolType == lastPointer.toolType) {
                 int64_t deltaX = currentPointer.x - lastPointer.x;
                 int64_t deltaY = currentPointer.y - lastPointer.y;
@@ -5918,11 +6298,11 @@
             matchedCurrentBits.markBit(currentPointerIndex);
             matchedLastBits.markBit(lastPointerIndex);
 
-            uint32_t id = mLastRawPointerData.pointers[lastPointerIndex].id;
-            mCurrentRawPointerData.pointers[currentPointerIndex].id = id;
-            mCurrentRawPointerData.idToIndex[id] = currentPointerIndex;
-            mCurrentRawPointerData.markIdBit(id,
-                    mCurrentRawPointerData.isHovering(currentPointerIndex));
+            uint32_t id = last->rawPointerData.pointers[lastPointerIndex].id;
+            current->rawPointerData.pointers[currentPointerIndex].id = id;
+            current->rawPointerData.idToIndex[id] = currentPointerIndex;
+            current->rawPointerData.markIdBit(id,
+                    current->rawPointerData.isHovering(currentPointerIndex));
             usedIdBits.markBit(id);
 
 #if DEBUG_POINTER_ASSIGNMENT
@@ -5938,10 +6318,10 @@
         uint32_t currentPointerIndex = matchedCurrentBits.markFirstUnmarkedBit();
         uint32_t id = usedIdBits.markFirstUnmarkedBit();
 
-        mCurrentRawPointerData.pointers[currentPointerIndex].id = id;
-        mCurrentRawPointerData.idToIndex[id] = currentPointerIndex;
-        mCurrentRawPointerData.markIdBit(id,
-                mCurrentRawPointerData.isHovering(currentPointerIndex));
+        current->rawPointerData.pointers[currentPointerIndex].id = id;
+        current->rawPointerData.idToIndex[id] = currentPointerIndex;
+        current->rawPointerData.markIdBit(id,
+                current->rawPointerData.isHovering(currentPointerIndex));
 
 #if DEBUG_POINTER_ASSIGNMENT
         ALOGD("assignPointerIds - assigned: cur=%d, id=%d",
@@ -6020,18 +6400,18 @@
     mSingleTouchMotionAccumulator.process(rawEvent);
 }
 
-void SingleTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) {
+void SingleTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) {
     if (mTouchButtonAccumulator.isToolActive()) {
-        mCurrentRawPointerData.pointerCount = 1;
-        mCurrentRawPointerData.idToIndex[0] = 0;
+        outState->rawPointerData.pointerCount = 1;
+        outState->rawPointerData.idToIndex[0] = 0;
 
         bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE
                 && (mTouchButtonAccumulator.isHovering()
                         || (mRawPointerAxes.pressure.valid
                                 && mSingleTouchMotionAccumulator.getAbsolutePressure() <= 0));
-        mCurrentRawPointerData.markIdBit(0, isHovering);
+        outState->rawPointerData.markIdBit(0, isHovering);
 
-        RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[0];
+        RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[0];
         outPointer.id = 0;
         outPointer.x = mSingleTouchMotionAccumulator.getAbsoluteX();
         outPointer.y = mSingleTouchMotionAccumulator.getAbsoluteY();
@@ -6092,7 +6472,7 @@
     mMultiTouchMotionAccumulator.process(rawEvent);
 }
 
-void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) {
+void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) {
     size_t inCount = mMultiTouchMotionAccumulator.getSlotCount();
     size_t outCount = 0;
     BitSet32 newPointerIdBits;
@@ -6113,7 +6493,7 @@
             break; // too many fingers!
         }
 
-        RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[outCount];
+        RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[outCount];
         outPointer.x = inSlot->getX();
         outPointer.y = inSlot->getY();
         outPointer.pressure = inSlot->getPressure();
@@ -6140,38 +6520,37 @@
         outPointer.isHovering = isHovering;
 
         // Assign pointer id using tracking id if available.
-        if (*outHavePointerIds) {
-            int32_t trackingId = inSlot->getTrackingId();
-            int32_t id = -1;
-            if (trackingId >= 0) {
-                for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) {
-                    uint32_t n = idBits.clearFirstMarkedBit();
-                    if (mPointerTrackingIdMap[n] == trackingId) {
-                        id = n;
-                    }
+        mHavePointerIds = true;
+        int32_t trackingId = inSlot->getTrackingId();
+        int32_t id = -1;
+        if (trackingId >= 0) {
+            for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) {
+                uint32_t n = idBits.clearFirstMarkedBit();
+                if (mPointerTrackingIdMap[n] == trackingId) {
+                    id = n;
                 }
+            }
 
-                if (id < 0 && !mPointerIdBits.isFull()) {
-                    id = mPointerIdBits.markFirstUnmarkedBit();
-                    mPointerTrackingIdMap[id] = trackingId;
-                }
+            if (id < 0 && !mPointerIdBits.isFull()) {
+                id = mPointerIdBits.markFirstUnmarkedBit();
+                mPointerTrackingIdMap[id] = trackingId;
             }
-            if (id < 0) {
-                *outHavePointerIds = false;
-                mCurrentRawPointerData.clearIdBits();
-                newPointerIdBits.clear();
-            } else {
-                outPointer.id = id;
-                mCurrentRawPointerData.idToIndex[id] = outCount;
-                mCurrentRawPointerData.markIdBit(id, isHovering);
-                newPointerIdBits.markBit(id);
-            }
+        }
+        if (id < 0) {
+            mHavePointerIds = false;
+            outState->rawPointerData.clearIdBits();
+            newPointerIdBits.clear();
+        } else {
+            outPointer.id = id;
+            outState->rawPointerData.idToIndex[id] = outCount;
+            outState->rawPointerData.markIdBit(id, isHovering);
+            newPointerIdBits.markBit(id);
         }
 
         outCount += 1;
     }
 
-    mCurrentRawPointerData.pointerCount = outCount;
+    outState->rawPointerData.pointerCount = outCount;
     mPointerIdBits = newPointerIdBits;
 
     mMultiTouchMotionAccumulator.finishSync();
@@ -6215,6 +6594,77 @@
             || mTouchButtonAccumulator.hasStylus();
 }
 
+// --- ExternalStylusInputMapper
+
+ExternalStylusInputMapper::ExternalStylusInputMapper(InputDevice* device) :
+    InputMapper(device) {
+
+}
+
+uint32_t ExternalStylusInputMapper::getSources() {
+    return AINPUT_SOURCE_STYLUS;
+}
+
+void ExternalStylusInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
+    InputMapper::populateDeviceInfo(info);
+    info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, AINPUT_SOURCE_STYLUS,
+            0.0f, 1.0f, 0.0f, 0.0f, 0.0f);
+}
+
+void ExternalStylusInputMapper::dump(String8& dump) {
+    dump.append(INDENT2 "External Stylus Input Mapper:\n");
+    dump.append(INDENT3 "Raw Stylus Axes:\n");
+    dumpRawAbsoluteAxisInfo(dump, mRawPressureAxis, "Pressure");
+    dump.append(INDENT3 "Stylus State:\n");
+    dumpStylusState(dump, mStylusState);
+}
+
+void ExternalStylusInputMapper::configure(nsecs_t when,
+        const InputReaderConfiguration* config, uint32_t changes) {
+    getAbsoluteAxisInfo(ABS_PRESSURE, &mRawPressureAxis);
+    mTouchButtonAccumulator.configure(getDevice());
+}
+
+void ExternalStylusInputMapper::reset(nsecs_t when) {
+    InputDevice* device = getDevice();
+    mSingleTouchMotionAccumulator.reset(device);
+    mTouchButtonAccumulator.reset(device);
+    InputMapper::reset(when);
+}
+
+void ExternalStylusInputMapper::process(const RawEvent* rawEvent) {
+    mSingleTouchMotionAccumulator.process(rawEvent);
+    mTouchButtonAccumulator.process(rawEvent);
+
+    if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
+        sync(rawEvent->when);
+    }
+}
+
+void ExternalStylusInputMapper::sync(nsecs_t when) {
+    mStylusState.clear();
+
+    mStylusState.when = when;
+
+    mStylusState.toolType = mTouchButtonAccumulator.getToolType();
+    if (mStylusState.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
+        mStylusState.toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+    }
+
+    int32_t pressure = mSingleTouchMotionAccumulator.getAbsolutePressure();
+    if (mRawPressureAxis.valid) {
+        mStylusState.pressure = float(pressure) / mRawPressureAxis.maxValue;
+    } else if (mTouchButtonAccumulator.isToolActive()) {
+        mStylusState.pressure = 1.0f;
+    } else {
+        mStylusState.pressure = 0.0f;
+    }
+
+    mStylusState.buttons = mTouchButtonAccumulator.getButtonState();
+
+    mContext->dispatchExternalStylusState(mStylusState);
+}
+
 
 // --- JoystickInputMapper ---
 
@@ -6538,7 +6988,7 @@
     uint32_t policyFlags = 0;
 
     NotifyMotionArgs args(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, policyFlags,
-            AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+            AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
             ADISPLAY_ID_NONE, 1, &pointerProperties, &pointerCoords, 0, 0, 0);
     getListener()->notifyMotion(&args);
 }
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index 34f20af..7cb4680 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -139,7 +139,10 @@
         CHANGE_DEVICE_ALIAS = 1 << 5,
 
         // The location calibration matrix changed.
-        TOUCH_AFFINE_TRANSFORMATION = 1 << 6,
+        CHANGE_TOUCH_AFFINE_TRANSFORMATION = 1 << 6,
+
+        // The presence of an external stylus has changed.
+        CHANGE_EXTERNAL_STYLUS_PRESENCE = 1 << 7,
 
         // All devices must be reopened.
         CHANGE_MUST_REOPEN = 1 << 31,
@@ -371,6 +374,31 @@
     virtual void cancelVibrate(int32_t deviceId, int32_t token) = 0;
 };
 
+struct StylusState {
+    /* Time the stylus event was received. */
+    nsecs_t when;
+    /* Pressure as reported by the stylus, normalized to the range [0, 1.0]. */
+    float pressure;
+    /* The state of the stylus buttons as a bitfield (e.g. AMOTION_EVENT_BUTTON_SECONDARY). */
+    uint32_t buttons;
+    /* Which tool type the stylus is currently using (e.g. AMOTION_EVENT_TOOL_TYPE_ERASER). */
+    int32_t toolType;
+
+    void copyFrom(const StylusState& other) {
+        when = other.when;
+        pressure = other.pressure;
+        buttons = other.buttons;
+        toolType = other.toolType;
+    }
+
+    void clear() {
+        when = LLONG_MAX;
+        pressure = 0.f;
+        buttons = 0;
+        toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN;
+    }
+};
+
 
 /* Internal interface used by individual input devices to access global input device state
  * and parameters maintained by the input reader.
@@ -392,6 +420,9 @@
     virtual void requestTimeoutAtTime(nsecs_t when) = 0;
     virtual int32_t bumpGeneration() = 0;
 
+    virtual void getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices) = 0;
+    virtual void dispatchExternalStylusState(const StylusState& outState) = 0;
+
     virtual InputReaderPolicyInterface* getPolicy() = 0;
     virtual InputListenerInterface* getListener() = 0;
     virtual EventHubInterface* getEventHub() = 0;
@@ -458,6 +489,8 @@
         virtual void fadePointer();
         virtual void requestTimeoutAtTime(nsecs_t when);
         virtual int32_t bumpGeneration();
+        virtual void getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices);
+        virtual void dispatchExternalStylusState(const StylusState& outState);
         virtual InputReaderPolicyInterface* getPolicy();
         virtual InputListenerInterface* getListener();
         virtual EventHubInterface* getEventHub();
@@ -496,6 +529,10 @@
     void updateGlobalMetaStateLocked();
     int32_t getGlobalMetaStateLocked();
 
+    void notifyExternalStylusPresenceChanged();
+    void getExternalStylusDevicesLocked(Vector<InputDeviceInfo>& outDevices);
+    void dispatchExternalStylusState(const StylusState& state);
+
     void fadePointerLocked();
 
     int32_t mGeneration;
@@ -555,6 +592,9 @@
     inline bool isExternal() { return mIsExternal; }
     inline void setExternal(bool external) { mIsExternal = external; }
 
+    inline void setMic(bool hasMic) { mHasMic = hasMic; }
+    inline bool hasMic() const { return mHasMic; }
+
     inline bool isIgnored() { return mMappers.isEmpty(); }
 
     void dump(String8& dump);
@@ -563,6 +603,7 @@
     void reset(nsecs_t when);
     void process(const RawEvent* rawEvents, size_t count);
     void timeoutExpired(nsecs_t when);
+    void updateExternalStylusState(const StylusState& state);
 
     void getDeviceInfo(InputDeviceInfo* outDeviceInfo);
     int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode);
@@ -618,6 +659,7 @@
 
     uint32_t mSources;
     bool mIsExternal;
+    bool mHasMic;
     bool mDropUntilNextSync;
 
     typedef int32_t (InputMapper::*GetStateFunc)(uint32_t sourceMask, int32_t code);
@@ -831,9 +873,21 @@
         return pointerCoords[idToIndex[id]];
     }
 
-    inline bool isHovering(uint32_t pointerIndex) {
+    inline PointerCoords& editPointerCoordsWithId(uint32_t id) {
+        return pointerCoords[idToIndex[id]];
+    }
+
+    inline PointerProperties& editPointerPropertiesWithId(uint32_t id) {
+        return pointerProperties[idToIndex[id]];
+    }
+
+    inline bool isHovering(uint32_t pointerIndex) const {
         return hoveringIdBits.hasBit(pointerProperties[pointerIndex].id);
     }
+
+    inline bool isTouching(uint32_t pointerIndex) const {
+        return touchingIdBits.hasBit(pointerProperties[pointerIndex].id);
+    }
 };
 
 
@@ -978,6 +1032,8 @@
 
     virtual int32_t getMetaState();
 
+    virtual void updateExternalStylusState(const StylusState& state);
+
     virtual void fadePointer();
 
 protected:
@@ -989,6 +1045,7 @@
 
     static void dumpRawAbsoluteAxisInfo(String8& dump,
             const RawAbsoluteAxisInfo& axis, const char* name);
+    static void dumpStylusState(String8& dump, const StylusState& state);
 };
 
 
@@ -1195,6 +1252,7 @@
     virtual void fadePointer();
     virtual void cancelTouch(nsecs_t when);
     virtual void timeoutExpired(nsecs_t when);
+    virtual void updateExternalStylusState(const StylusState& state);
 
 protected:
     CursorButtonAccumulator mCursorButtonAccumulator;
@@ -1334,36 +1392,86 @@
     // Affine location transformation/calibration
     struct TouchAffineTransformation mAffineTransform;
 
-    // Raw pointer axis information from the driver.
     RawPointerAxes mRawPointerAxes;
 
-    // Raw pointer sample data.
-    RawPointerData mCurrentRawPointerData;
-    RawPointerData mLastRawPointerData;
+    struct RawState {
+        nsecs_t when;
 
-    // Cooked pointer sample data.
-    CookedPointerData mCurrentCookedPointerData;
-    CookedPointerData mLastCookedPointerData;
+        // Raw pointer sample data.
+        RawPointerData rawPointerData;
 
-    // Button state.
-    int32_t mCurrentButtonState;
-    int32_t mLastButtonState;
+        int32_t buttonState;
 
-    // Scroll state.
-    int32_t mCurrentRawVScroll;
-    int32_t mCurrentRawHScroll;
+        // Scroll state.
+        int32_t rawVScroll;
+        int32_t rawHScroll;
 
-    // Id bits used to differentiate fingers, stylus and mouse tools.
-    BitSet32 mCurrentFingerIdBits; // finger or unknown
-    BitSet32 mLastFingerIdBits;
-    BitSet32 mCurrentStylusIdBits; // stylus or eraser
-    BitSet32 mLastStylusIdBits;
-    BitSet32 mCurrentMouseIdBits; // mouse or lens
-    BitSet32 mLastMouseIdBits;
+        void copyFrom(const RawState& other) {
+            when = other.when;
+            rawPointerData.copyFrom(other.rawPointerData);
+            buttonState = other.buttonState;
+            rawVScroll = other.rawVScroll;
+            rawHScroll = other.rawHScroll;
+        }
+
+        void clear() {
+            when = 0;
+            rawPointerData.clear();
+            buttonState = 0;
+            rawVScroll = 0;
+            rawHScroll = 0;
+        }
+    };
+
+    struct CookedState {
+        // Cooked pointer sample data.
+        CookedPointerData cookedPointerData;
+
+        // Id bits used to differentiate fingers, stylus and mouse tools.
+        BitSet32 fingerIdBits;
+        BitSet32 stylusIdBits;
+        BitSet32 mouseIdBits;
+
+        int32_t buttonState;
+
+        void copyFrom(const CookedState& other) {
+            cookedPointerData.copyFrom(other.cookedPointerData);
+            fingerIdBits = other.fingerIdBits;
+            stylusIdBits = other.stylusIdBits;
+            mouseIdBits = other.mouseIdBits;
+            buttonState = other.buttonState;
+        }
+
+        void clear() {
+            cookedPointerData.clear();
+            fingerIdBits.clear();
+            stylusIdBits.clear();
+            mouseIdBits.clear();
+            buttonState = 0;
+        }
+    };
+
+    Vector<RawState> mRawStatesPending;
+    RawState mCurrentRawState;
+    CookedState mCurrentCookedState;
+    RawState mLastRawState;
+    CookedState mLastCookedState;
+
+    // State provided by an external stylus
+    StylusState mExternalStylusState;
+    int64_t mExternalStylusId;
+    nsecs_t mExternalStylusFusionTimeout;
+    bool mExternalStylusDataPending;
 
     // True if we sent a HOVER_ENTER event.
     bool mSentHoverEnter;
 
+    // Have we assigned pointer IDs for this stream
+    bool mHavePointerIds;
+
+    // Is the current stream of direct touch events aborted
+    bool mCurrentMotionAborted;
+
     // The time the primary pointer last went down.
     nsecs_t mDownTime;
 
@@ -1383,11 +1491,13 @@
     virtual void parseCalibration();
     virtual void resolveCalibration();
     virtual void dumpCalibration(String8& dump);
-    virtual void dumpAffineTransformation(String8& dump);
-    virtual bool hasStylus() const = 0;
     virtual void updateAffineTransformation();
+    virtual void dumpAffineTransformation(String8& dump);
+    virtual void resolveExternalStylusPresence();
+    virtual bool hasStylus() const = 0;
+    virtual bool hasExternalStylus() const;
 
-    virtual void syncTouch(nsecs_t when, bool* outHavePointerIds) = 0;
+    virtual void syncTouch(nsecs_t when, RawState* outState) = 0;
 
 private:
     // The current viewport.
@@ -1433,6 +1543,8 @@
     float mTiltYCenter;
     float mTiltYScale;
 
+    bool mExternalStylusConnected;
+
     // Oriented motion ranges for input device info.
     struct OrientedRanges {
         InputDeviceInfo::MotionRange x;
@@ -1675,16 +1787,25 @@
     VelocityControl mWheelXVelocityControl;
     VelocityControl mWheelYVelocityControl;
 
+    void resetExternalStylus();
+    void clearStylusDataPendingFlags();
+
     void sync(nsecs_t when);
 
     bool consumeRawTouches(nsecs_t when, uint32_t policyFlags);
+    void processRawTouches(bool timeout);
+    void cookAndDispatch(nsecs_t when);
     void dispatchVirtualKey(nsecs_t when, uint32_t policyFlags,
             int32_t keyEventAction, int32_t keyEventFlags);
 
     void dispatchTouches(nsecs_t when, uint32_t policyFlags);
     void dispatchHoverExit(nsecs_t when, uint32_t policyFlags);
     void dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags);
+    void dispatchButtonRelease(nsecs_t when, uint32_t policyFlags);
+    void dispatchButtonPress(nsecs_t when, uint32_t policyFlags);
+    const BitSet32& findActiveIdBits(const CookedPointerData& cookedPointerData);
     void cookPointerData();
+    void abortTouches(nsecs_t when, uint32_t policyFlags);
 
     void dispatchPointerUsage(nsecs_t when, uint32_t policyFlags, PointerUsage pointerUsage);
     void abortPointerUsage(nsecs_t when, uint32_t policyFlags);
@@ -1705,13 +1826,17 @@
             bool down, bool hovering);
     void abortPointerSimple(nsecs_t when, uint32_t policyFlags);
 
+    bool assignExternalStylusId(const RawState& state, bool timeout);
+    void applyExternalStylusButtonState(nsecs_t when);
+    void applyExternalStylusTouchState(nsecs_t when);
+
     // Dispatches a motion event.
     // If the changedId is >= 0 and the action is POINTER_DOWN or POINTER_UP, the
     // method will take care of setting the index and transmuting the action to DOWN or UP
     // it is the first / last pointer to go down / up.
     void dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
-            int32_t action, int32_t flags, int32_t metaState, int32_t buttonState,
-            int32_t edgeFlags,
+            int32_t action, int32_t actionButton,
+            int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
             const PointerProperties* properties, const PointerCoords* coords,
             const uint32_t* idToIndex, BitSet32 idBits,
             int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime);
@@ -1726,7 +1851,7 @@
     bool isPointInsideSurface(int32_t x, int32_t y);
     const VirtualKey* findVirtualKeyHit(int32_t x, int32_t y);
 
-    void assignPointerIds();
+    static void assignPointerIds(const RawState* last, RawState* current);
 };
 
 
@@ -1739,7 +1864,7 @@
     virtual void process(const RawEvent* rawEvent);
 
 protected:
-    virtual void syncTouch(nsecs_t when, bool* outHavePointerIds);
+    virtual void syncTouch(nsecs_t when, RawState* outState);
     virtual void configureRawPointerAxes();
     virtual bool hasStylus() const;
 
@@ -1757,7 +1882,7 @@
     virtual void process(const RawEvent* rawEvent);
 
 protected:
-    virtual void syncTouch(nsecs_t when, bool* outHavePointerIds);
+    virtual void syncTouch(nsecs_t when, RawState* outState);
     virtual void configureRawPointerAxes();
     virtual bool hasStylus() const;
 
@@ -1769,6 +1894,27 @@
     int32_t mPointerTrackingIdMap[MAX_POINTER_ID + 1];
 };
 
+class ExternalStylusInputMapper : public InputMapper {
+public:
+    ExternalStylusInputMapper(InputDevice* device);
+    virtual ~ExternalStylusInputMapper() = default;
+
+    virtual uint32_t getSources();
+    virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
+    virtual void dump(String8& dump);
+    virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
+    virtual void reset(nsecs_t when);
+    virtual void process(const RawEvent* rawEvent);
+    virtual void sync(nsecs_t when);
+
+private:
+    SingleTouchMotionAccumulator mSingleTouchMotionAccumulator;
+    RawAbsoluteAxisInfo mRawPressureAxis;
+    TouchButtonAccumulator mTouchButtonAccumulator;
+
+    StylusState mStylusState;
+};
+
 
 class JoystickInputMapper : public InputMapper {
 public:
diff --git a/services/inputflinger/host/Android.mk b/services/inputflinger/host/Android.mk
new file mode 100644
index 0000000..b828175
--- /dev/null
+++ b/services/inputflinger/host/Android.mk
@@ -0,0 +1,62 @@
+# Copyright (C) 2015 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_CLANG := true
+
+LOCAL_SRC_FILES:= \
+    InputFlinger.cpp \
+    InputDriver.cpp \
+    InputHost.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+    libbinder \
+    libcrypto \
+    libcutils \
+    libinput \
+    liblog \
+    libutils \
+    libhardware
+
+
+# TODO: Move inputflinger to its own process and mark it hidden
+#LOCAL_CFLAGS += -fvisibility=hidden
+
+LOCAL_CFLAGS += -Wno-unused-parameter
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+
+LOCAL_MODULE := libinputflingerhost
+
+include $(BUILD_SHARED_LIBRARY)
+
+########################################################################
+# build input flinger executable
+include $(CLEAR_VARS)
+
+LOCAL_CLANG := true
+
+LOCAL_SRC_FILES:= \
+	main.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libbinder \
+	libinputflingerhost \
+	libutils
+
+LOCAL_MODULE := inputflinger
+
+include $(BUILD_EXECUTABLE)
diff --git a/services/inputflinger/host/InputDriver.cpp b/services/inputflinger/host/InputDriver.cpp
new file mode 100644
index 0000000..630a596
--- /dev/null
+++ b/services/inputflinger/host/InputDriver.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2015 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 <stdint.h>
+#include <sys/types.h>
+
+#define LOG_TAG "InputDriver"
+
+#define LOG_NDEBUG 0
+
+#include "InputDriver.h"
+#include "InputHost.h"
+
+#include <hardware/input.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#define INDENT2 "    "
+
+namespace android {
+
+static input_host_callbacks_t kCallbacks = {
+    .create_device_identifier = create_device_identifier,
+    .create_device_definition = create_device_definition,
+    .create_input_report_definition = create_input_report_definition,
+    .create_output_report_definition = create_output_report_definition,
+    .input_device_definition_add_report = input_device_definition_add_report,
+    .input_report_definition_add_collection = input_report_definition_add_collection,
+    .input_report_definition_declare_usage_int = input_report_definition_declare_usage_int,
+    .input_report_definition_declare_usages_bool = input_report_definition_declare_usages_bool,
+    .register_device = register_device,
+    .input_allocate_report = input_allocate_report,
+    .input_report_set_usage_int = input_report_set_usage_int,
+    .input_report_set_usage_bool = input_report_set_usage_bool,
+    .report_event = report_event,
+    .input_get_device_property_map = input_get_device_property_map,
+    .input_get_device_property = input_get_device_property,
+    .input_get_property_key = input_get_property_key,
+    .input_get_property_value = input_get_property_value,
+    .input_free_device_property = input_free_device_property,
+    .input_free_device_property_map = input_free_device_property_map,
+};
+
+InputDriver::InputDriver(const char* name) : mName(String8(name)) {
+    const hw_module_t* module;
+    int err = input_open(&module, name);
+    LOG_ALWAYS_FATAL_IF(err != 0, "Input module %s not found", name);
+    mHal = reinterpret_cast<const input_module_t*>(module);
+}
+
+void InputDriver::init(InputHostInterface* host) {
+    mHal->init(mHal, static_cast<input_host_t*>(host), kCallbacks);
+}
+
+void InputDriver::dump(String8& result) {
+    result.appendFormat(INDENT2 "HAL Input Driver (%s)\n", mName.string());
+}
+
+
+// HAL wrapper functions
+
+input_device_identifier_t* create_device_identifier(input_host_t* host,
+        const char* name, int32_t product_id, int32_t vendor_id,
+        input_bus_t bus, const char* unique_id) {
+    return nullptr;
+}
+
+input_device_definition_t* create_device_definition(input_host_t* host) {
+    return nullptr;
+}
+
+input_report_definition_t* create_input_report_definition(input_host_t* host) {
+    return nullptr;
+}
+
+input_report_definition_t* create_output_report_definition(input_host_t* host) {
+    return nullptr;
+}
+
+void input_device_definition_add_report(input_host_t* host,
+        input_device_definition_t* d, input_report_definition_t* r) { }
+
+void input_report_definition_add_collection(input_host_t* host,
+        input_report_definition_t* report, input_collection_id_t id, int32_t arity) { }
+
+void input_report_definition_declare_usage_int(input_host_t* host,
+        input_report_definition_t* report, input_collection_id_t id,
+        input_usage_t usage, int32_t min, int32_t max, float resolution) { }
+
+void input_report_definition_declare_usages_bool(input_host_t* host,
+        input_report_definition_t* report, input_collection_id_t id,
+        input_usage_t* usage, size_t usage_count) { }
+
+
+input_device_handle_t* register_device(input_host_t* host,
+        input_device_identifier_t* id, input_device_definition_t* d) {
+    return nullptr;
+}
+
+input_report_t* input_allocate_report(input_host_t* host, input_report_definition_t* r) {
+    return nullptr;
+}
+void input_report_set_usage_int(input_host_t* host, input_report_t* r,
+        input_collection_id_t id, input_usage_t usage, int32_t value, int32_t arity_index) { }
+
+void input_report_set_usage_bool(input_host_t* host, input_report_t* r,
+        input_collection_id_t id, input_usage_t usage, bool value, int32_t arity_index) { }
+
+void report_event(input_host_t* host, input_device_handle_t* d, input_report_t* report) { }
+
+input_property_map_t* input_get_device_property_map(input_host_t* host,
+        input_device_identifier_t* id) {
+    return nullptr;
+}
+
+input_property_t* input_get_device_property(input_host_t* host, input_property_map_t* map,
+        const char* key) {
+    return nullptr;
+}
+
+const char* input_get_property_key(input_host_t* host, input_property_t* property) {
+    return nullptr;
+}
+
+const char* input_get_property_value(input_host_t* host, input_property_t* property) {
+    return nullptr;
+}
+
+void input_free_device_property(input_host_t* host, input_property_t* property) { }
+
+void input_free_device_property_map(input_host_t* host, input_property_map_t* map) { }
+
+} // namespace android
diff --git a/services/inputflinger/host/InputDriver.h b/services/inputflinger/host/InputDriver.h
new file mode 100644
index 0000000..7734ac2
--- /dev/null
+++ b/services/inputflinger/host/InputDriver.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2015 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_INPUT_DRIVER_H
+#define ANDROID_INPUT_DRIVER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "InputHost.h"
+
+#include <hardware/input.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+
+namespace android {
+
+class InputHostInterface;
+
+class InputDriverInterface : public virtual RefBase {
+protected:
+    InputDriverInterface() = default;
+    virtual ~InputDriverInterface() = default;
+
+public:
+    virtual void init(InputHostInterface* host) = 0;
+
+    virtual void dump(String8& result) = 0;
+};
+
+class InputDriver : public InputDriverInterface {
+public:
+    InputDriver(const char* name);
+    virtual ~InputDriver() = default;
+
+    virtual void init(InputHostInterface* host) override;
+
+    virtual void dump(String8& result) override;
+
+private:
+    String8 mName;
+    const input_module_t* mHal;
+};
+
+
+extern "C" {
+
+input_device_identifier_t* create_device_identifier(input_host_t* host,
+        const char* name, int32_t product_id, int32_t vendor_id,
+        input_bus_t bus, const char* unique_id);
+
+input_device_definition_t* create_device_definition(input_host_t* host);
+
+input_report_definition_t* create_input_report_definition(input_host_t* host);
+
+input_report_definition_t* create_output_report_definition(input_host_t* host);
+
+void input_device_definition_add_report(input_host_t* host,
+        input_device_definition_t* d, input_report_definition_t* r);
+
+void input_report_definition_add_collection(input_host_t* host,
+        input_report_definition_t* report, input_collection_id_t id, int32_t arity);
+
+void input_report_definition_declare_usage_int(input_host_t* host,
+        input_report_definition_t* report, input_collection_id_t id,
+        input_usage_t usage, int32_t min, int32_t max, float resolution);
+
+void input_report_definition_declare_usages_bool(input_host_t* host,
+        input_report_definition_t* report, input_collection_id_t id,
+        input_usage_t* usage, size_t usage_count);
+
+
+input_device_handle_t* register_device(input_host_t* host,
+        input_device_identifier_t* id, input_device_definition_t* d);
+
+void unregister_device(input_host_t* host, input_device_handle_t* handle);
+
+input_report_t* input_allocate_report(input_host_t* host, input_report_definition_t* r);
+
+void input_report_set_usage_int(input_host_t* host, input_report_t* r,
+        input_collection_id_t id, input_usage_t usage, int32_t value, int32_t arity_index);
+
+void input_report_set_usage_bool(input_host_t* host, input_report_t* r,
+        input_collection_id_t id, input_usage_t usage, bool value, int32_t arity_index);
+
+void report_event(input_host_t* host, input_device_handle_t* d, input_report_t* report);
+
+input_property_map_t* input_get_device_property_map(input_host_t* host,
+        input_device_identifier_t* id);
+
+input_property_t* input_get_device_property(input_host_t* host, input_property_map_t* map,
+        const char* key);
+
+const char* input_get_property_key(input_host_t* host, input_property_t* property);
+
+const char* input_get_property_value(input_host_t* host, input_property_t* property);
+
+void input_free_device_property(input_host_t* host, input_property_t* property);
+
+void input_free_device_property_map(input_host_t* host, input_property_map_t* map);
+}
+
+} // namespace android
+#endif // ANDROID_INPUT_DRIVER_H
diff --git a/services/inputflinger/host/InputFlinger.cpp b/services/inputflinger/host/InputFlinger.cpp
new file mode 100644
index 0000000..859c3b8
--- /dev/null
+++ b/services/inputflinger/host/InputFlinger.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#define LOG_TAG "InputFlinger"
+
+
+#include <stdint.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+
+#include "InputFlinger.h"
+#include "InputDriver.h"
+
+#include <binder/IPCThreadState.h>
+#include <binder/PermissionCache.h>
+#include <hardware/input.h>
+#include <cutils/log.h>
+#include <private/android_filesystem_config.h>
+
+namespace android {
+
+const String16 sAccessInputFlingerPermission("android.permission.ACCESS_INPUT_FLINGER");
+const String16 sDumpPermission("android.permission.DUMP");
+
+
+InputFlinger::InputFlinger() :
+        BnInputFlinger() {
+    ALOGI("InputFlinger is starting");
+    mHost = new InputHost();
+    mHost->registerInputDriver(new InputDriver(INPUT_INSTANCE_EVDEV));
+}
+
+InputFlinger::~InputFlinger() {
+}
+
+status_t InputFlinger::dump(int fd, const Vector<String16>& args) {
+    String8 result;
+    const IPCThreadState* ipc = IPCThreadState::self();
+    const int pid = ipc->getCallingPid();
+    const int uid = ipc->getCallingUid();
+    if ((uid != AID_SHELL)
+            && !PermissionCache::checkPermission(sDumpPermission, pid, uid)) {
+        result.appendFormat("Permission Denial: "
+                "can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid);
+    } else {
+        dumpInternal(result);
+    }
+    write(fd, result.string(), result.size());
+    return OK;
+}
+
+void InputFlinger::dumpInternal(String8& result) {
+    result.append("INPUT FLINGER (dumpsys inputflinger)\n");
+    mHost->dump(result);
+}
+
+}; // namespace android
diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h
new file mode 100644
index 0000000..39e69e5
--- /dev/null
+++ b/services/inputflinger/host/InputFlinger.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2013 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_INPUT_FLINGER_H
+#define ANDROID_INPUT_FLINGER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "InputHost.h"
+
+#include <cutils/compiler.h>
+#include <input/IInputFlinger.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+class InputFlinger : public BnInputFlinger {
+public:
+    static char const* getServiceName() ANDROID_API {
+        return "inputflinger";
+    }
+
+    InputFlinger() ANDROID_API;
+
+    virtual status_t dump(int fd, const Vector<String16>& args);
+
+private:
+    virtual ~InputFlinger();
+
+    void dumpInternal(String8& result);
+
+    sp<InputHostInterface> mHost;
+};
+
+} // namespace android
+
+#endif // ANDROID_INPUT_FLINGER_H
diff --git a/services/inputflinger/host/InputHost.cpp b/services/inputflinger/host/InputHost.cpp
new file mode 100644
index 0000000..51d3e6b
--- /dev/null
+++ b/services/inputflinger/host/InputHost.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015 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 <vector>
+
+#include "InputDriver.h"
+#include "InputHost.h"
+
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#define INDENT "  "
+
+namespace android {
+
+void InputHost::registerInputDriver(InputDriverInterface* driver) {
+    LOG_ALWAYS_FATAL_IF(driver == nullptr, "Cannot register a nullptr as an InputDriver!");
+    driver->init(this);
+    mDrivers.push_back(driver);
+}
+
+void InputHost::dump(String8& result) {
+    result.append(INDENT "Input Drivers:\n");
+    for (size_t i = 0; i < mDrivers.size(); i++) {
+        mDrivers[i]->dump(result);
+    }
+}
+
+} // namespace android
diff --git a/services/inputflinger/host/InputHost.h b/services/inputflinger/host/InputHost.h
new file mode 100644
index 0000000..42a66e0
--- /dev/null
+++ b/services/inputflinger/host/InputHost.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 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_INPUT_HOST_H
+#define ANDROID_INPUT_HOST_H
+
+#include <vector>
+
+#include <hardware/input.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/StrongPointer.h>
+
+#include "InputDriver.h"
+
+// Declare a concrete type for the HAL
+struct input_host {
+};
+
+namespace android {
+
+class InputDriverInterface;
+
+class InputHostInterface : public input_host_t, public virtual RefBase {
+protected:
+    InputHostInterface() = default;
+    virtual ~InputHostInterface() = default;
+
+public:
+
+    virtual void registerInputDriver(InputDriverInterface* driver) = 0;
+
+    virtual void dump(String8& result) = 0;
+};
+
+class InputHost : public InputHostInterface {
+public:
+    InputHost() = default;
+
+    virtual void registerInputDriver(InputDriverInterface* driver) override;
+
+    virtual void dump(String8& result) override;
+
+private:
+    std::vector<sp<InputDriverInterface>> mDrivers;
+};
+
+} // namespace android
+#endif // ANDRIOD_INPUT_HOST_H
diff --git a/services/inputflinger/host/main.cpp b/services/inputflinger/host/main.cpp
new file mode 100644
index 0000000..0a517cc
--- /dev/null
+++ b/services/inputflinger/host/main.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2013 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 <binder/BinderService.h>
+#include "InputFlinger.h"
+
+using namespace android;
+
+int main(int, char**) {
+    ProcessState::self()->setThreadPoolMaxThreadCount(4);
+    BinderService<InputFlinger>::publishAndJoinThreadPool(true);
+    return 0;
+}
diff --git a/services/inputflinger/tests/Android.mk b/services/inputflinger/tests/Android.mk
index 0742a08..4c43392 100644
--- a/services/inputflinger/tests/Android.mk
+++ b/services/inputflinger/tests/Android.mk
@@ -10,7 +10,6 @@
 shared_libraries := \
     libcutils \
     liblog \
-    libandroidfw \
     libutils \
     libhardware \
     libhardware_legacy \
@@ -24,7 +23,7 @@
     external/skia/include/core
 
 
-module_tags := eng tests
+module_tags := tests
 
 $(foreach file,$(test_src_files), \
     $(eval include $(CLEAR_VARS)) \
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 9b68986..2d8eaef 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -150,7 +150,7 @@
 
     // Rejects undefined motion actions.
     event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
-            /*action*/ -1, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+            /*action*/ -1, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -161,7 +161,7 @@
     // Rejects pointer down with invalid index.
     event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
             AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+            0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -171,7 +171,7 @@
 
     event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
             AMOTION_EVENT_ACTION_POINTER_DOWN | (-1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+            0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -182,7 +182,7 @@
     // Rejects pointer up with invalid index.
     event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
             AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+            0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -192,7 +192,7 @@
 
     event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
             AMOTION_EVENT_ACTION_POINTER_UP | (-1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+            0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -202,7 +202,7 @@
 
     // Rejects motion events with invalid number of pointers.
     event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
-            AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+            AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ 0, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -211,7 +211,7 @@
             << "Should reject motion events with 0 pointers.";
 
     event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
-            AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+            AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -222,7 +222,7 @@
     // Rejects motion events with invalid pointer ids.
     pointerProperties[0].id = -1;
     event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
-            AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+            AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -232,7 +232,7 @@
 
     pointerProperties[0].id = MAX_POINTER_ID + 1;
     event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
-            AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+            AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -244,7 +244,7 @@
     pointerProperties[0].id = 1;
     pointerProperties[1].id = 1;
     event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
-            AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+            AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ 2, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 40f51b6..f34b810 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -777,6 +777,14 @@
     virtual int32_t bumpGeneration() {
         return ++mGeneration;
     }
+
+    virtual void getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices) {
+
+    }
+
+    virtual void dispatchExternalStylusState(const StylusState&) {
+
+    }
 };
 
 
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 80845a2..dd1bccf 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -79,16 +79,17 @@
     sensor_t const* list;
     ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list);
 
-    result.appendFormat("halVersion %d\n", getHalDeviceVersion());
+    result.appendFormat("halVersion 0x%08x\n", getHalDeviceVersion());
     result.appendFormat("%d h/w sensors:\n", int(count));
 
     Mutex::Autolock _l(mLock);
     for (size_t i=0 ; i<size_t(count) ; i++) {
         const Info& info = mActivationCount.valueFor(list[i].handle);
+        if (info.batchParams.isEmpty()) continue;
         result.appendFormat("handle=0x%08x, active-count=%zu, batch_period(ms)={ ", list[i].handle,
                             info.batchParams.size());
         for (size_t j = 0; j < info.batchParams.size(); j++) {
-            BatchParams params = info.batchParams.valueAt(j);
+            const BatchParams& params = info.batchParams.valueAt(j);
             result.appendFormat("%4.1f%s", params.batchDelay / 1e6f,
                                 j < info.batchParams.size() - 1 ? ", " : "");
         }
@@ -147,8 +148,12 @@
     if (enabled) {
         ALOGD_IF(DEBUG_CONNECTIONS, "enable index=%zd", info.batchParams.indexOfKey(ident));
 
+        if (isClientDisabledLocked(ident)) {
+            return INVALID_OPERATION;
+        }
+
         if (info.batchParams.indexOfKey(ident) >= 0) {
-          if (info.batchParams.size() == 1) {
+          if (info.numActiveClients() == 1) {
               // This is the first connection, we need to activate the underlying h/w sensor.
               actuateHardware = true;
           }
@@ -160,7 +165,7 @@
         ALOGD_IF(DEBUG_CONNECTIONS, "disable index=%zd", info.batchParams.indexOfKey(ident));
 
         if (info.removeBatchParamsForIdent(ident) >= 0) {
-            if (info.batchParams.size() == 0) {
+            if (info.numActiveClients() == 0) {
                 // This is the last connection, we need to de-activate the underlying h/w sensor.
                 actuateHardware = true;
             } else {
@@ -181,10 +186,15 @@
         } else {
             // sensor wasn't enabled for this ident
         }
+
+        if (isClientDisabledLocked(ident)) {
+            return NO_ERROR;
+        }
     }
 
     if (actuateHardware) {
-        ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w activate handle=%d enabled=%d", handle, enabled);
+        ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w activate handle=%d enabled=%d", handle,
+                 enabled);
         err = mSensorDevice->activate(
                 reinterpret_cast<struct sensors_poll_device_t *> (mSensorDevice), handle, enabled);
         ALOGE_IF(err, "Error %s sensor %d (%s)", enabled ? "activating" : "disabling", handle,
@@ -197,7 +207,7 @@
     }
 
     // On older devices which do not support batch, call setDelay().
-    if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1 && info.batchParams.size() > 0) {
+    if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1 && info.numActiveClients() > 0) {
         ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w setDelay %d %" PRId64, handle,
                  info.bestBatchParams.batchDelay);
         mSensorDevice->setDelay(
@@ -279,6 +289,7 @@
         samplingPeriodNs = MINIMUM_EVENTS_PERIOD;
     }
     Mutex::Autolock _l(mLock);
+    if (isClientDisabledLocked(ident)) return INVALID_OPERATION;
     Info& info( mActivationCount.editValueFor(handle) );
     // If the underlying sensor is NOT in continuous mode, setDelay() should return an error.
     // Calling setDelay() in batch mode is an invalid operation.
@@ -298,7 +309,6 @@
 
 int SensorDevice::getHalDeviceVersion() const {
     if (!mSensorDevice) return -1;
-
     return mSensorDevice->common.version;
 }
 
@@ -306,12 +316,110 @@
     if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1) {
         return INVALID_OPERATION;
     }
+    if (isClientDisabled(ident)) return INVALID_OPERATION;
     ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w flush %d", handle);
     return mSensorDevice->flush(mSensorDevice, handle);
 }
 
+bool SensorDevice::isClientDisabled(void* ident) {
+    Mutex::Autolock _l(mLock);
+    return isClientDisabledLocked(ident);
+}
+
+bool SensorDevice::isClientDisabledLocked(void* ident) {
+    return mDisabledClients.indexOf(ident) >= 0;
+}
+
+void SensorDevice::enableAllSensors() {
+    Mutex::Autolock _l(mLock);
+    mDisabledClients.clear();
+    const int halVersion = getHalDeviceVersion();
+    for (size_t i = 0; i< mActivationCount.size(); ++i) {
+        Info& info = mActivationCount.editValueAt(i);
+        if (info.batchParams.isEmpty()) continue;
+        info.selectBatchParams();
+        const int sensor_handle = mActivationCount.keyAt(i);
+        ALOGD_IF(DEBUG_CONNECTIONS, "\t>> reenable actuating h/w sensor enable handle=%d ",
+                   sensor_handle);
+        status_t err(NO_ERROR);
+        if (halVersion > SENSORS_DEVICE_API_VERSION_1_0) {
+            err = mSensorDevice->batch(mSensorDevice, sensor_handle,
+                 info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
+                 info.bestBatchParams.batchTimeout);
+            ALOGE_IF(err, "Error calling batch on sensor %d (%s)", sensor_handle, strerror(-err));
+        }
+
+        if (err == NO_ERROR) {
+            err = mSensorDevice->activate(
+                    reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice),
+                    sensor_handle, 1);
+            ALOGE_IF(err, "Error activating sensor %d (%s)", sensor_handle, strerror(-err));
+        }
+
+        if (halVersion <= SENSORS_DEVICE_API_VERSION_1_0) {
+             err = mSensorDevice->setDelay(
+                    reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice),
+                    sensor_handle, info.bestBatchParams.batchDelay);
+             ALOGE_IF(err, "Error calling setDelay sensor %d (%s)", sensor_handle, strerror(-err));
+        }
+    }
+}
+
+void SensorDevice::disableAllSensors() {
+    Mutex::Autolock _l(mLock);
+   for (size_t i = 0; i< mActivationCount.size(); ++i) {
+        const Info& info = mActivationCount.valueAt(i);
+        // Check if this sensor has been activated previously and disable it.
+        if (info.batchParams.size() > 0) {
+           const int sensor_handle = mActivationCount.keyAt(i);
+           ALOGD_IF(DEBUG_CONNECTIONS, "\t>> actuating h/w sensor disable handle=%d ",
+                   sensor_handle);
+           mSensorDevice->activate(
+                   reinterpret_cast<struct sensors_poll_device_t *> (mSensorDevice),
+                   sensor_handle, 0);
+           // Add all the connections that were registered for this sensor to the disabled
+           // clients list.
+           for (size_t j = 0; j < info.batchParams.size(); ++j) {
+               mDisabledClients.add(info.batchParams.keyAt(j));
+           }
+        }
+    }
+}
+
+status_t SensorDevice::injectSensorData(const sensors_event_t *injected_sensor_event) {
+      ALOGD_IF(DEBUG_CONNECTIONS,
+              "sensor_event handle=%d ts=%lld data=%.2f, %.2f, %.2f %.2f %.2f %.2f",
+               injected_sensor_event->sensor,
+               injected_sensor_event->timestamp, injected_sensor_event->data[0],
+               injected_sensor_event->data[1], injected_sensor_event->data[2],
+               injected_sensor_event->data[3], injected_sensor_event->data[4],
+               injected_sensor_event->data[5]);
+      if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_4) {
+          return INVALID_OPERATION;
+      }
+      return mSensorDevice->inject_sensor_data(mSensorDevice, injected_sensor_event);
+}
+
+status_t SensorDevice::setMode(uint32_t mode) {
+     if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_4) {
+          return INVALID_OPERATION;
+     }
+     return mSensorModule->set_operation_mode(mode);
+}
+
 // ---------------------------------------------------------------------------
 
+int SensorDevice::Info::numActiveClients() {
+    SensorDevice& device(SensorDevice::getInstance());
+    int num = 0;
+    for (size_t i = 0; i < batchParams.size(); ++i) {
+        if (!device.isClientDisabledLocked(batchParams.keyAt(i))) {
+            ++num;
+        }
+    }
+    return num;
+}
+
 status_t SensorDevice::Info::setBatchParamsForIdent(void* ident, int flags,
                                                     int64_t samplingPeriodNs,
                                                     int64_t maxBatchReportLatencyNs) {
@@ -329,19 +437,16 @@
 }
 
 void SensorDevice::Info::selectBatchParams() {
-    BatchParams bestParams(-1, -1, -1);
+    BatchParams bestParams(0, -1, -1);
+    SensorDevice& device(SensorDevice::getInstance());
 
-    if (batchParams.size() > 0) {
-        BatchParams params = batchParams.valueAt(0);
-        bestParams = params;
-    }
-
-    for (size_t i = 1; i < batchParams.size(); ++i) {
+    for (size_t i = 0; i < batchParams.size(); ++i) {
+        if (device.isClientDisabledLocked(batchParams.keyAt(i))) continue;
         BatchParams params = batchParams.valueAt(i);
-        if (params.batchDelay < bestParams.batchDelay) {
+        if (bestParams.batchDelay == -1 || params.batchDelay < bestParams.batchDelay) {
             bestParams.batchDelay = params.batchDelay;
         }
-        if (params.batchTimeout < bestParams.batchTimeout) {
+        if (bestParams.batchTimeout == -1 || params.batchTimeout < bestParams.batchTimeout) {
             bestParams.batchTimeout = params.batchTimeout;
         }
     }
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 761b48c..c484849 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -42,6 +42,7 @@
     // Struct to store all the parameters(samplingPeriod, maxBatchReportLatency and flags) from
     // batch call. For continous mode clients, maxBatchReportLatency is set to zero.
     struct BatchParams {
+      // TODO: Get rid of flags parameter everywhere.
       int flags;
       nsecs_t batchDelay, batchTimeout;
       BatchParams() : flags(0), batchDelay(0), batchTimeout(0) {}
@@ -65,7 +66,7 @@
         // requested by the client.
         KeyedVector<void*, BatchParams> batchParams;
 
-        Info() : bestBatchParams(-1, -1, -1) {}
+        Info() : bestBatchParams(0, -1, -1) {}
         // Sets batch parameters for this ident. Returns error if this ident is not already present
         // in the KeyedVector above.
         status_t setBatchParamsForIdent(void* ident, int flags, int64_t samplingPeriodNs,
@@ -75,10 +76,17 @@
         // Removes batchParams for an ident and re-computes bestBatchParams. Returns the index of
         // the removed ident. If index >=0, ident is present and successfully removed.
         ssize_t removeBatchParamsForIdent(void* ident);
+
+        int numActiveClients();
     };
     DefaultKeyedVector<int, Info> mActivationCount;
 
+    // Use this vector to determine which client is activated or deactivated.
+    SortedVector<void *> mDisabledClients;
     SensorDevice();
+
+    bool isClientDisabled(void* ident);
+    bool isClientDisabledLocked(void* ident);
 public:
     ssize_t getSensorList(sensor_t const** list);
     status_t initCheck() const;
@@ -90,7 +98,11 @@
     // Call batch with timeout zero instead of calling setDelay() for newer devices.
     status_t setDelay(void* ident, int handle, int64_t ns);
     status_t flush(void* ident, int handle);
+    status_t setMode(uint32_t mode);
+    void disableAllSensors();
+    void enableAllSensors();
     void autoDisable(void *ident, int handle);
+    status_t injectSensorData(const sensors_event_t *event);
     void dump(String8& result);
 };
 
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index a857366..40b21a9 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -31,6 +31,7 @@
 #include <utils/Singleton.h>
 #include <utils/String16.h>
 
+#include <binder/AppOpsManager.h>
 #include <binder/BinderService.h>
 #include <binder/IServiceManager.h>
 #include <binder/PermissionCache.h>
@@ -63,7 +64,9 @@
  *
  */
 
-const char* SensorService::WAKE_LOCK_NAME = "SensorService";
+const char* SensorService::WAKE_LOCK_NAME = "SensorService_wakelock";
+// Permissions.
+static const String16 sDump("android.permission.DUMP");
 
 SensorService::SensorService()
     : mInitCheck(NO_INIT), mSocketBufferSize(SOCKET_BUFFER_SIZE_NON_BATCHED),
@@ -74,7 +77,6 @@
 void SensorService::onFirstRef()
 {
     ALOGD("nuSensorService starting...");
-
     SensorDevice& dev(SensorDevice::getInstance());
 
     if (dev.initCheck() == NO_ERROR) {
@@ -82,7 +84,7 @@
         ssize_t count = dev.getSensorList(&list);
         if (count > 0) {
             ssize_t orientationIndex = -1;
-            bool hasGyro = false;
+            bool hasGyro = false, hasAccel = false, hasMag = false;
             uint32_t virtualSensorsNeeds =
                     (1<<SENSOR_TYPE_GRAVITY) |
                     (1<<SENSOR_TYPE_LINEAR_ACCELERATION) |
@@ -92,6 +94,12 @@
             for (ssize_t i=0 ; i<count ; i++) {
                 registerSensor( new HardwareSensor(list[i]) );
                 switch (list[i].type) {
+                    case SENSOR_TYPE_ACCELEROMETER:
+                        hasAccel = true;
+                        break;
+                    case SENSOR_TYPE_MAGNETIC_FIELD:
+                        hasMag = true;
+                        break;
                     case SENSOR_TYPE_ORIENTATION:
                         orientationIndex = i;
                         break;
@@ -115,7 +123,7 @@
             // build the sensor list returned to users
             mUserSensorList = mSensorList;
 
-            if (hasGyro) {
+            if (hasGyro && hasAccel && hasMag) {
                 Sensor aSensor;
 
                 // Add Android virtual sensors if they're not already
@@ -154,7 +162,7 @@
             // Check if the device really supports batching by looking at the FIFO event
             // counts for each sensor.
             bool batchingSupported = false;
-            for (int i = 0; i < mSensorList.size(); ++i) {
+            for (size_t i = 0; i < mSensorList.size(); ++i) {
                 if (mSensorList[i].getFifoMaxEventCount() > 0) {
                     batchingSupported = true;
                     break;
@@ -190,10 +198,16 @@
             mSensorEventBuffer = new sensors_event_t[minBufferSize];
             mSensorEventScratch = new sensors_event_t[minBufferSize];
             mMapFlushEventsToConnections = new SensorEventConnection const * [minBufferSize];
+            mCurrentOperatingMode = NORMAL;
 
+            mNextSensorRegIndex = 0;
+            for (int i = 0; i < SENSOR_REGISTRATIONS_BUF_SIZE; ++i) {
+                mLastNSensorRegistrations.push();
+            }
+
+            mInitCheck = NO_ERROR;
             mAckReceiver = new SensorEventAckReceiver(this);
             mAckReceiver->run("SensorEventAckReceiver", PRIORITY_URGENT_DISPLAY);
-            mInitCheck = NO_ERROR;
             run("SensorService", PRIORITY_URGENT_DISPLAY);
         }
     }
@@ -210,7 +224,7 @@
     // add to our handle->SensorInterface mapping
     mSensorMap.add(sensor.getHandle(), s);
     // create an entry in the mLastEventSeen array
-    mLastEventSeen.add(sensor.getHandle(), event);
+    mLastEventSeen.add(sensor.getHandle(), NULL);
 
     return sensor;
 }
@@ -228,9 +242,7 @@
         delete mSensorMap.valueAt(i);
 }
 
-static const String16 sDump("android.permission.DUMP");
-
-status_t SensorService::dump(int fd, const Vector<String16>& /*args*/)
+status_t SensorService::dump(int fd, const Vector<String16>& args)
 {
     String8 result;
     if (!PermissionCache::checkCallingPermission(sDump)) {
@@ -239,116 +251,188 @@
                 IPCThreadState::self()->getCallingPid(),
                 IPCThreadState::self()->getCallingUid());
     } else {
+        if (args.size() > 2) {
+           return INVALID_OPERATION;
+        }
         Mutex::Autolock _l(mLock);
-        result.append("Sensor List:\n");
-        for (size_t i=0 ; i<mSensorList.size() ; i++) {
-            const Sensor& s(mSensorList[i]);
-            const sensors_event_t& e(mLastEventSeen.valueFor(s.getHandle()));
-            result.appendFormat(
-                    "%-15s| %-10s| version=%d |%-20s| 0x%08x | \"%s\" | type=%d |",
-                    s.getName().string(),
-                    s.getVendor().string(),
-                    s.getVersion(),
-                    s.getStringType().string(),
-                    s.getHandle(),
-                    s.getRequiredPermission().string(),
-                    s.getType());
-
-            const int reportingMode = s.getReportingMode();
-            if (reportingMode == AREPORTING_MODE_CONTINUOUS) {
-                result.append(" continuous | ");
-            } else if (reportingMode == AREPORTING_MODE_ON_CHANGE) {
-                result.append(" on-change | ");
-            } else if (reportingMode == AREPORTING_MODE_ONE_SHOT) {
-                result.append(" one-shot | ");
+        SensorDevice& dev(SensorDevice::getInstance());
+        if (args.size() == 2 && args[0] == String16("restrict")) {
+            // If already in restricted mode. Ignore.
+            if (mCurrentOperatingMode == RESTRICTED) {
+                return status_t(NO_ERROR);
+            }
+            // If in any mode other than normal, ignore.
+            if (mCurrentOperatingMode != NORMAL) {
+                return INVALID_OPERATION;
+            }
+            mCurrentOperatingMode = RESTRICTED;
+            dev.disableAllSensors();
+            // Clear all pending flush connections for all active sensors. If one of the active
+            // connections has called flush() and the underlying sensor has been disabled before a
+            // flush complete event is returned, we need to remove the connection from this queue.
+            for (size_t i=0 ; i< mActiveSensors.size(); ++i) {
+                mActiveSensors.valueAt(i)->clearAllPendingFlushConnections();
+            }
+            mWhiteListedPackage.setTo(String8(args[1]));
+            return status_t(NO_ERROR);
+        } else if (args.size() == 1 && args[0] == String16("enable")) {
+            // If currently in restricted mode, reset back to NORMAL mode else ignore.
+            if (mCurrentOperatingMode == RESTRICTED) {
+                mCurrentOperatingMode = NORMAL;
+                dev.enableAllSensors();
+            }
+            if (mCurrentOperatingMode == DATA_INJECTION) {
+               resetToNormalModeLocked();
+            }
+            mWhiteListedPackage.clear();
+            return status_t(NO_ERROR);
+        } else if (args.size() == 2 && args[0] == String16("data_injection")) {
+            if (mCurrentOperatingMode == NORMAL) {
+                dev.disableAllSensors();
+                status_t err = dev.setMode(DATA_INJECTION);
+                if (err == NO_ERROR) {
+                    mCurrentOperatingMode = DATA_INJECTION;
+                } else {
+                    // Re-enable sensors.
+                    dev.enableAllSensors();
+                }
+                mWhiteListedPackage.setTo(String8(args[1]));
+                return NO_ERROR;
+            } else if (mCurrentOperatingMode == DATA_INJECTION) {
+                // Already in DATA_INJECTION mode. Treat this as a no_op.
+                return NO_ERROR;
             } else {
-                result.append(" special-trigger | ");
+                // Transition to data injection mode supported only from NORMAL mode.
+                return INVALID_OPERATION;
+            }
+        } else if (mSensorList.size() == 0) {
+            result.append("No Sensors on the device\n");
+        } else {
+            // Default dump the sensor list and debugging information.
+            result.append("Sensor List:\n");
+            for (size_t i=0 ; i<mSensorList.size() ; i++) {
+                const Sensor& s(mSensorList[i]);
+                result.appendFormat(
+                        "%-15s| %-10s| version=%d |%-20s| 0x%08x | \"%s\" | type=%d |",
+                        s.getName().string(),
+                        s.getVendor().string(),
+                        s.getVersion(),
+                        s.getStringType().string(),
+                        s.getHandle(),
+                        s.getRequiredPermission().string(),
+                        s.getType());
+
+                const int reportingMode = s.getReportingMode();
+                if (reportingMode == AREPORTING_MODE_CONTINUOUS) {
+                    result.append(" continuous | ");
+                } else if (reportingMode == AREPORTING_MODE_ON_CHANGE) {
+                    result.append(" on-change | ");
+                } else if (reportingMode == AREPORTING_MODE_ONE_SHOT) {
+                    result.append(" one-shot | ");
+                } else {
+                    result.append(" special-trigger | ");
+                }
+
+                if (s.getMaxDelay() > 0) {
+                    result.appendFormat("minRate=%.2fHz | ", 1e6f / s.getMaxDelay());
+                } else {
+                    result.appendFormat("maxDelay=%dus |", s.getMaxDelay());
+                }
+
+                if (s.getMinDelay() > 0) {
+                    result.appendFormat("maxRate=%.2fHz | ", 1e6f / s.getMinDelay());
+                } else {
+                    result.appendFormat("minDelay=%dus |", s.getMinDelay());
+                }
+
+                if (s.getFifoMaxEventCount() > 0) {
+                    result.appendFormat("FifoMax=%d events | ",
+                            s.getFifoMaxEventCount());
+                } else {
+                    result.append("no batching | ");
+                }
+
+                if (s.isWakeUpSensor()) {
+                    result.appendFormat("wakeUp | ");
+                } else {
+                    result.appendFormat("non-wakeUp | ");
+                }
+
+                int bufIndex = mLastEventSeen.indexOfKey(s.getHandle());
+                if (bufIndex >= 0) {
+                    const CircularBuffer* buf = mLastEventSeen.valueAt(bufIndex);
+                    if (buf != NULL && s.getRequiredPermission().isEmpty()) {
+                        buf->printBuffer(result);
+                    } else {
+                        result.append("last=<> \n");
+                    }
+                }
+                result.append("\n");
+            }
+            SensorFusion::getInstance().dump(result);
+            SensorDevice::getInstance().dump(result);
+
+            result.append("Active sensors:\n");
+            for (size_t i=0 ; i<mActiveSensors.size() ; i++) {
+                int handle = mActiveSensors.keyAt(i);
+                result.appendFormat("%s (handle=0x%08x, connections=%zu)\n",
+                        getSensorName(handle).string(),
+                        handle,
+                        mActiveSensors.valueAt(i)->getNumConnections());
             }
 
-            if (s.getMaxDelay() > 0) {
-                result.appendFormat("minRate=%.2fHz | ", 1e6f / s.getMaxDelay());
-            } else {
-                result.appendFormat("maxDelay=%dus |", s.getMaxDelay());
+            result.appendFormat("Socket Buffer size = %d events\n",
+                                mSocketBufferSize/sizeof(sensors_event_t));
+            result.appendFormat("WakeLock Status: %s \n", mWakeLockAcquired ? "acquired" :
+                    "not held");
+            result.appendFormat("Mode :");
+            switch(mCurrentOperatingMode) {
+               case NORMAL:
+                   result.appendFormat(" NORMAL\n");
+                   break;
+               case RESTRICTED:
+                   result.appendFormat(" RESTRICTED : %s\n", mWhiteListedPackage.string());
+                   break;
+               case DATA_INJECTION:
+                   result.appendFormat(" DATA_INJECTION : %s\n", mWhiteListedPackage.string());
+            }
+            result.appendFormat("%zd active connections\n", mActiveConnections.size());
+
+            for (size_t i=0 ; i < mActiveConnections.size() ; i++) {
+                sp<SensorEventConnection> connection(mActiveConnections[i].promote());
+                if (connection != 0) {
+                    result.appendFormat("Connection Number: %zu \n", i);
+                    connection->dump(result);
+                }
             }
 
-            if (s.getMinDelay() > 0) {
-                result.appendFormat("maxRate=%.2fHz | ", 1e6f / s.getMinDelay());
-            } else {
-                result.appendFormat("minDelay=%dus |", s.getMinDelay());
-            }
-
-            if (s.getFifoMaxEventCount() > 0) {
-                result.appendFormat("FifoMax=%d events | ",
-                        s.getFifoMaxEventCount());
-            } else {
-                result.append("no batching | ");
-            }
-
-            if (s.isWakeUpSensor()) {
-                result.appendFormat("wakeUp | ");
-            } else {
-                result.appendFormat("non-wakeUp | ");
-            }
-
-            switch (s.getType()) {
-                case SENSOR_TYPE_ROTATION_VECTOR:
-                case SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR:
-                    result.appendFormat(
-                            "last=<%5.1f,%5.1f,%5.1f,%5.1f,%5.1f, %" PRId64 ">\n",
-                            e.data[0], e.data[1], e.data[2], e.data[3], e.data[4], e.timestamp);
-                    break;
-                case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
-                case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
-                    result.appendFormat(
-                            "last=<%5.1f,%5.1f,%5.1f,%5.1f,%5.1f,%5.1f, %" PRId64 ">\n",
-                            e.data[0], e.data[1], e.data[2], e.data[3], e.data[4], e.data[5],
-                            e.timestamp);
-                    break;
-                case SENSOR_TYPE_GAME_ROTATION_VECTOR:
-                    result.appendFormat(
-                            "last=<%5.1f,%5.1f,%5.1f,%5.1f, %" PRId64 ">\n",
-                            e.data[0], e.data[1], e.data[2], e.data[3], e.timestamp);
-                    break;
-                case SENSOR_TYPE_SIGNIFICANT_MOTION:
-                case SENSOR_TYPE_STEP_DETECTOR:
-                    result.appendFormat( "last=<%f %" PRId64 ">\n", e.data[0], e.timestamp);
-                    break;
-                case SENSOR_TYPE_STEP_COUNTER:
-                    result.appendFormat( "last=<%" PRIu64 ", %" PRId64 ">\n", e.u64.step_counter,
-                                         e.timestamp);
-                    break;
-                default:
-                    // default to 3 values
-                    result.appendFormat(
-                            "last=<%5.1f,%5.1f,%5.1f, %" PRId64 ">\n",
-                            e.data[0], e.data[1], e.data[2], e.timestamp);
-                    break;
-            }
-            result.append("\n");
-        }
-        SensorFusion::getInstance().dump(result);
-        SensorDevice::getInstance().dump(result);
-
-        result.append("Active sensors:\n");
-        for (size_t i=0 ; i<mActiveSensors.size() ; i++) {
-            int handle = mActiveSensors.keyAt(i);
-            result.appendFormat("%s (handle=0x%08x, connections=%zu)\n",
-                    getSensorName(handle).string(),
-                    handle,
-                    mActiveSensors.valueAt(i)->getNumConnections());
-        }
-
-        result.appendFormat("Socket Buffer size = %d events\n",
-                            mSocketBufferSize/sizeof(sensors_event_t));
-        result.appendFormat("WakeLock Status: %s \n", mWakeLockAcquired ? "acquired" : "not held");
-        result.appendFormat("%zd active connections\n", mActiveConnections.size());
-
-        for (size_t i=0 ; i < mActiveConnections.size() ; i++) {
-            sp<SensorEventConnection> connection(mActiveConnections[i].promote());
-            if (connection != 0) {
-                result.appendFormat("Connection Number: %zu \n", i);
-                connection->dump(result);
-            }
+            result.appendFormat("Previous Registrations:\n");
+            // Log in the reverse chronological order.
+            int currentIndex = (mNextSensorRegIndex - 1 + SENSOR_REGISTRATIONS_BUF_SIZE) %
+                SENSOR_REGISTRATIONS_BUF_SIZE;
+            const int startIndex = currentIndex;
+            do {
+                const SensorRegistrationInfo& reg_info = mLastNSensorRegistrations[currentIndex];
+                if (SensorRegistrationInfo::isSentinel(reg_info)) {
+                    // Ignore sentinel, proceed to next item.
+                    currentIndex = (currentIndex - 1 + SENSOR_REGISTRATIONS_BUF_SIZE) %
+                        SENSOR_REGISTRATIONS_BUF_SIZE;
+                    continue;
+                }
+                if (reg_info.mActivated) {
+                   result.appendFormat("%02d:%02d:%02d activated package=%s handle=0x%08x "
+                           "samplingRate=%dus maxReportLatency=%dus\n",
+                           reg_info.mHour, reg_info.mMin, reg_info.mSec,
+                           reg_info.mPackageName.string(), reg_info.mSensorHandle,
+                           reg_info.mSamplingRateUs, reg_info.mMaxReportLatencyUs);
+                } else {
+                   result.appendFormat("%02d:%02d:%02d de-activated package=%s handle=0x%08x\n",
+                           reg_info.mHour, reg_info.mMin, reg_info.mSec,
+                           reg_info.mPackageName.string(), reg_info.mSensorHandle);
+                }
+                currentIndex = (currentIndex - 1 + SENSOR_REGISTRATIONS_BUF_SIZE) %
+                        SENSOR_REGISTRATIONS_BUF_SIZE;
+            } while(startIndex != currentIndex);
         }
     }
     write(fd, result.string(), result.size());
@@ -371,8 +455,9 @@
                 sensor->autoDisable(connection.get(), handle);
                 cleanupWithoutDisableLocked(connection, handle);
             }
+
         }
-    }
+   }
 }
 
 bool SensorService::threadLoop()
@@ -554,7 +639,6 @@
     }
 }
 
-
 bool SensorService::isWakeLockAcquired() {
     Mutex::Autolock _l(mLock);
     return mWakeLockAcquired;
@@ -577,19 +661,15 @@
 
 void SensorService::recordLastValueLocked(
         const sensors_event_t* buffer, size_t count) {
-    const sensors_event_t* last = NULL;
     for (size_t i = 0; i < count; i++) {
-        const sensors_event_t* event = &buffer[i];
-        if (event->type != SENSOR_TYPE_META_DATA) {
-            if (last && event->sensor != last->sensor) {
-                mLastEventSeen.editValueFor(last->sensor) = *last;
+        if (buffer[i].type != SENSOR_TYPE_META_DATA) {
+            CircularBuffer* &circular_buf = mLastEventSeen.editValueFor(buffer[i].sensor);
+            if (circular_buf == NULL) {
+                circular_buf = new CircularBuffer(buffer[i].type);
             }
-            last = event;
+            circular_buf->addEvent(buffer[i]);
         }
     }
-    if (last) {
-        mLastEventSeen.editValueFor(last->sensor) = *last;
-    }
 }
 
 void SensorService::sortEventBuffer(sensors_event_t* buffer, size_t count)
@@ -630,12 +710,11 @@
     return sensor != NULL && sensor->getSensor().isWakeUpSensor();
 }
 
-
 SensorService::SensorRecord * SensorService::getSensorRecord(int handle) {
      return mActiveSensors.valueFor(handle);
 }
 
-Vector<Sensor> SensorService::getSensorList()
+Vector<Sensor> SensorService::getSensorList(const String16& opPackageName)
 {
     char value[PROPERTY_VALUE_MAX];
     property_get("debug.sensors", value, "0");
@@ -644,24 +723,65 @@
     Vector<Sensor> accessibleSensorList;
     for (size_t i = 0; i < initialSensorList.size(); i++) {
         Sensor sensor = initialSensorList[i];
-        if (canAccessSensor(sensor)) {
+        if (canAccessSensor(sensor, "getSensorList", opPackageName)) {
             accessibleSensorList.add(sensor);
         } else {
-            ALOGI("Skipped sensor %s because it requires permission %s",
+            ALOGI("Skipped sensor %s because it requires permission %s and app op %d",
                   sensor.getName().string(),
-                  sensor.getRequiredPermission().string());
+                  sensor.getRequiredPermission().string(),
+                  sensor.getRequiredAppOp());
         }
     }
     return accessibleSensorList;
 }
 
-sp<ISensorEventConnection> SensorService::createSensorEventConnection()
-{
+sp<ISensorEventConnection> SensorService::createSensorEventConnection(const String8& packageName,
+        int requestedMode, const String16& opPackageName) {
+    // Only 2 modes supported for a SensorEventConnection ... NORMAL and DATA_INJECTION.
+    if (requestedMode != NORMAL && requestedMode != DATA_INJECTION) {
+        return NULL;
+    }
+
+    Mutex::Autolock _l(mLock);
+    // To create a client in DATA_INJECTION mode to inject data, SensorService should already be
+    // operating in DI mode.
+    if (requestedMode == DATA_INJECTION) {
+        if (mCurrentOperatingMode != DATA_INJECTION) return NULL;
+        if (!isWhiteListedPackage(packageName)) return NULL;
+    }
+
     uid_t uid = IPCThreadState::self()->getCallingUid();
-    sp<SensorEventConnection> result(new SensorEventConnection(this, uid));
+    sp<SensorEventConnection> result(new SensorEventConnection(this, uid, packageName,
+            requestedMode == DATA_INJECTION, opPackageName));
+    if (requestedMode == DATA_INJECTION) {
+        if (mActiveConnections.indexOf(result) < 0) {
+            mActiveConnections.add(result);
+        }
+        // Add the associated file descriptor to the Looper for polling whenever there is data to
+        // be injected.
+        result->updateLooperRegistration(mLooper);
+    }
     return result;
 }
 
+int SensorService::isDataInjectionEnabled() {
+    Mutex::Autolock _l(mLock);
+    return (mCurrentOperatingMode == DATA_INJECTION);
+}
+
+status_t SensorService::resetToNormalMode() {
+    Mutex::Autolock _l(mLock);
+    return resetToNormalModeLocked();
+}
+
+status_t SensorService::resetToNormalModeLocked() {
+    SensorDevice& dev(SensorDevice::getInstance());
+    dev.enableAllSensors();
+    status_t err = dev.setMode(NORMAL);
+    mCurrentOperatingMode = NORMAL;
+    return err;
+}
+
 void SensorService::cleanupConnection(SensorEventConnection* c)
 {
     Mutex::Autolock _l(mLock);
@@ -708,7 +828,8 @@
 }
 
 status_t SensorService::enable(const sp<SensorEventConnection>& connection,
-        int handle, nsecs_t samplingPeriodNs,  nsecs_t maxBatchReportLatencyNs, int reservedFlags)
+        int handle, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags,
+        const String16& opPackageName)
 {
     if (mInitCheck != NO_ERROR)
         return mInitCheck;
@@ -718,11 +839,16 @@
         return BAD_VALUE;
     }
 
-    if (!verifyCanAccessSensor(sensor->getSensor(), "Tried enabling")) {
+    if (!canAccessSensor(sensor->getSensor(), "Tried enabling", opPackageName)) {
         return BAD_VALUE;
     }
 
     Mutex::Autolock _l(mLock);
+    if ((mCurrentOperatingMode == RESTRICTED || mCurrentOperatingMode == DATA_INJECTION)
+           && !isWhiteListedPackage(connection->getPackageName())) {
+        return INVALID_OPERATION;
+    }
+
     SensorRecord* rec = mActiveSensors.valueFor(handle);
     if (rec == 0) {
         rec = new SensorRecord(connection);
@@ -738,14 +864,24 @@
             if (sensor->getSensor().getReportingMode() == AREPORTING_MODE_ON_CHANGE) {
                 // NOTE: The wake_up flag of this event may get set to
                 // WAKE_UP_SENSOR_EVENT_NEEDS_ACK if this is a wake_up event.
-                sensors_event_t& event(mLastEventSeen.editValueFor(handle));
-                if (event.version == sizeof(sensors_event_t)) {
-                    if (isWakeUpSensorEvent(event) && !mWakeLockAcquired) {
-                        setWakeLockAcquiredLocked(true);
-                    }
-                    connection->sendEvents(&event, 1, NULL);
-                    if (!connection->needsWakeLock() && mWakeLockAcquired) {
-                        checkWakeLockStateLocked();
+                CircularBuffer *circular_buf = mLastEventSeen.valueFor(handle);
+                if (circular_buf) {
+                    sensors_event_t event;
+                    memset(&event, 0, sizeof(event));
+                    // It is unlikely that this buffer is empty as the sensor is already active.
+                    // One possible corner case may be two applications activating an on-change
+                    // sensor at the same time.
+                    if(circular_buf->populateLastEvent(&event)) {
+                        event.sensor = handle;
+                        if (event.version == sizeof(sensors_event_t)) {
+                            if (isWakeUpSensorEvent(event) && !mWakeLockAcquired) {
+                                setWakeLockAcquiredLocked(true);
+                            }
+                            connection->sendEvents(&event, 1, NULL);
+                            if (!connection->needsWakeLock() && mWakeLockAcquired) {
+                                checkWakeLockStateLocked();
+                            }
+                        }
                     }
                 }
             }
@@ -773,7 +909,7 @@
                                 "rate=%" PRId64 " timeout== %" PRId64"",
              handle, reservedFlags, samplingPeriodNs, maxBatchReportLatencyNs);
 
-    status_t err = sensor->batch(connection.get(), handle, reservedFlags, samplingPeriodNs,
+    status_t err = sensor->batch(connection.get(), handle, 0, samplingPeriodNs,
                                  maxBatchReportLatencyNs);
 
     // Call flush() before calling activate() on the sensor. Wait for a first flush complete
@@ -798,6 +934,19 @@
 
     if (err == NO_ERROR) {
         connection->updateLooperRegistration(mLooper);
+        SensorRegistrationInfo &reg_info =
+            mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex);
+        reg_info.mSensorHandle = handle;
+        reg_info.mSamplingRateUs = samplingPeriodNs/1000;
+        reg_info.mMaxReportLatencyUs = maxBatchReportLatencyNs/1000;
+        reg_info.mActivated = true;
+        reg_info.mPackageName = connection->getPackageName();
+        time_t rawtime = time(NULL);
+        struct tm * timeinfo = localtime(&rawtime);
+        reg_info.mHour = timeinfo->tm_hour;
+        reg_info.mMin = timeinfo->tm_min;
+        reg_info.mSec = timeinfo->tm_sec;
+        mNextSensorRegIndex = (mNextSensorRegIndex + 1) % SENSOR_REGISTRATIONS_BUF_SIZE;
     }
 
     if (err != NO_ERROR) {
@@ -818,6 +967,20 @@
     if (err == NO_ERROR) {
         SensorInterface* sensor = mSensorMap.valueFor(handle);
         err = sensor ? sensor->activate(connection.get(), false) : status_t(BAD_VALUE);
+
+    }
+    if (err == NO_ERROR) {
+        SensorRegistrationInfo &reg_info =
+            mLastNSensorRegistrations.editItemAt(mNextSensorRegIndex);
+        reg_info.mActivated = false;
+        reg_info.mPackageName= connection->getPackageName();
+        reg_info.mSensorHandle = handle;
+        time_t rawtime = time(NULL);
+        struct tm * timeinfo = localtime(&rawtime);
+        reg_info.mHour = timeinfo->tm_hour;
+        reg_info.mMin = timeinfo->tm_min;
+        reg_info.mSec = timeinfo->tm_sec;
+        mNextSensorRegIndex = (mNextSensorRegIndex + 1) % SENSOR_REGISTRATIONS_BUF_SIZE;
     }
     return err;
 }
@@ -852,7 +1015,7 @@
 }
 
 status_t SensorService::setEventRate(const sp<SensorEventConnection>& connection,
-        int handle, nsecs_t ns)
+        int handle, nsecs_t ns, const String16& opPackageName)
 {
     if (mInitCheck != NO_ERROR)
         return mInitCheck;
@@ -861,7 +1024,7 @@
     if (!sensor)
         return BAD_VALUE;
 
-    if (!verifyCanAccessSensor(sensor->getSensor(), "Tried configuring")) {
+    if (!canAccessSensor(sensor->getSensor(), "Tried configuring", opPackageName)) {
         return BAD_VALUE;
     }
 
@@ -876,7 +1039,8 @@
     return sensor->setDelay(connection.get(), handle, ns);
 }
 
-status_t SensorService::flushSensor(const sp<SensorEventConnection>& connection) {
+status_t SensorService::flushSensor(const sp<SensorEventConnection>& connection,
+        const String16& opPackageName) {
     if (mInitCheck != NO_ERROR) return mInitCheck;
     SensorDevice& dev(SensorDevice::getInstance());
     const int halVersion = dev.getHalDeviceVersion();
@@ -896,6 +1060,10 @@
             // flush complete event.
             connection->incrementPendingFlushCount(handle);
         } else {
+            if (!canAccessSensor(sensor->getSensor(), "Tried flushing", opPackageName)) {
+                err = INVALID_OPERATION;
+                continue;
+            }
             status_t err_flush = sensor->flush(connection.get(), handle);
             if (err_flush == NO_ERROR) {
                 SensorRecord* rec = mActiveSensors.valueFor(handle);
@@ -907,23 +1075,42 @@
     return err;
 }
 
-bool SensorService::canAccessSensor(const Sensor& sensor) {
-    return (sensor.getRequiredPermission().isEmpty()) ||
-            PermissionCache::checkCallingPermission(String16(sensor.getRequiredPermission()));
-}
+bool SensorService::canAccessSensor(const Sensor& sensor, const char* operation,
+        const String16& opPackageName) {
+    const String8& requiredPermission = sensor.getRequiredPermission();
 
-bool SensorService::verifyCanAccessSensor(const Sensor& sensor, const char* operation) {
-    if (canAccessSensor(sensor)) {
+    if (requiredPermission.length() <= 0) {
         return true;
+    }
+
+    bool hasPermission = false;
+
+    // Runtime permissions can't use the cache as they may change.
+    if (sensor.isRequiredPermissionRuntime()) {
+        hasPermission = checkPermission(String16(requiredPermission),
+                IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid());
     } else {
-        String8 errorMessage;
-        errorMessage.appendFormat(
-                "%s a sensor (%s) without holding its required permission: %s",
-                operation,
-                sensor.getName().string(),
-                sensor.getRequiredPermission().string());
+        hasPermission = PermissionCache::checkCallingPermission(String16(requiredPermission));
+    }
+
+    if (!hasPermission) {
+        ALOGE("%s a sensor (%s) without holding its required permission: %s",
+                operation, sensor.getName().string(), sensor.getRequiredPermission().string());
         return false;
     }
+
+    const int32_t opCode = sensor.getRequiredAppOp();
+    if (opCode >= 0) {
+        AppOpsManager appOps;
+        if (appOps.noteOp(opCode, IPCThreadState::self()->getCallingUid(), opPackageName)
+                        != AppOpsManager::MODE_ALLOWED) {
+            ALOGE("%s a sensor (%s) without enabled required app op: %D",
+                    operation, sensor.getName().string(), opCode);
+            return false;
+        }
+    }
+
+    return true;
 }
 
 void SensorService::checkWakeLockState() {
@@ -969,6 +1156,33 @@
     }
 }
 
+bool SensorService::isWhiteListedPackage(const String8& packageName) {
+    return (packageName.contains(mWhiteListedPackage.string()));
+}
+
+int SensorService::getNumEventsForSensorType(int sensor_event_type) {
+    switch (sensor_event_type) {
+        case SENSOR_TYPE_ROTATION_VECTOR:
+        case SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR:
+            return 5;
+
+        case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
+        case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
+            return 6;
+
+        case SENSOR_TYPE_GAME_ROTATION_VECTOR:
+            return 4;
+
+        case SENSOR_TYPE_SIGNIFICANT_MOTION:
+        case SENSOR_TYPE_STEP_DETECTOR:
+        case SENSOR_TYPE_STEP_COUNTER:
+            return 1;
+
+         default:
+            return 3;
+    }
+}
+
 // ---------------------------------------------------------------------------
 SensorService::SensorRecord::SensorRecord(
         const sp<SensorEventConnection>& connection)
@@ -1025,12 +1239,121 @@
     return NULL;
 }
 
+void SensorService::SensorRecord::clearAllPendingFlushConnections() {
+    mPendingFlushConnections.clear();
+}
+
+
+// ---------------------------------------------------------------------------
+SensorService::TrimmedSensorEvent::TrimmedSensorEvent(int sensorType) {
+    mTimestamp = -1;
+    const int numData = SensorService::getNumEventsForSensorType(sensorType);
+    if (sensorType == SENSOR_TYPE_STEP_COUNTER) {
+        mStepCounter = 0;
+    } else {
+        mData = new float[numData];
+        for (int i = 0; i < numData; ++i) {
+            mData[i] = -1.0;
+        }
+    }
+    mHour = mMin = mSec = INT32_MIN;
+}
+
+bool SensorService::TrimmedSensorEvent::isSentinel(const TrimmedSensorEvent& event) {
+    return (event.mHour == INT32_MIN && event.mMin == INT32_MIN && event.mSec == INT32_MIN);
+}
+// --------------------------------------------------------------------------
+SensorService::CircularBuffer::CircularBuffer(int sensor_event_type) {
+    mNextInd = 0;
+    mBufSize = CIRCULAR_BUF_SIZE;
+    if (sensor_event_type == SENSOR_TYPE_STEP_COUNTER ||
+            sensor_event_type == SENSOR_TYPE_SIGNIFICANT_MOTION ||
+            sensor_event_type == SENSOR_TYPE_ACCELEROMETER) {
+        mBufSize = CIRCULAR_BUF_SIZE * 5;
+    }
+    mTrimmedSensorEventArr = new TrimmedSensorEvent *[mBufSize];
+    mSensorType = sensor_event_type;
+    for (int i = 0; i < mBufSize; ++i) {
+        mTrimmedSensorEventArr[i] = new TrimmedSensorEvent(mSensorType);
+    }
+}
+
+void SensorService::CircularBuffer::addEvent(const sensors_event_t& sensor_event) {
+    TrimmedSensorEvent *curr_event = mTrimmedSensorEventArr[mNextInd];
+    curr_event->mTimestamp = sensor_event.timestamp;
+    if (mSensorType == SENSOR_TYPE_STEP_COUNTER) {
+        curr_event->mStepCounter = sensor_event.u64.step_counter;
+    } else {
+        memcpy(curr_event->mData, sensor_event.data,
+                 sizeof(float) * SensorService::getNumEventsForSensorType(mSensorType));
+    }
+    time_t rawtime = time(NULL);
+    struct tm * timeinfo = localtime(&rawtime);
+    curr_event->mHour = timeinfo->tm_hour;
+    curr_event->mMin = timeinfo->tm_min;
+    curr_event->mSec = timeinfo->tm_sec;
+    mNextInd = (mNextInd + 1) % mBufSize;
+}
+
+void SensorService::CircularBuffer::printBuffer(String8& result) const {
+    const int numData = SensorService::getNumEventsForSensorType(mSensorType);
+    int i = mNextInd, eventNum = 1;
+    result.appendFormat("last %d events = < ", mBufSize);
+    do {
+        if (TrimmedSensorEvent::isSentinel(*mTrimmedSensorEventArr[i])) {
+            // Sentinel, ignore.
+            i = (i + 1) % mBufSize;
+            continue;
+        }
+        result.appendFormat("%d) ", eventNum++);
+        if (mSensorType == SENSOR_TYPE_STEP_COUNTER) {
+            result.appendFormat("%llu,", mTrimmedSensorEventArr[i]->mStepCounter);
+        } else {
+            for (int j = 0; j < numData; ++j) {
+                result.appendFormat("%5.1f,", mTrimmedSensorEventArr[i]->mData[j]);
+            }
+        }
+        result.appendFormat("%lld %02d:%02d:%02d ", mTrimmedSensorEventArr[i]->mTimestamp,
+                mTrimmedSensorEventArr[i]->mHour, mTrimmedSensorEventArr[i]->mMin,
+                mTrimmedSensorEventArr[i]->mSec);
+        i = (i + 1) % mBufSize;
+    } while (i != mNextInd);
+    result.appendFormat(">\n");
+}
+
+bool SensorService::CircularBuffer::populateLastEvent(sensors_event_t *event) {
+    int lastEventInd = (mNextInd - 1 + mBufSize) % mBufSize;
+    // Check if the buffer is empty.
+    if (TrimmedSensorEvent::isSentinel(*mTrimmedSensorEventArr[lastEventInd])) {
+        return false;
+    }
+    event->version = sizeof(sensors_event_t);
+    event->type = mSensorType;
+    event->timestamp = mTrimmedSensorEventArr[lastEventInd]->mTimestamp;
+    if (mSensorType == SENSOR_TYPE_STEP_COUNTER) {
+          event->u64.step_counter = mTrimmedSensorEventArr[lastEventInd]->mStepCounter;
+    } else {
+        memcpy(event->data, mTrimmedSensorEventArr[lastEventInd]->mData,
+                 sizeof(float) * SensorService::getNumEventsForSensorType(mSensorType));
+    }
+    return true;
+}
+
+SensorService::CircularBuffer::~CircularBuffer() {
+    for (int i = 0; i < mBufSize; ++i) {
+        delete mTrimmedSensorEventArr[i];
+    }
+    delete [] mTrimmedSensorEventArr;
+}
+
 // ---------------------------------------------------------------------------
 
 SensorService::SensorEventConnection::SensorEventConnection(
-        const sp<SensorService>& service, uid_t uid)
+        const sp<SensorService>& service, uid_t uid, String8 packageName, bool isDataInjectionMode,
+        const String16& opPackageName)
     : mService(service), mUid(uid), mWakeLockRefCount(0), mHasLooperCallbacks(false),
-      mDead(false), mEventCache(NULL), mCacheSize(0), mMaxCacheSize(0) {
+      mDead(false), mDataInjectionMode(isDataInjectionMode), mEventCache(NULL),
+      mCacheSize(0), mMaxCacheSize(0), mPackageName(packageName), mOpPackageName(opPackageName) {
     mChannel = new BitTube(mService->mSocketBufferSize);
 #if DEBUG_CONNECTIONS
     mEventsReceived = mEventsSentFromCache = mEventsSent = 0;
@@ -1062,8 +1385,10 @@
 
 void SensorService::SensorEventConnection::dump(String8& result) {
     Mutex::Autolock _l(mConnectionLock);
-    result.appendFormat("\t WakeLockRefCount %d | uid %d | cache size %d | max cache size %d\n",
-            mWakeLockRefCount, mUid, mCacheSize, mMaxCacheSize);
+    result.appendFormat("\tOperating Mode: %s\n",mDataInjectionMode ? "DATA_INJECTION" : "NORMAL");
+    result.appendFormat("\t %s | WakeLockRefCount %d | uid %d | cache size %d | "
+            "max cache size %d\n", mPackageName.string(), mWakeLockRefCount, mUid, mCacheSize,
+            mMaxCacheSize);
     for (size_t i = 0; i < mSensorInfo.size(); ++i) {
         const FlushInfo& flushInfo = mSensorInfo.valueAt(i);
         result.appendFormat("\t %s 0x%08x | status: %s | pending flush events %d \n",
@@ -1087,7 +1412,8 @@
 
 bool SensorService::SensorEventConnection::addSensor(int32_t handle) {
     Mutex::Autolock _l(mConnectionLock);
-    if (!verifyCanAccessSensor(mService->getSensorFromHandle(handle), "Tried adding")) {
+    if (!canAccessSensor(mService->getSensorFromHandle(handle),
+            "Tried adding", mOpPackageName)) {
         return false;
     }
     if (mSensorInfo.indexOfKey(handle) < 0) {
@@ -1126,6 +1452,10 @@
     return false;
 }
 
+String8 SensorService::SensorEventConnection::getPackageName() const {
+    return mPackageName;
+}
+
 void SensorService::SensorEventConnection::setFirstFlushPending(int32_t handle,
                                 bool value) {
     Mutex::Autolock _l(mConnectionLock);
@@ -1143,7 +1473,8 @@
 
 void SensorService::SensorEventConnection::updateLooperRegistrationLocked(
         const sp<Looper>& looper) {
-    bool isConnectionActive = mSensorInfo.size() > 0;
+    bool isConnectionActive = (mSensorInfo.size() > 0 && !mDataInjectionMode) ||
+                              mDataInjectionMode;
     // If all sensors are unregistered OR Looper has encountered an error, we
     // can remove the Fd from the Looper if it has been previously added.
     if (!isConnectionActive || mDead) {
@@ -1157,6 +1488,7 @@
 
     int looper_flags = 0;
     if (mCacheSize > 0) looper_flags |= ALOOPER_EVENT_OUTPUT;
+    if (mDataInjectionMode) looper_flags |= ALOOPER_EVENT_INPUT;
     for (size_t i = 0; i < mSensorInfo.size(); ++i) {
         const int handle = mSensorInfo.keyAt(i);
         if (mService->getSensorFromHandle(handle).isWakeUpSensor()) {
@@ -1200,7 +1532,7 @@
         sensors_event_t* scratch,
         SensorEventConnection const * const * mapFlushEventsToConnections) {
     // filter out events not for this connection
-    size_t count = 0;
+    int count = 0;
     Mutex::Autolock _l(mConnectionLock);
     if (scratch) {
         size_t i=0;
@@ -1492,7 +1824,7 @@
     status_t err;
     if (enabled) {
         err = mService->enable(this, handle, samplingPeriodNs, maxBatchReportLatencyNs,
-                               reservedFlags);
+                               reservedFlags, mOpPackageName);
 
     } else {
         err = mService->disable(this, handle);
@@ -1503,11 +1835,11 @@
 status_t SensorService::SensorEventConnection::setEventRate(
         int handle, nsecs_t samplingPeriodNs)
 {
-    return mService->setEventRate(this, handle, samplingPeriodNs);
+    return mService->setEventRate(this, handle, samplingPeriodNs, mOpPackageName);
 }
 
 status_t  SensorService::SensorEventConnection::flush() {
-    return  mService->flushSensor(this);
+    return  mService->flushSensor(this, mOpPackageName);
 }
 
 int SensorService::SensorEventConnection::handleEvent(int fd, int events, void* /*data*/) {
@@ -1523,26 +1855,55 @@
             updateLooperRegistrationLocked(mService->getLooper());
         }
         mService->checkWakeLockState();
+        if (mDataInjectionMode) {
+            // If the Looper has encountered some error in data injection mode, reset SensorService
+            // back to normal mode.
+            mService->resetToNormalMode();
+            mDataInjectionMode = false;
+        }
         return 1;
     }
 
     if (events & ALOOPER_EVENT_INPUT) {
-        uint32_t numAcks = 0;
-        ssize_t ret = ::recv(fd, &numAcks, sizeof(numAcks), MSG_DONTWAIT);
+        unsigned char buf[sizeof(sensors_event_t)];
+        ssize_t numBytesRead = ::recv(fd, buf, sizeof(buf), MSG_DONTWAIT);
         {
            Mutex::Autolock _l(mConnectionLock);
-           // Sanity check to ensure  there are no read errors in recv, numAcks is always
-           // within the range and not zero. If any of the above don't hold reset mWakeLockRefCount
-           // to zero.
-           if (ret != sizeof(numAcks) || numAcks > mWakeLockRefCount || numAcks == 0) {
-               ALOGE("Looper read error ret=%d numAcks=%d", ret, numAcks);
-               mWakeLockRefCount = 0;
-           } else {
-               mWakeLockRefCount -= numAcks;
-           }
+           if (numBytesRead == sizeof(sensors_event_t)) {
+               if (!mDataInjectionMode) {
+                   ALOGE("Data injected in normal mode, dropping event"
+                         "package=%s uid=%d", mPackageName.string(), mUid);
+                   // Unregister call backs.
+                   return 0;
+               }
+               SensorDevice& dev(SensorDevice::getInstance());
+               sensors_event_t sensor_event;
+               memset(&sensor_event, 0, sizeof(sensor_event));
+               memcpy(&sensor_event, buf, sizeof(sensors_event_t));
+               Sensor sensor = mService->getSensorFromHandle(sensor_event.sensor);
+               sensor_event.type = sensor.getType();
+               dev.injectSensorData(&sensor_event);
 #if DEBUG_CONNECTIONS
-           mTotalAcksReceived += numAcks;
+               ++mEventsReceived;
 #endif
+           } else if (numBytesRead == sizeof(uint32_t)) {
+               uint32_t numAcks = 0;
+               memcpy(&numAcks, buf, numBytesRead);
+               // Sanity check to ensure  there are no read errors in recv, numAcks is always
+               // within the range and not zero. If any of the above don't hold reset
+               // mWakeLockRefCount to zero.
+               if (numAcks > 0 && numAcks < mWakeLockRefCount) {
+                   mWakeLockRefCount -= numAcks;
+               } else {
+                   mWakeLockRefCount = 0;
+               }
+#if DEBUG_CONNECTIONS
+               mTotalAcksReceived += numAcks;
+#endif
+           } else {
+               // Read error, reset wakelock refcount.
+               mWakeLockRefCount = 0;
+           }
         }
         // Check if wakelock can be released by sensorservice. mConnectionLock needs to be released
         // here as checkWakeLockState() will need it.
@@ -1561,8 +1922,8 @@
 }
 
 int SensorService::SensorEventConnection::computeMaxCacheSizeLocked() const {
-    int fifoWakeUpSensors = 0;
-    int fifoNonWakeUpSensors = 0;
+    size_t fifoWakeUpSensors = 0;
+    size_t fifoNonWakeUpSensors = 0;
     for (size_t i = 0; i < mSensorInfo.size(); ++i) {
         const Sensor& sensor = mService->getSensorFromHandle(mSensorInfo.keyAt(i));
         if (sensor.getFifoReservedEventCount() == sensor.getFifoMaxEventCount()) {
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index e9ca3a5..9a573ae 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -27,6 +27,7 @@
 #include <utils/AndroidThreads.h>
 #include <utils/RefBase.h>
 #include <utils/Looper.h>
+#include <utils/String8.h>
 
 #include <binder/BinderService.h>
 
@@ -52,6 +53,9 @@
 // For older HALs which don't support batching, use a smaller socket buffer size.
 #define SOCKET_BUFFER_SIZE_NON_BATCHED 4 * 1024
 
+#define CIRCULAR_BUF_SIZE 10
+#define SENSOR_REGISTRATIONS_BUF_SIZE 20
+
 struct sensors_poll_device_t;
 struct sensors_module_t;
 
@@ -65,6 +69,51 @@
 {
     friend class BinderService<SensorService>;
 
+    enum Mode {
+       // The regular operating mode where any application can register/unregister/call flush on
+       // sensors.
+       NORMAL = 0,
+       // This mode is only used for testing purposes. Not all HALs support this mode. In this
+       // mode, the HAL ignores the sensor data provided by physical sensors and accepts the data
+       // that is injected from the SensorService as if it were the real sensor data. This mode
+       // is primarily used for testing various algorithms like vendor provided SensorFusion,
+       // Step Counter and Step Detector etc. Typically in this mode, there will be a client
+       // (a SensorEventConnection) which will be injecting sensor data into the HAL. Normal apps
+       // can unregister and register for any sensor that supports injection. Registering to sensors
+       // that do not support injection will give an error.
+       // TODO(aakella) : Allow exactly one client to inject sensor data at a time.
+       DATA_INJECTION = 1,
+       // This mode is used only for testing sensors. Each sensor can be tested in isolation with
+       // the required sampling_rate and maxReportLatency parameters without having to think about
+       // the data rates requested by other applications. End user devices are always expected to be
+       // in NORMAL mode. When this mode is first activated, all active sensors from all connections
+       // are disabled. Calling flush() will return an error. In this mode, only the requests from
+       // selected apps whose package names are whitelisted are allowed (typically CTS apps).  Only
+       // these apps can register/unregister/call flush() on sensors. If SensorService switches to
+       // NORMAL mode again, all sensors that were previously registered to are activated with the
+       // corresponding paramaters if the application hasn't unregistered for sensors in the mean
+       // time.
+       // NOTE: Non whitelisted app whose sensors were previously deactivated may still receive
+       // events if a whitelisted app requests data from the same sensor.
+       RESTRICTED = 2
+
+      // State Transitions supported.
+      //     RESTRICTED   <---  NORMAL   ---> DATA_INJECTION
+      //                  --->           <---
+
+      // Shell commands to switch modes in SensorService.
+      // 1) Put SensorService in RESTRICTED mode with packageName .cts. If it is already in
+      // restricted mode it is treated as a NO_OP (and packageName is NOT changed).
+      // $ adb shell dumpsys sensorservice restrict .cts.
+      //
+      // 2) Put SensorService in DATA_INJECTION mode with packageName .xts. If it is already in
+      // data_injection mode it is treated as a NO_OP (and packageName is NOT changed).
+      // $ adb shell dumpsys sensorservice data_injection .xts.
+      //
+      // 3) Reset sensorservice back to NORMAL mode.
+      // $ adb shell dumpsys sensorservice enable
+    };
+
     static const char* WAKE_LOCK_NAME;
 
     static char const* getServiceName() ANDROID_API { return "sensorservice"; }
@@ -77,8 +126,10 @@
     virtual bool threadLoop();
 
     // ISensorServer interface
-    virtual Vector<Sensor> getSensorList();
-    virtual sp<ISensorEventConnection> createSensorEventConnection();
+    virtual Vector<Sensor> getSensorList(const String16& opPackageName);
+    virtual sp<ISensorEventConnection> createSensorEventConnection(const String8& packageName,
+             int requestedMode, const String16& opPackageName);
+    virtual int isDataInjectionEnabled();
     virtual status_t dump(int fd, const Vector<String16>& args);
 
     class SensorEventConnection : public BnSensorEventConnection, public LooperCallback {
@@ -133,7 +184,6 @@
         // connection FD may be added to the Looper. The flags to set are determined by the internal
         // state of the connection. FDs are added to the looper when wake-up sensors are registered
         // (to poll for acknowledgements) and when write fails on the socket when there are too many
-        // events (to poll when the FD is available for writing). FDs are removed when there is an
         // error and the other end hangs up or when this client unregisters for this connection.
         void updateLooperRegistration(const sp<Looper>& looper);
         void updateLooperRegistrationLocked(const sp<Looper>& looper);
@@ -156,6 +206,8 @@
         // mWakeLockRefCount is reset to zero. needsWakeLock method will always return false, if
         // this flag is set.
         bool mDead;
+
+        bool mDataInjectionMode;
         struct FlushInfo {
             // The number of flush complete events dropped for this sensor is stored here.
             // They are sent separately before the next batch of events.
@@ -169,14 +221,16 @@
         KeyedVector<int, FlushInfo> mSensorInfo;
         sensors_event_t *mEventCache;
         int mCacheSize, mMaxCacheSize;
-
+        String8 mPackageName;
+        const String16 mOpPackageName;
 #if DEBUG_CONNECTIONS
         int mEventsReceived, mEventsSent, mEventsSentFromCache;
         int mTotalAcksNeeded, mTotalAcksReceived;
 #endif
 
     public:
-        SensorEventConnection(const sp<SensorService>& service, uid_t uid);
+        SensorEventConnection(const sp<SensorService>& service, uid_t uid, String8 packageName,
+                 bool isDataInjectionMode, const String16& opPackageName);
 
         status_t sendEvents(sensors_event_t const* buffer, size_t count,
                 sensors_event_t* scratch,
@@ -190,6 +244,7 @@
         void dump(String8& result);
         bool needsWakeLock();
         void resetWakeLockRefCount();
+        String8 getPackageName() const;
 
         uid_t getUid() const { return mUid; }
     };
@@ -208,6 +263,7 @@
         void addPendingFlushConnection(const sp<SensorEventConnection>& connection);
         void removeFirstPendingFlushConnection();
         SensorEventConnection * getFirstPendingFlushConnection();
+        void clearAllPendingFlushConnections();
     };
 
     class SensorEventAckReceiver : public Thread {
@@ -217,6 +273,63 @@
         SensorEventAckReceiver(const sp<SensorService>& service): mService(service) {}
     };
 
+    // sensor_event_t with only the data and the timestamp.
+    struct TrimmedSensorEvent {
+        union {
+            float *mData;
+            uint64_t mStepCounter;
+        };
+        // Timestamp from the sensor_event.
+        int64_t mTimestamp;
+        // HH:MM:SS local time at which this sensor event is read at SensorService. Useful
+        // for debugging.
+        int32_t mHour, mMin, mSec;
+
+        TrimmedSensorEvent(int sensorType);
+        static bool isSentinel(const TrimmedSensorEvent& event);
+
+        ~TrimmedSensorEvent() {
+            delete [] mData;
+        }
+    };
+
+    // A circular buffer of TrimmedSensorEvents. The size of this buffer is typically 10. The
+    // last N events generated from the sensor are stored in this buffer. The buffer is NOT
+    // cleared when the sensor unregisters and as a result one may see very old data in the
+    // dumpsys output but this is WAI.
+    class CircularBuffer {
+        int mNextInd;
+        int mSensorType;
+        int mBufSize;
+        TrimmedSensorEvent ** mTrimmedSensorEventArr;
+    public:
+        CircularBuffer(int sensor_event_type);
+        void addEvent(const sensors_event_t& sensor_event);
+        void printBuffer(String8& buffer) const;
+        bool populateLastEvent(sensors_event_t *event);
+        ~CircularBuffer();
+    };
+
+    struct SensorRegistrationInfo {
+        int32_t mSensorHandle;
+        String8 mPackageName;
+        bool mActivated;
+        int32_t mSamplingRateUs;
+        int32_t mMaxReportLatencyUs;
+        int32_t mHour, mMin, mSec;
+
+        SensorRegistrationInfo() : mPackageName() {
+            mSensorHandle = mSamplingRateUs = mMaxReportLatencyUs = INT32_MIN;
+            mHour = mMin = mSec = INT32_MIN;
+            mActivated = false;
+        }
+
+        static bool isSentinel(const SensorRegistrationInfo& info) {
+           return (info.mHour == INT32_MIN && info.mMin == INT32_MIN && info.mSec == INT32_MIN);
+        }
+    };
+
+    static int getNumEventsForSensorType(int sensor_event_type);
     String8 getSensorName(int handle) const;
     bool isVirtualSensor(int handle) const;
     Sensor getSensorFromHandle(int handle) const;
@@ -231,8 +344,8 @@
             const sp<SensorEventConnection>& connection, int handle);
     void cleanupAutoDisabledSensorLocked(const sp<SensorEventConnection>& connection,
             sensors_event_t const* buffer, const int count);
-    static bool canAccessSensor(const Sensor& sensor);
-    static bool verifyCanAccessSensor(const Sensor& sensor, const char* operation);
+    static bool canAccessSensor(const Sensor& sensor, const char* operation,
+            const String16& opPackageName);
     // SensorService acquires a partial wakelock for delivering events from wake up sensors. This
     // method checks whether all the events from these wake up sensors have been delivered to the
     // corresponding applications, if yes the wakelock is released.
@@ -261,6 +374,15 @@
     // to the output vector.
     void populateActiveConnections(SortedVector< sp<SensorEventConnection> >* activeConnections);
 
+    // If SensorService is operating in RESTRICTED mode, only select whitelisted packages are
+    // allowed to register for or call flush on sensors. Typically only cts test packages are
+    // allowed.
+    bool isWhiteListedPackage(const String8& packageName);
+
+    // Reset the state of SensorService to NORMAL mode.
+    status_t resetToNormalMode();
+    status_t resetToNormalModeLocked();
+
     // constants
     Vector<Sensor> mSensorList;
     Vector<Sensor> mUserSensorListDebug;
@@ -282,17 +404,28 @@
     bool mWakeLockAcquired;
     sensors_event_t *mSensorEventBuffer, *mSensorEventScratch;
     SensorEventConnection const **mMapFlushEventsToConnections;
+    Mode mCurrentOperatingMode;
+    // This packagaName is set when SensorService is in RESTRICTED or DATA_INJECTION mode. Only
+    // applications with this packageName are allowed to activate/deactivate or call flush on
+    // sensors. To run CTS this is can be set to ".cts." and only CTS tests will get access to
+    // sensors.
+    String8 mWhiteListedPackage;
 
     // The size of this vector is constant, only the items are mutable
-    KeyedVector<int32_t, sensors_event_t> mLastEventSeen;
+    KeyedVector<int32_t, CircularBuffer *> mLastEventSeen;
 
+    int mNextSensorRegIndex;
+    Vector<SensorRegistrationInfo> mLastNSensorRegistrations;
 public:
     void cleanupConnection(SensorEventConnection* connection);
     status_t enable(const sp<SensorEventConnection>& connection, int handle,
-                    nsecs_t samplingPeriodNs,  nsecs_t maxBatchReportLatencyNs, int reservedFlags);
+                    nsecs_t samplingPeriodNs,  nsecs_t maxBatchReportLatencyNs, int reservedFlags,
+                    const String16& opPackageName);
     status_t disable(const sp<SensorEventConnection>& connection, int handle);
-    status_t setEventRate(const sp<SensorEventConnection>& connection, int handle, nsecs_t ns);
-    status_t flushSensor(const sp<SensorEventConnection>& connection);
+    status_t setEventRate(const sp<SensorEventConnection>& connection, int handle, nsecs_t ns,
+                          const String16& opPackageName);
+    status_t flushSensor(const sp<SensorEventConnection>& connection,
+                         const String16& opPackageName);
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/sensorservice/tests/sensorservicetest.cpp b/services/sensorservice/tests/sensorservicetest.cpp
index 1025fa8..cfdf6a3 100644
--- a/services/sensorservice/tests/sensorservicetest.cpp
+++ b/services/sensorservice/tests/sensorservicetest.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <inttypes.h>
 #include <android/sensor.h>
 #include <gui/Sensor.h>
 #include <gui/SensorManager.h>
@@ -25,7 +26,7 @@
 static nsecs_t sStartTime = 0;
 
 
-int receiver(int fd, int events, void* data)
+int receiver(__unused int fd, __unused int events, void* data)
 {
     sp<SensorEventQueue> q((SensorEventQueue*)data);
     ssize_t n;
@@ -44,7 +45,7 @@
             oldTimeStamp = buffer[i].timestamp;
 
             if (buffer[i].type == Sensor::TYPE_ACCELEROMETER) {
-                printf("%lld\t%8f\t%8f\t%8f\t%f\n",
+                printf("%" PRId64 "\t%8f\t%8f\t%8f\t%f\n",
                         buffer[i].timestamp,
                         buffer[i].data[0], buffer[i].data[1], buffer[i].data[2],
                         1.0/t);
@@ -59,9 +60,9 @@
 }
 
 
-int main(int argc, char** argv)
+int main()
 {
-    SensorManager& mgr(SensorManager::getInstance());
+    SensorManager mgr(String16("Sensor Service Test"));
 
     Sensor const* const* list;
     ssize_t count = mgr.getSensorList(&list);
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index f7d32d0..49389e0 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -93,7 +93,7 @@
      const int pid = ipc->getCallingPid();
      const int uid = ipc->getCallingUid();
      const int self_pid = getpid();
-     if (CC_UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != 0)) {
+     if (CC_UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != AID_SYSTEM && uid != 0)) {
          // we're called from a different process, do the real check
          if (!PermissionCache::checkCallingPermission(sAccessSurfaceFlinger))
          {
diff --git a/services/surfaceflinger/DdmConnection.cpp b/services/surfaceflinger/DdmConnection.cpp
index a000a84..659c2c8 100644
--- a/services/surfaceflinger/DdmConnection.cpp
+++ b/services/surfaceflinger/DdmConnection.cpp
@@ -66,7 +66,7 @@
     jint (*registerNatives)(JNIEnv* env, jclass clazz);
     registerNatives = reinterpret_cast<decltype(registerNatives)>(
             dlsym(libandroid_runtime_dso,
-                  "Java_com_android_internal_util_WithFramework_registerNatives"));
+                "Java_com_android_internal_util_WithFramework_registerNatives"));
     ALOGE_IF(!registerNatives, "DdmConnection: %s", dlerror());
 
     if (!JNI_CreateJavaVM || !registerNatives) {
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index 96efc34..67142b6 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -139,7 +139,7 @@
     enum { MAX_RESYNC_SAMPLES = 32 };
     enum { MIN_RESYNC_SAMPLES_FOR_UPDATE = 3 };
     enum { NUM_PRESENT_SAMPLES = 8 };
-    enum { MAX_RESYNC_SAMPLES_WITHOUT_PRESENT = 12 };
+    enum { MAX_RESYNC_SAMPLES_WITHOUT_PRESENT = 4 };
 
     // mPeriod is the computed period of the modeled vsync events in
     // nanoseconds.
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index c8b36ec..2dad005 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -305,13 +305,16 @@
 }
 
 void HWComposer::hotplug(int disp, int connected) {
-    if (disp == HWC_DISPLAY_PRIMARY || disp >= VIRTUAL_DISPLAY_ID_BASE) {
+    if (disp >= VIRTUAL_DISPLAY_ID_BASE) {
         ALOGE("hotplug event received for invalid display: disp=%d connected=%d",
                 disp, connected);
         return;
     }
     queryDisplayProperties(disp);
-    mEventHandler.onHotplugReceived(disp, bool(connected));
+    // Do not teardown or recreate the primary display
+    if (disp != HWC_DISPLAY_PRIMARY) {
+        mEventHandler.onHotplugReceived(disp, bool(connected));
+    }
 }
 
 static float getDefaultDensity(uint32_t width, uint32_t height) {
@@ -461,7 +464,7 @@
 }
 
 uint32_t HWComposer::getFormat(int disp) const {
-    if (uint32_t(disp)>31 || !mAllocatedDisplayIDs.hasBit(disp)) {
+    if (static_cast<uint32_t>(disp) >= MAX_HWC_DISPLAYS || !mAllocatedDisplayIDs.hasBit(disp)) {
         return HAL_PIXEL_FORMAT_RGBA_8888;
     } else {
         return mDisplayData[disp].format;
@@ -632,6 +635,7 @@
 }
 
 status_t HWComposer::prepare() {
+    Mutex::Autolock _l(mDisplayLock);
     for (size_t i=0 ; i<mNumDisplays ; i++) {
         DisplayData& disp(mDisplayData[i]);
         if (disp.framebufferTarget) {
@@ -1142,6 +1146,7 @@
 }
 
 void HWComposer::dump(String8& result) const {
+    Mutex::Autolock _l(mDisplayLock);
     if (mHwc) {
         result.appendFormat("Hardware Composer state (version %08x):\n", hwcApiVersion(mHwc));
         result.appendFormat("  mDebugForceFakeVSync=%d\n", mDebugForceFakeVSync);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 28d8c65..cc98b4c 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -354,6 +354,8 @@
     // mLists[i>0] can be NULL. that display is to be ignored
     struct hwc_display_contents_1*  mLists[MAX_HWC_DISPLAYS];
     DisplayData                     mDisplayData[MAX_HWC_DISPLAYS];
+    // protect mDisplayData from races between prepare and dump
+    mutable Mutex mDisplayLock;
     size_t                          mNumDisplays;
 
     cb_context*                     mCBContext;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 11cbdc6..ba4c198 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -530,6 +530,15 @@
     return INVALID_OPERATION;
 }
 
+status_t VirtualDisplaySurface::setGenerationNumber(uint32_t /* generation */) {
+    ALOGE("setGenerationNumber not supported on VirtualDisplaySurface");
+    return INVALID_OPERATION;
+}
+
+String8 VirtualDisplaySurface::getConsumerName() const {
+    return String8("VirtualDisplaySurface");
+}
+
 void VirtualDisplaySurface::updateQueueBufferOutput(
         const QueueBufferOutput& qbo) {
     uint32_t w, h, transformHint, numPendingBuffers;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 97af980..6298751 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -116,6 +116,8 @@
     virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,
             PixelFormat format, uint32_t usage);
     virtual status_t allowAllocation(bool allow);
+    virtual status_t setGenerationNumber(uint32_t generationNumber);
+    virtual String8 getConsumerName() const override;
 
     //
     // Utility methods
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 2944c63..5ff79a9 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -76,11 +76,15 @@
         mFiltering(false),
         mNeedsFiltering(false),
         mMesh(Mesh::TRIANGLE_FAN, 4, 2, 2),
-        mSecure(false),
         mProtectedByApp(false),
         mHasSurface(false),
         mClientRef(client),
-        mPotentialCursor(false)
+        mPotentialCursor(false),
+        mQueueItemLock(),
+        mQueueItemCondition(),
+        mQueueItems(),
+        mLastFrameNumberReceived(0),
+        mUpdateTexImageFailed(false)
 {
     mCurrentCrop.makeInvalid();
     mFlinger->getRenderEngine().genTextures(1, &mTextureName);
@@ -91,6 +95,8 @@
         layerFlags |= layer_state_t::eLayerHidden;
     if (flags & ISurfaceComposerClient::eOpaque)
         layerFlags |= layer_state_t::eLayerOpaque;
+    if (flags & ISurfaceComposerClient::eSecure)
+        layerFlags |= layer_state_t::eLayerSecure;
 
     if (flags & ISurfaceComposerClient::eNonPremultiplied)
         mPremultipliedAlpha = false;
@@ -163,20 +169,54 @@
     // Add this buffer from our internal queue tracker
     { // Autolock scope
         Mutex::Autolock lock(mQueueItemLock);
+
+        // Reset the frame number tracker when we receive the first buffer after
+        // a frame number reset
+        if (item.mFrameNumber == 1) {
+            mLastFrameNumberReceived = 0;
+        }
+
+        // Ensure that callbacks are handled in order
+        while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
+            status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
+                    ms2ns(500));
+            if (result != NO_ERROR) {
+                ALOGE("[%s] Timed out waiting on callback", mName.string());
+            }
+        }
+
         mQueueItems.push_back(item);
+        android_atomic_inc(&mQueuedFrames);
+
+        // Wake up any pending callbacks
+        mLastFrameNumberReceived = item.mFrameNumber;
+        mQueueItemCondition.broadcast();
     }
 
-    android_atomic_inc(&mQueuedFrames);
     mFlinger->signalLayerUpdate();
 }
 
 void Layer::onFrameReplaced(const BufferItem& item) {
     Mutex::Autolock lock(mQueueItemLock);
+
+    // Ensure that callbacks are handled in order
+    while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
+        status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
+                ms2ns(500));
+        if (result != NO_ERROR) {
+            ALOGE("[%s] Timed out waiting on callback", mName.string());
+        }
+    }
+
     if (mQueueItems.empty()) {
         ALOGE("Can't replace a frame on an empty queue");
         return;
     }
     mQueueItems.editItemAt(0) = item;
+
+    // Wake up any pending callbacks
+    mLastFrameNumberReceived = item.mFrameNumber;
+    mQueueItemCondition.broadcast();
 }
 
 void Layer::onSidebandStreamChanged() {
@@ -217,7 +257,6 @@
     mFormat = format;
 
     mPotentialCursor = (flags & ISurfaceComposerClient::eCursorWindow) ? true : false;
-    mSecure = (flags & ISurfaceComposerClient::eSecure) ? true : false;
     mProtectedByApp = (flags & ISurfaceComposerClient::eProtectedByApp) ? true : false;
     mCurrentOpacity = getOpacityForFormat(format);
 
@@ -512,16 +551,7 @@
     const Transform& tr = hw->getTransform();
     Region visible = tr.transform(visibleRegion.intersect(hw->getViewport()));
     layer.setVisibleRegionScreen(visible);
-
-    // Pass full-surface damage down untouched
-    if (surfaceDamageRegion.isRect() &&
-            surfaceDamageRegion.getBounds() == Rect::INVALID_RECT) {
-        layer.setSurfaceDamage(surfaceDamageRegion);
-    } else {
-        Region surfaceDamage =
-            tr.transform(surfaceDamageRegion.intersect(hw->getViewport()));
-        layer.setSurfaceDamage(surfaceDamage);
-    }
+    layer.setSurfaceDamage(surfaceDamageRegion);
 
     if (mSidebandStream.get()) {
         layer.setSidebandStream(mSidebandStream);
@@ -821,6 +851,12 @@
     return ((s.flags & layer_state_t::eLayerOpaque) != 0) || mCurrentOpacity;
 }
 
+bool Layer::isSecure() const
+{
+    const Layer::State& s(mDrawingState);
+    return (s.flags & layer_state_t::eLayerSecure);
+}
+
 bool Layer::isProtected() const
 {
     const sp<GraphicBuffer>& activeBuffer(mActiveBuffer);
@@ -1065,11 +1101,26 @@
 // ----------------------------------------------------------------------------
 
 bool Layer::shouldPresentNow(const DispSync& dispSync) const {
+    if (mSidebandStreamChanged) {
+        return true;
+    }
+
     Mutex::Autolock lock(mQueueItemLock);
+    if (mQueueItems.empty()) {
+        return false;
+    }
+    auto timestamp = mQueueItems[0].mTimestamp;
     nsecs_t expectedPresent =
             mSurfaceFlingerConsumer->computeExpectedPresent(dispSync);
-    return mQueueItems.empty() ?
-            false : mQueueItems[0].mTimestamp < expectedPresent;
+
+    // Ignore timestamps more than a second in the future
+    bool isPlausible = timestamp < (expectedPresent + s2ns(1));
+    ALOGW_IF(!isPlausible, "[%s] Timestamp %" PRId64 " seems implausible "
+            "relative to expectedPresent %" PRId64, mName.string(), timestamp,
+            expectedPresent);
+
+    bool isDue = timestamp < expectedPresent;
+    return isDue || !isPlausible;
 }
 
 bool Layer::onPreComposition() {
@@ -1120,6 +1171,10 @@
     if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) {
         // mSidebandStreamChanged was true
         mSidebandStream = mSurfaceFlingerConsumer->getSidebandStream();
+        if (mSidebandStream != NULL) {
+            setTransactionFlags(eTransactionNeeded);
+            mFlinger->setTransactionFlags(eTraversalNeeded);
+        }
         recomputeVisibleRegions = true;
 
         const State& s(getDrawingState());
@@ -1252,21 +1307,62 @@
         Reject r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
                 getProducerStickyTransform() != 0);
 
+        uint64_t maxFrameNumber = 0;
+        {
+            Mutex::Autolock lock(mQueueItemLock);
+            maxFrameNumber = mLastFrameNumberReceived;
+        }
+
         status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r,
-                mFlinger->mPrimaryDispSync);
+                mFlinger->mPrimaryDispSync, maxFrameNumber);
         if (updateResult == BufferQueue::PRESENT_LATER) {
             // Producer doesn't want buffer to be displayed yet.  Signal a
             // layer update so we check again at the next opportunity.
             mFlinger->signalLayerUpdate();
             return outDirtyRegion;
-        }
-
-        // Remove this buffer from our internal queue tracker
-        { // Autolock scope
+        } else if (updateResult == SurfaceFlingerConsumer::BUFFER_REJECTED) {
+            // If the buffer has been rejected, remove it from the shadow queue
+            // and return early
             Mutex::Autolock lock(mQueueItemLock);
             mQueueItems.removeAt(0);
+            android_atomic_dec(&mQueuedFrames);
+            return outDirtyRegion;
+        } else if (updateResult != NO_ERROR || mUpdateTexImageFailed) {
+            // This can occur if something goes wrong when trying to create the
+            // EGLImage for this buffer. If this happens, the buffer has already
+            // been released, so we need to clean up the queue and bug out
+            // early.
+            {
+                Mutex::Autolock lock(mQueueItemLock);
+                mQueueItems.clear();
+                android_atomic_and(0, &mQueuedFrames);
+            }
+
+            // Once we have hit this state, the shadow queue may no longer
+            // correctly reflect the incoming BufferQueue's contents, so even if
+            // updateTexImage starts working, the only safe course of action is
+            // to continue to ignore updates.
+            mUpdateTexImageFailed = true;
+
+            return outDirtyRegion;
         }
 
+        { // Autolock scope
+            auto currentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
+
+            Mutex::Autolock lock(mQueueItemLock);
+
+            // Remove any stale buffers that have been dropped during
+            // updateTexImage
+            while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
+                mQueueItems.removeAt(0);
+                android_atomic_dec(&mQueuedFrames);
+            }
+
+            mQueueItems.removeAt(0);
+        }
+
+
         // Decrement the queued-frames count.  Signal another event if we
         // have more frames pending.
         if (android_atomic_dec(&mQueuedFrames) > 1) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 46c17e5..c1e5e9f 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -174,7 +174,7 @@
      * isSecure - true if this surface is secure, that is if it prevents
      * screenshots or VNC servers.
      */
-    virtual bool isSecure() const           { return mSecure; }
+    virtual bool isSecure() const;
 
     /*
      * isProtected - true if the layer may contain protected content in the
@@ -339,9 +339,9 @@
 
 private:
     // Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener
-    virtual void onFrameAvailable(const BufferItem& item);
-    virtual void onFrameReplaced(const BufferItem& item);
-    virtual void onSidebandStreamChanged();
+    virtual void onFrameAvailable(const BufferItem& item) override;
+    virtual void onFrameReplaced(const BufferItem& item) override;
+    virtual void onSidebandStreamChanged() override;
 
     void commitTransaction();
 
@@ -402,7 +402,6 @@
     mutable Texture mTexture;
 
     // page-flip thread (currently main thread)
-    bool mSecure; // no screenshots
     bool mProtectedByApp; // application requires protected path to external sink
 
     // protected by mLock
@@ -416,7 +415,10 @@
 
     // Local copy of the queued contents of the incoming BufferQueue
     mutable Mutex mQueueItemLock;
+    Condition mQueueItemCondition;
     Vector<BufferItem> mQueueItems;
+    uint64_t mLastFrameNumberReceived;
+    bool mUpdateTexImageFailed; // This is only modified from the main thread
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index 9fb555b..fb7af97 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -114,6 +114,14 @@
     return mProducer->allowAllocation(allow);
 }
 
+status_t MonitoredProducer::setGenerationNumber(uint32_t generationNumber) {
+    return mProducer->setGenerationNumber(generationNumber);
+}
+
+String8 MonitoredProducer::getConsumerName() const {
+    return mProducer->getConsumerName();
+}
+
 IBinder* MonitoredProducer::onAsBinder() {
     return IInterface::asBinder(mProducer).get();
 }
diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
index b2f8293..da95766 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -54,6 +54,8 @@
     virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,
             PixelFormat format, uint32_t usage);
     virtual status_t allowAllocation(bool allow);
+    virtual status_t setGenerationNumber(uint32_t generationNumber);
+    virtual String8 getConsumerName() const override;
     virtual IBinder* onAsBinder();
 
 private:
diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/services/surfaceflinger/RenderEngine/Description.cpp
index 1adcd1f..0dab872 100644
--- a/services/surfaceflinger/RenderEngine/Description.cpp
+++ b/services/surfaceflinger/RenderEngine/Description.cpp
@@ -88,5 +88,9 @@
     mColorMatrixEnabled = (mtx != identity);
 }
 
+const mat4& Description::getColorMatrix() const {
+    return mColorMatrix;
+}
+
 
 } /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/Description.h b/services/surfaceflinger/RenderEngine/Description.h
index 43b835f..8a3447c 100644
--- a/services/surfaceflinger/RenderEngine/Description.h
+++ b/services/surfaceflinger/RenderEngine/Description.h
@@ -66,6 +66,7 @@
     void setColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
     void setProjectionMatrix(const mat4& mtx);
     void setColorMatrix(const mat4& mtx);
+    const mat4& getColorMatrix() const;
 
 private:
     bool mUniformsDirty;
diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
index 2e6af49..1a9f59b 100644
--- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
@@ -262,14 +262,6 @@
     }
 }
 
-void GLES11RenderEngine::beginGroup(const mat4& /*colorTransform*/) {
-    // doesn't do anything in GLES 1.1
-}
-
-void GLES11RenderEngine::endGroup() {
-    // doesn't do anything in GLES 1.1
-}
-
 void GLES11RenderEngine::dump(String8& result) {
     RenderEngine::dump(result);
 }
diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
index 87eb3e4..08de646 100644
--- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
@@ -62,9 +62,6 @@
 
     virtual void drawMesh(const Mesh& mesh);
 
-    virtual void beginGroup(const mat4& colorTransform);
-    virtual void endGroup();
-
     virtual size_t getMaxTextureSize() const;
     virtual size_t getMaxViewportDims() const;
 };
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
index 8712c9a..1fabaf5 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -169,6 +169,12 @@
     mState.setTexture(texture);
 }
 
+mat4 GLES20RenderEngine::setupColorTransform(const mat4& colorTransform) {
+    mat4 oldTransform = mState.getColorMatrix();
+    mState.setColorMatrix(colorTransform);
+    return oldTransform;
+}
+
 void GLES20RenderEngine::disableTexturing() {
     mState.disableTexture();
 }
@@ -237,78 +243,6 @@
     }
 }
 
-void GLES20RenderEngine::beginGroup(const mat4& colorTransform) {
-
-    GLuint tname, name;
-    // create the texture
-    glGenTextures(1, &tname);
-    glBindTexture(GL_TEXTURE_2D, tname);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mVpWidth, mVpHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
-
-    // create a Framebuffer Object to render into
-    glGenFramebuffers(1, &name);
-    glBindFramebuffer(GL_FRAMEBUFFER, name);
-    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tname, 0);
-
-    Group group;
-    group.texture = tname;
-    group.fbo = name;
-    group.width = mVpWidth;
-    group.height = mVpHeight;
-    group.colorTransform = colorTransform;
-
-    mGroupStack.push(group);
-}
-
-void GLES20RenderEngine::endGroup() {
-
-    const Group group(mGroupStack.top());
-    mGroupStack.pop();
-
-    // activate the previous render target
-    GLuint fbo = 0;
-    if (!mGroupStack.isEmpty()) {
-        fbo = mGroupStack.top().fbo;
-    }
-    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
-
-    // set our state
-    Texture texture(Texture::TEXTURE_2D, group.texture);
-    texture.setDimensions(group.width, group.height);
-    glBindTexture(GL_TEXTURE_2D, group.texture);
-
-    mState.setPlaneAlpha(1.0f);
-    mState.setPremultipliedAlpha(true);
-    mState.setOpaque(false);
-    mState.setTexture(texture);
-    mState.setColorMatrix(group.colorTransform);
-    glDisable(GL_BLEND);
-
-    Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2, 2);
-    Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
-    Mesh::VertexArray<vec2> texCoord(mesh.getTexCoordArray<vec2>());
-    position[0] = vec2(0, 0);
-    position[1] = vec2(group.width, 0);
-    position[2] = vec2(group.width, group.height);
-    position[3] = vec2(0, group.height);
-    texCoord[0] = vec2(0, 0);
-    texCoord[1] = vec2(1, 0);
-    texCoord[2] = vec2(1, 1);
-    texCoord[3] = vec2(0, 1);
-    drawMesh(mesh);
-
-    // reset color matrix
-    mState.setColorMatrix(mat4());
-
-    // free our fbo and texture
-    glDeleteFramebuffers(1, &group.fbo);
-    glDeleteTextures(1, &group.texture);
-}
-
 void GLES20RenderEngine::dump(String8& result) {
     RenderEngine::dump(result);
 }
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
index 3d6243e..819356a 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
@@ -72,14 +72,12 @@
     virtual void setupLayerTexturing(const Texture& texture);
     virtual void setupLayerBlackedOut();
     virtual void setupFillWithColor(float r, float g, float b, float a);
+    virtual mat4 setupColorTransform(const mat4& colorTransform);
     virtual void disableTexturing();
     virtual void disableBlending();
 
     virtual void drawMesh(const Mesh& mesh);
 
-    virtual void beginGroup(const mat4& colorTransform);
-    virtual void endGroup();
-
     virtual size_t getMaxTextureSize() const;
     virtual size_t getMaxViewportDims() const;
 };
diff --git a/services/surfaceflinger/RenderEngine/Mesh.cpp b/services/surfaceflinger/RenderEngine/Mesh.cpp
index 3f50cb0..ffd9be2 100644
--- a/services/surfaceflinger/RenderEngine/Mesh.cpp
+++ b/services/surfaceflinger/RenderEngine/Mesh.cpp
@@ -16,14 +16,40 @@
 
 #include "Mesh.h"
 
+#include <utils/Log.h>
+
 namespace android {
 
 Mesh::Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordSize)
     : mVertexCount(vertexCount), mVertexSize(vertexSize), mTexCoordsSize(texCoordSize),
       mPrimitive(primitive)
 {
-    mVertices = new float[(vertexSize + texCoordSize) * vertexCount];
-    mStride = mVertexSize + mTexCoordsSize;
+    if (vertexCount == 0) {
+        mVertices = new float[1];
+        mVertices[0] = 0.0f;
+        mStride = 0;
+        return;
+    }
+
+    size_t stride = vertexSize + texCoordSize;
+    size_t remainder = (stride * vertexCount) / vertexCount;
+    // Since all of the input parameters are unsigned, if stride is less than
+    // either vertexSize or texCoordSize, it must have overflowed. remainder
+    // will be equal to stride as long as stride * vertexCount doesn't overflow.
+    if ((stride < vertexSize) || (remainder != stride)) {
+        ALOGE("Overflow in Mesh(..., %zu, %zu, %zu)", vertexCount, vertexSize,
+                texCoordSize);
+        mVertices = new float[1];
+        mVertices[0] = 0.0f;
+        mVertexCount = 0;
+        mVertexSize = 0;
+        mTexCoordsSize = 0;
+        mStride = 0;
+        return;
+    }
+
+    mVertices = new float[stride * vertexCount];
+    mStride = stride;
 }
 
 Mesh::~Mesh() {
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
index 0de5cca..ba11259 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
@@ -199,10 +199,8 @@
             // un-premultiply if needed before linearization
             fs << "gl_FragColor.rgb = gl_FragColor.rgb/gl_FragColor.a;";
         }
-        fs << "gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(2.2));";
         fs << "vec4 transformed = colorMatrix * vec4(gl_FragColor.rgb, 1);";
         fs << "gl_FragColor.rgb = transformed.rgb/transformed.a;";
-        fs << "gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(1.0 / 2.2));";
         if (!needs.isOpaque() && needs.isPremultiplied()) {
             // and re-premultiply if needed after gamma correction
             fs << "gl_FragColor.rgb = gl_FragColor.rgb*gl_FragColor.a;";
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index 8d7529c..31a961e 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -99,18 +99,16 @@
     virtual void setupLayerBlackedOut() = 0;
     virtual void setupFillWithColor(float r, float g, float b, float a) = 0;
 
+    virtual mat4 setupColorTransform(const mat4& /* colorTransform */) {
+        return mat4();
+    }
+
     virtual void disableTexturing() = 0;
     virtual void disableBlending() = 0;
 
     // drawing
     virtual void drawMesh(const Mesh& mesh) = 0;
 
-    // grouping
-    // creates a color-transform group, everything drawn in the group will be
-    // transformed by the given color transform when endGroup() is called.
-    virtual void beginGroup(const mat4& colorTransform) = 0;
-    virtual void endGroup() = 0;
-
     // queries
     virtual size_t getMaxTextureSize() const = 0;
     virtual size_t getMaxViewportDims() const = 0;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index df4ac2e..de0f921 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -149,7 +149,11 @@
         mPrimaryHWVsyncEnabled(false),
         mHWVsyncAvailable(false),
         mDaltonize(false),
-        mHasColorMatrix(false)
+        mHasColorMatrix(false),
+        mHasPoweredOff(false),
+        mFrameBuckets(),
+        mTotalTime(0),
+        mLastSwapTime(0)
 {
     ALOGI("SurfaceFlinger is starting");
 
@@ -546,7 +550,7 @@
 
 status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
         Vector<DisplayInfo>* configs) {
-    if (configs == NULL) {
+    if ((configs == NULL) || (display.get() == NULL)) {
         return BAD_VALUE;
     }
 
@@ -997,8 +1001,8 @@
         }
     }
 
+    const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
     if (kIgnorePresentFences) {
-        const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
         if (hw->isDisplayOn()) {
             enableHardwareVsync();
         }
@@ -1017,6 +1021,26 @@
         }
         mAnimFrameTracker.advanceFrame();
     }
+
+    if (hw->getPowerMode() == HWC_POWER_MODE_OFF) {
+        return;
+    }
+
+    nsecs_t currentTime = systemTime();
+    if (mHasPoweredOff) {
+        mHasPoweredOff = false;
+    } else {
+        nsecs_t period = mPrimaryDispSync.getPeriod();
+        nsecs_t elapsedTime = currentTime - mLastSwapTime;
+        size_t numPeriods = static_cast<size_t>(elapsedTime / period);
+        if (numPeriods < NUM_BUCKETS - 1) {
+            mFrameBuckets[numPeriods] += elapsedTime;
+        } else {
+            mFrameBuckets[NUM_BUCKETS - 1] += elapsedTime;
+        }
+        mTotalTime += elapsedTime;
+    }
+    mLastSwapTime = currentTime;
 }
 
 void SurfaceFlinger::rebuildLayerStacks() {
@@ -1848,9 +1872,9 @@
         if (mDaltonize) {
             colorMatrix = colorMatrix * mDaltonizer();
         }
-        engine.beginGroup(colorMatrix);
+        mat4 oldMatrix = engine.setupColorTransform(colorMatrix);
         doComposeSurfaces(hw, dirtyRegion);
-        engine.endGroup();
+        engine.setupColorTransform(oldMatrix);
     }
 
     // update the swap region and clear the dirty region
@@ -1994,18 +2018,25 @@
     engine.fillRegionWithColor(region, height, 0, 0, 0, 0);
 }
 
-void SurfaceFlinger::addClientLayer(const sp<Client>& client,
+status_t SurfaceFlinger::addClientLayer(const sp<Client>& client,
         const sp<IBinder>& handle,
         const sp<IGraphicBufferProducer>& gbc,
         const sp<Layer>& lbc)
 {
+    // add this layer to the current state list
+    {
+        Mutex::Autolock _l(mStateLock);
+        if (mCurrentState.layersSortedByZ.size() >= MAX_LAYERS) {
+            return NO_MEMORY;
+        }
+        mCurrentState.layersSortedByZ.add(lbc);
+        mGraphicBufferProducerList.add(IInterface::asBinder(gbc));
+    }
+
     // attach this layer to the client
     client->attachLayer(handle, lbc);
 
-    // add this layer to the current state list
-    Mutex::Autolock _l(mStateLock);
-    mCurrentState.layersSortedByZ.add(lbc);
-    mGraphicBufferProducerList.add(IInterface::asBinder(gbc));
+    return NO_ERROR;
 }
 
 status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer) {
@@ -2204,9 +2235,7 @@
             if (layer->setTransparentRegionHint(s.transparentRegion))
                 flags |= eTraversalNeeded;
         }
-        if ((what & layer_state_t::eVisibilityChanged) ||
-                (what & layer_state_t::eOpacityChanged)) {
-            // TODO: should we just use an eFlagsChanged for this?
+        if (what & layer_state_t::eFlagsChanged) {
             if (layer->setFlags(s.flags, s.mask))
                 flags |= eTraversalNeeded;
         }
@@ -2262,10 +2291,16 @@
             break;
     }
 
-    if (result == NO_ERROR) {
-        addClientLayer(client, *handle, *gbp, layer);
-        setTransactionFlags(eTransactionNeeded);
+    if (result != NO_ERROR) {
+        return result;
     }
+
+    result = addClientLayer(client, *handle, *gbp, layer);
+    if (result != NO_ERROR) {
+        return result;
+    }
+
+    setTransactionFlags(eTransactionNeeded);
     return result;
 }
 
@@ -2398,6 +2433,7 @@
         }
 
         mVisibleRegionsDirty = true;
+        mHasPoweredOff = true;
         repaintEverything();
     } else if (mode == HWC_POWER_MODE_OFF) {
         if (type == DisplayDevice::DISPLAY_PRIMARY) {
@@ -2498,6 +2534,13 @@
                 mPrimaryDispSync.dump(result);
                 dumpAll = false;
             }
+
+            if ((index < numArgs) &&
+                    (args[index] == String16("--static-screen"))) {
+                index++;
+                dumpStaticScreenStats(result);
+                dumpAll = false;
+            }
         }
 
         if (dumpAll) {
@@ -2601,6 +2644,23 @@
     result.append(config);
 }
 
+void SurfaceFlinger::dumpStaticScreenStats(String8& result) const
+{
+    result.appendFormat("Static screen stats:\n");
+    for (size_t b = 0; b < NUM_BUCKETS - 1; ++b) {
+        float bucketTimeSec = mFrameBuckets[b] / 1e9;
+        float percent = 100.0f *
+                static_cast<float>(mFrameBuckets[b]) / mTotalTime;
+        result.appendFormat("  < %zd frames: %.3f s (%.1f%%)\n",
+                b + 1, bucketTimeSec, percent);
+    }
+    float bucketTimeSec = mFrameBuckets[NUM_BUCKETS - 1] / 1e9;
+    float percent = 100.0f *
+            static_cast<float>(mFrameBuckets[NUM_BUCKETS - 1]) / mTotalTime;
+    result.appendFormat("  %zd+ frames: %.3f s (%.1f%%)\n",
+            NUM_BUCKETS - 1, bucketTimeSec, percent);
+}
+
 void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
         String8& result) const
 {
@@ -2647,6 +2707,11 @@
         mHwc->getRefreshPeriod(HWC_DISPLAY_PRIMARY));
     result.append("\n");
 
+    // Dump static screen stats
+    result.append("\n");
+    dumpStaticScreenStats(result);
+    result.append("\n");
+
     /*
      * Dump the visible layer list
      */
@@ -2794,7 +2859,7 @@
             IPCThreadState* ipc = IPCThreadState::self();
             const int pid = ipc->getCallingPid();
             const int uid = ipc->getCallingUid();
-            if ((uid != AID_GRAPHICS) &&
+            if ((uid != AID_GRAPHICS && uid != AID_SYSTEM) &&
                     !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) {
                 ALOGE("Permission Denial: "
                         "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
@@ -3253,8 +3318,12 @@
     ATRACE_CALL();
 
     // get screen geometry
-    const uint32_t hw_w = hw->getWidth();
-    const uint32_t hw_h = hw->getHeight();
+    uint32_t hw_w = hw->getWidth();
+    uint32_t hw_h = hw->getHeight();
+
+    if (rotation & Transform::ROT_90) {
+        std::swap(hw_w, hw_h);
+    }
 
     if ((reqWidth > hw_w) || (reqHeight > hw_h)) {
         ALOGE("size mismatch (%d, %d) > (%d, %d)",
@@ -3270,8 +3339,8 @@
     sp<Surface> sur = new Surface(producer, false);
     ANativeWindow* window = sur.get();
 
-    status_t result = NO_ERROR;
-    if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) == NO_ERROR) {
+    status_t result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
+    if (result == NO_ERROR) {
         uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
                         GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
 
@@ -3361,7 +3430,7 @@
                     result = BAD_VALUE;
                 }
                 // queueBuffer takes ownership of syncFd
-                window->queueBuffer(window, buffer, syncFd);
+                result = window->queueBuffer(window, buffer, syncFd);
             }
         } else {
             result = BAD_VALUE;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index a06d1be..3759a92 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -144,6 +144,8 @@
     // every half hour.
     enum { LOG_FRAME_STATS_PERIOD =  30*60*60 };
 
+    static const size_t MAX_LAYERS = 4096;
+
     // We're reference counted, never destroy SurfaceFlinger directly
     virtual ~SurfaceFlinger();
 
@@ -305,7 +307,7 @@
     status_t removeLayer(const sp<Layer>& layer);
 
     // add a layer to SurfaceFlinger
-    void addClientLayer(const sp<Client>& client,
+    status_t addClientLayer(const sp<Client>& client,
             const sp<IBinder>& handle,
             const sp<IGraphicBufferProducer>& gbc,
             const sp<Layer>& lbc);
@@ -416,6 +418,8 @@
 
     void logFrameStats();
 
+    void dumpStaticScreenStats(String8& result) const;
+
     /* ------------------------------------------------------------------------
      * Attributes
      */
@@ -494,6 +498,13 @@
 
     mat4 mColorMatrix;
     bool mHasColorMatrix;
+
+    // Static screen stats
+    bool mHasPoweredOff;
+    static const size_t NUM_BUCKETS = 8; // < 1-7, 7+
+    nsecs_t mFrameBuckets[NUM_BUCKETS];
+    nsecs_t mTotalTime;
+    nsecs_t mLastSwapTime;
 };
 
 }; // namespace android
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index 19c497a..ed1f31b 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -32,7 +32,7 @@
 // ---------------------------------------------------------------------------
 
 status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter,
-        const DispSync& dispSync)
+        const DispSync& dispSync, uint64_t maxFrameNumber)
 {
     ATRACE_CALL();
     ALOGV("updateTexImage");
@@ -54,7 +54,8 @@
     // Acquire the next buffer.
     // In asynchronous mode the list is guaranteed to be one buffer
     // deep, while in synchronous mode we use the oldest buffer.
-    err = acquireBufferLocked(&item, computeExpectedPresent(dispSync));
+    err = acquireBufferLocked(&item, computeExpectedPresent(dispSync),
+            maxFrameNumber);
     if (err != NO_ERROR) {
         if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
             err = NO_ERROR;
@@ -74,7 +75,7 @@
     int buf = item.mBuf;
     if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) {
         releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, EGL_NO_SYNC_KHR);
-        return NO_ERROR;
+        return BUFFER_REJECTED;
     }
 
     // Release the previous buffer.
@@ -104,8 +105,9 @@
 }
 
 status_t SurfaceFlingerConsumer::acquireBufferLocked(BufferItem* item,
-        nsecs_t presentWhen) {
-    status_t result = GLConsumer::acquireBufferLocked(item, presentWhen);
+        nsecs_t presentWhen, uint64_t maxFrameNumber) {
+    status_t result = GLConsumer::acquireBufferLocked(item, presentWhen,
+            maxFrameNumber);
     if (result == NO_ERROR) {
         mTransformToDisplayInverse = item->mTransformToDisplayInverse;
         mSurfaceDamage = item->mSurfaceDamage;
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index 1aaba18..779e5b7 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -28,6 +28,8 @@
  */
 class SurfaceFlingerConsumer : public GLConsumer {
 public:
+    static const status_t BUFFER_REJECTED = UNKNOWN_ERROR + 8;
+
     struct ContentsChangedListener: public FrameAvailableListener {
         virtual void onSidebandStreamChanged() = 0;
     };
@@ -47,13 +49,15 @@
         virtual ~BufferRejecter() { }
     };
 
-    virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen);
+    virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen,
+            uint64_t maxFrameNumber = 0) override;
 
     // This version of updateTexImage() takes a functor that may be used to
     // reject the newly acquired buffer.  Unlike the GLConsumer version,
     // this does not guarantee that the buffer has been bound to the GL
     // texture.
-    status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync);
+    status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync,
+            uint64_t maxFrameNumber = 0);
 
     // See GLConsumer::bindTextureImageLocked().
     status_t bindTextureImage();
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 4d363c8..dcde512 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -16,6 +16,8 @@
 
 #include <gtest/gtest.h>
 
+#include <android/native_window.h>
+
 #include <binder/IMemory.h>
 
 #include <gui/ISurfaceComposer.h>
@@ -53,21 +55,23 @@
 class ScreenCapture : public RefBase {
 public:
     static void captureScreen(sp<ScreenCapture>* sc) {
-        sp<IMemoryHeap> heap;
-        uint32_t w=0, h=0;
-        PixelFormat fmt=0;
+        sp<IGraphicBufferProducer> producer;
+        sp<IGraphicBufferConsumer> consumer;
+        BufferQueue::createBufferQueue(&producer, &consumer);
+        IGraphicBufferProducer::QueueBufferOutput bufferOutput;
+        sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1);
         sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-        sp<IBinder> display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
-        ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &heap, &w, &h, &fmt, 0, 0,
-                0, INT_MAX));
-        ASSERT_TRUE(heap != NULL);
-        ASSERT_EQ(PIXEL_FORMAT_RGBA_8888, fmt);
-        *sc = new ScreenCapture(w, h, heap);
+        sp<IBinder> display(sf->getBuiltInDisplay(
+                ISurfaceComposer::eDisplayIdMain));
+        ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(), 0, 0,
+                0, INT_MAX, false));
+        *sc = new ScreenCapture(cpuConsumer);
     }
 
     void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) {
-        const uint8_t* img = reinterpret_cast<const uint8_t*>(mHeap->base());
-        const uint8_t* pixel = img + (4 * (y*mWidth + x));
+        ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mBuf.format);
+        const uint8_t* img = static_cast<const uint8_t*>(mBuf.data);
+        const uint8_t* pixel = img + (4 * (y * mBuf.stride + x));
         if (r != pixel[0] || g != pixel[1] || b != pixel[2]) {
             String8 err(String8::format("pixel @ (%3d, %3d): "
                     "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]",
@@ -77,15 +81,17 @@
     }
 
 private:
-    ScreenCapture(uint32_t w, uint32_t h, const sp<IMemoryHeap>& heap) :
-        mWidth(w),
-        mHeight(h),
-        mHeap(heap)
-    {}
+    ScreenCapture(const sp<CpuConsumer>& cc) :
+        mCC(cc) {
+        EXPECT_EQ(NO_ERROR, mCC->lockNextBuffer(&mBuf));
+    }
 
-    const uint32_t mWidth;
-    const uint32_t mHeight;
-    sp<IMemoryHeap> mHeap;
+    ~ScreenCapture() {
+        mCC->unlockBuffer(mBuf);
+    }
+
+    sp<CpuConsumer> mCC;
+    CpuConsumer::LockedBuffer mBuf;
 };
 
 class LayerUpdateTest : public ::testing::Test {