Merge "Removed HardwarePropertiesManagerService helper." into nyc-dev
diff --git a/aidl/gui/android/view/Surface.aidl b/aidl/gui/android/view/Surface.aidl
new file mode 100644
index 0000000..674c163
--- /dev/null
+++ b/aidl/gui/android/view/Surface.aidl
@@ -0,0 +1,20 @@
+/* //device/java/android/android/view/Surface.aidl
+**
+** Copyright 2007, 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.
+*/
+
+package android.view;
+
+parcelable Surface cpp_header "gui/Surface.h";
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 87f637c..23954ea 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -42,6 +42,8 @@
 
 using namespace android;
 
+#define LOG_TAG "atrace"
+
 #define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
 
 enum { MAX_SYS_FILES = 10 };
@@ -769,6 +771,7 @@
 // Read the current kernel trace and write it to stdout.
 static void dumpTrace()
 {
+    ALOGE("Dumping trace");
     int traceFD = open(k_tracePath, O_RDWR);
     if (traceFD == -1) {
         fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index e15a0c5..5898b41 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -90,9 +90,7 @@
  * See bugreport-format.txt for more info.
  */
 // TODO: change to "v1" before final N build
-static std::string VERSION_DEFAULT = "v1-dev1";
-// TODO: remove before final N build
-static std::string VERSION_DUMPSYS_SPLIT = "v1-dev1-dumpsys-split";
+static std::string VERSION_DEFAULT = "v1-dev2";
 
 /* gets the tombstone data, according to the bugreport type: if zipped gets all tombstones,
  * otherwise gets just those modified in the last half an hour. */
@@ -607,9 +605,8 @@
     run_command("PROCESSES AND THREADS", 10, "ps", "-Z", "-t", "-p", "-P", NULL);
     run_command("LIBRANK", 10, SU_PATH, "root", "librank", NULL);
 
-    run_command("ROUTE", 10, "route", NULL);
     run_command("PRINTENV", 10, "printenv", NULL);
-    run_command("NETSTAT", 10, "netstat", NULL);
+    run_command("NETSTAT", 10, "netstat", "-n", NULL);
     run_command("LSMOD", 10, "lsmod", NULL);
 
     do_dmesg();
@@ -851,12 +848,7 @@
     /* the full dumpsys is starting to take a long time, so we need
        to increase its timeout.  we really need to do the timeouts in
        dumpsys itself... */
-    if (version == VERSION_DUMPSYS_SPLIT) {
-        // Skipping meminfo and cpuinfo services.
-        run_command("DUMPSYS", 60, "dumpsys", "--skip", "meminfo,cpuinfo", NULL);
-    } else {
-        run_command("DUMPSYS", 60, "dumpsys", NULL);
-    }
+    run_command("DUMPSYS", 60, "dumpsys", "--skip", "meminfo,cpuinfo", NULL);
 
     printf("========================================================\n");
     printf("== Checkins\n");
@@ -909,8 +901,8 @@
             "  -B: send broadcast when finished (requires -o)\n"
             "  -P: send broadcast when started and update system properties on progress (requires -o and -B)\n"
             "  -R: take bugreport in remote mode (requires -o, -z, -d and -B, shouldn't be used with -P)\n"
-            "  -V: sets the bugreport format version (%s or %s)\n",
-            VERSION_DEFAULT.c_str(), VERSION_DUMPSYS_SPLIT.c_str());
+            "  -V: sets the bugreport format version (valid values: %s)\n",
+            VERSION_DEFAULT.c_str());
 }
 
 static void sigpipe_handler(int n) {
@@ -1066,7 +1058,9 @@
     }
 
     /* parse arguments */
-    log_args("Dumpstate command line", argc, const_cast<const char **>(argv));
+    std::string args;
+    format_args(argc, const_cast<const char **>(argv), &args);
+    MYLOGD("Dumpstate command line: %s\n", args.c_str());
     int c;
     while ((c = getopt(argc, argv, "dho:svqzpPBRV:")) != -1) {
         switch (c) {
@@ -1103,7 +1097,7 @@
         exit(1);
     }
 
-    if (version != VERSION_DEFAULT && version != VERSION_DUMPSYS_SPLIT) {
+    if (version != VERSION_DEFAULT) {
         usage();
         exit(1);
     }
@@ -1176,8 +1170,8 @@
                 log_path.c_str(), tmp_path.c_str(), screenshot_path.c_str());
 
         if (do_zip_file) {
-            MYLOGD("Creating initial .zip file\n");
             path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
+            MYLOGD("Creating initial .zip file (%s)\n", path.c_str());
             create_parent_dirs(path.c_str());
             zip_file.reset(fopen(path.c_str(), "wb"));
             if (!zip_file) {
@@ -1258,12 +1252,10 @@
     // duration is logged into MYLOG instead.
     print_header(version);
 
-    if (version == VERSION_DUMPSYS_SPLIT) {
-        // Invoking the following dumpsys calls before dump_traces() to try and
-        // keep the system stats as close to its initial state as possible.
-        run_command("DUMPSYS MEMINFO", 30, SU_PATH, "shell", "dumpsys", "meminfo", "-a", NULL);
-        run_command("DUMPSYS CPUINFO", 30, SU_PATH, "shell", "dumpsys", "cpuinfo", "-a", NULL);
-    }
+    // Invoking the following dumpsys calls before dump_traces() to try and
+    // keep the system stats as close to its initial state as possible.
+    run_command("DUMPSYS MEMINFO", 30, SU_PATH, "shell", "dumpsys", "meminfo", "-a", NULL);
+    run_command("DUMPSYS CPUINFO", 30, SU_PATH, "shell", "dumpsys", "cpuinfo", "-a", NULL);
 
     /* collect stack traces from Dalvik and native processes (needs root) */
     dump_traces_path = dump_traces();
@@ -1282,7 +1274,6 @@
     /* close output if needed */
     if (is_redirecting) {
         fclose(stdout);
-        fclose(stderr);
     }
 
     /* rename or zip the (now complete) .tmp file to its final location */
@@ -1391,5 +1382,9 @@
     MYLOGD("Final progress: %d/%d (originally %d)\n", progress, weight_total, WEIGHT_TOTAL);
     MYLOGI("done\n");
 
+    if (is_redirecting) {
+        fclose(stderr);
+    }
+
     return 0;
 }
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 9c975d2..288fe39 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -171,8 +171,8 @@
 /* dump eMMC Extended CSD data */
 void dump_emmc_ecsd(const char *ext_csd_path);
 
-/** logs command-line arguments */
-void log_args(const std::string& message, int argc, const char *argv[]);
+/** gets command-line arguments */
+void format_args(int argc, const char *argv[], std::string *args);
 
 /*
  * Helper class used to report how long it takes for a section to finish.
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index f0ae325..d21ef7b 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -394,7 +394,7 @@
 
     sprintf(title, "SHOW MAP %d (%s)", pid, name);
     sprintf(arg, "%d", pid);
-    run_command(title, 10, SU_PATH, "root", "showmap", arg, NULL);
+    run_command(title, 10, SU_PATH, "root", "showmap", "-q", arg, NULL);
 }
 
 static int _dump_file_from_fd(const char *title, const char *path, int fd) {
@@ -501,7 +501,7 @@
     dirp = opendir(dir);
     if (dirp == NULL) {
         retval = -errno;
-        fprintf(stderr, "%s: %s\n", dir, strerror(errno));
+        MYLOGE("%s: %s\n", dir, strerror(errno));
         return retval;
     }
 
@@ -607,6 +607,9 @@
     return true;
 }
 
+// TODO: refactor all those commands that convert args
+void format_args(const char* command, const char *args[], std::string *string);
+
 int run_command(const char *title, int timeout_seconds, const char *command, ...) {
     DurationReporter duration_reporter(title);
     fflush(stdout);
@@ -616,13 +619,24 @@
     va_list ap;
     va_start(ap, command);
     if (title) printf("------ %s (%s", title, command);
+    bool null_terminated = false;
     for (arg = 1; arg < sizeof(args) / sizeof(args[0]); ++arg) {
         args[arg] = va_arg(ap, const char *);
-        if (args[arg] == NULL) break;
+        if (args[arg] == nullptr) {
+            null_terminated = true;
+            break;
+        }
         if (title) printf(" %s", args[arg]);
     }
     if (title) printf(") ------\n");
     fflush(stdout);
+    if (!null_terminated) {
+        // Fail now, otherwise execvp() call on run_command_always() might hang.
+        std::string cmd;
+        format_args(command, args, &cmd);
+        MYLOGE("skipping command %s because its args were not NULL-terminated", cmd.c_str());
+        return -1;
+    }
 
     ON_DRY_RUN({ update_progress(timeout_seconds); va_end(ap); return 0; });
 
@@ -661,31 +675,43 @@
         sigaction(SIGPIPE, &sigact, NULL);
 
         execvp(command, (char**) args);
-        printf("*** exec(%s): %s\n", command, strerror(errno));
-        fflush(stdout);
-        _exit(-1);
+        // execvp's result will be handled after waitpid_with_timeout() below...
+        _exit(-1); // ...but it doesn't hurt to force exit, just in case
     }
 
     /* handle parent case */
     int status;
     bool ret = waitpid_with_timeout(pid, timeout_seconds, &status);
     uint64_t elapsed = DurationReporter::nanotime() - start;
+    std::string cmd; // used to log command and its args
     if (!ret) {
         if (errno == ETIMEDOUT) {
-            printf("*** %s: Timed out after %.3fs (killing pid %d)\n", command,
+            format_args(command, args, &cmd);
+            printf("*** command '%s' timed out after %.3fs (killing pid %d)\n", cmd.c_str(),
+                   (float) elapsed / NANOS_PER_SEC, pid);
+            MYLOGE("command '%s' timed out after %.3fs (killing pid %d)\n", cmd.c_str(),
                    (float) elapsed / NANOS_PER_SEC, pid);
         } else {
-            printf("*** %s: Error after %.4fs (killing pid %d)\n", command,
+            format_args(command, args, &cmd);
+            printf("*** command '%s': Error after %.4fs (killing pid %d)\n", cmd.c_str(),
+                   (float) elapsed / NANOS_PER_SEC, pid);
+            MYLOGE("command '%s': Error after %.4fs (killing pid %d)\n", cmd.c_str(),
                    (float) elapsed / NANOS_PER_SEC, pid);
         }
         kill(pid, SIGTERM);
         if (!waitpid_with_timeout(pid, 5, NULL)) {
             kill(pid, SIGKILL);
             if (!waitpid_with_timeout(pid, 5, NULL)) {
-                printf("*** %s: Cannot kill %d even with SIGKILL.\n", command, pid);
+                printf("couldn not kill command '%s' (pid %d) even with SIGKILL.\n", command, pid);
+                MYLOGE("couldn not kill command '%s' (pid %d) even with SIGKILL.\n", command, pid);
             }
         }
         return -1;
+    } else if (status) {
+        format_args(command, args, &cmd);
+        printf("*** command '%s' failed: %s\n", cmd.c_str(), strerror(errno));
+        MYLOGE("command '%s' failed: %s\n", cmd.c_str(), strerror(errno));
+        return -2;
     }
 
     if (WIFSIGNALED(status)) {
@@ -702,7 +728,7 @@
 
 void send_broadcast(const std::string& action, const std::vector<std::string>& args) {
     if (args.size() > 1000) {
-        fprintf(stderr, "send_broadcast: too many arguments (%d)\n", (int) args.size());
+        MYLOGE("send_broadcast: too many arguments (%d)\n", (int) args.size());
         return;
     }
     const char *am_args[1024] = { SU_PATH, "shell", "/system/bin/am", "broadcast",
@@ -713,7 +739,9 @@
     }
     // Always terminate with NULL.
     am_args[am_index + 1] = NULL;
-    log_args("send_broadcast arguments", am_index, am_args);
+    std::string args_string;
+    format_args(am_index + 1, am_args, &args_string);
+    MYLOGD("send_broadcast command: %s\n", args_string.c_str());
     run_command_always(NULL, 5, am_args);
 }
 
@@ -755,12 +783,12 @@
 void redirect_to_socket(FILE *redirect, const char *service) {
     int s = android_get_control_socket(service);
     if (s < 0) {
-        fprintf(stderr, "android_get_control_socket(%s): %s\n", service, strerror(errno));
+        MYLOGE("android_get_control_socket(%s): %s\n", service, strerror(errno));
         exit(1);
     }
     fcntl(s, F_SETFD, FD_CLOEXEC);
     if (listen(s, 4) < 0) {
-        fprintf(stderr, "listen(control socket): %s\n", strerror(errno));
+        MYLOGE("listen(control socket): %s\n", strerror(errno));
         exit(1);
     }
 
@@ -768,7 +796,7 @@
     socklen_t alen = sizeof(addr);
     int fd = accept(s, &addr, &alen);
     if (fd < 0) {
-        fprintf(stderr, "accept(control socket): %s\n", strerror(errno));
+        MYLOGE("accept(control socket): %s\n", strerror(errno));
         exit(1);
     }
 
@@ -810,7 +838,7 @@
     int fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
                                      S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
     if (fd < 0) {
-        fprintf(stderr, "%s: %s\n", path, strerror(errno));
+        MYLOGE("%s: %s\n", path, strerror(errno));
         exit(1);
     }
 
@@ -842,7 +870,7 @@
     strlcpy(anr_traces_path, traces_path, sizeof(anr_traces_path));
     strlcat(anr_traces_path, ".anr", sizeof(anr_traces_path));
     if (rename(traces_path, anr_traces_path) && errno != ENOENT) {
-        fprintf(stderr, "rename(%s, %s): %s\n", traces_path, anr_traces_path, strerror(errno));
+        MYLOGE("rename(%s, %s): %s\n", traces_path, anr_traces_path, strerror(errno));
         return NULL;  // Can't rename old traces.txt -- no permission? -- leave it alone instead
     }
 
@@ -850,12 +878,12 @@
     int fd = TEMP_FAILURE_RETRY(open(traces_path, O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW | O_CLOEXEC,
                                      0666));  /* -rw-rw-rw- */
     if (fd < 0) {
-        fprintf(stderr, "%s: %s\n", traces_path, strerror(errno));
+        MYLOGE("%s: %s\n", traces_path, strerror(errno));
         return NULL;
     }
     int chmod_ret = fchmod(fd, 0666);
     if (chmod_ret < 0) {
-        fprintf(stderr, "fchmod on %s failed: %s\n", traces_path, strerror(errno));
+        MYLOGE("fchmod on %s failed: %s\n", traces_path, strerror(errno));
         close(fd);
         return NULL;
     }
@@ -867,20 +895,20 @@
     /* walk /proc and kill -QUIT all Dalvik processes */
     DIR *proc = opendir("/proc");
     if (proc == NULL) {
-        fprintf(stderr, "/proc: %s\n", strerror(errno));
+        MYLOGE("/proc: %s\n", strerror(errno));
         goto error_close_fd;
     }
 
     /* use inotify to find when processes are done dumping */
     ifd = inotify_init();
     if (ifd < 0) {
-        fprintf(stderr, "inotify_init: %s\n", strerror(errno));
+        MYLOGE("inotify_init: %s\n", strerror(errno));
         goto error_close_fd;
     }
 
     wfd = inotify_add_watch(ifd, traces_path, IN_CLOSE_WRITE);
     if (wfd < 0) {
-        fprintf(stderr, "inotify_add_watch(%s): %s\n", traces_path, strerror(errno));
+        MYLOGE("inotify_add_watch(%s): %s\n", traces_path, strerror(errno));
         goto error_close_ifd;
     }
 
@@ -915,7 +943,7 @@
             ++dalvik_found;
             uint64_t start = DurationReporter::nanotime();
             if (kill(pid, SIGQUIT)) {
-                fprintf(stderr, "kill(%d, SIGQUIT): %s\n", pid, strerror(errno));
+                MYLOGE("kill(%d, SIGQUIT): %s\n", pid, strerror(errno));
                 continue;
             }
 
@@ -923,16 +951,16 @@
             struct pollfd pfd = { ifd, POLLIN, 0 };
             int ret = poll(&pfd, 1, 5000);  /* 5 sec timeout */
             if (ret < 0) {
-                fprintf(stderr, "poll: %s\n", strerror(errno));
+                MYLOGE("poll: %s\n", strerror(errno));
             } else if (ret == 0) {
-                fprintf(stderr, "warning: timed out dumping pid %d\n", pid);
+                MYLOGE("warning: timed out dumping pid %d\n", pid);
             } else {
                 struct inotify_event ie;
                 read(ifd, &ie, sizeof(ie));
             }
 
             if (lseek(fd, 0, SEEK_END) < 0) {
-                fprintf(stderr, "lseek: %s\n", strerror(errno));
+                MYLOGE("lseek: %s\n", strerror(errno));
             } else {
                 dprintf(fd, "[dump dalvik stack %d: %.3fs elapsed]\n",
                         pid, (float)(DurationReporter::nanotime() - start) / NANOS_PER_SEC);
@@ -940,7 +968,7 @@
         } else if (should_dump_native_traces(data)) {
             /* dump native process if appropriate */
             if (lseek(fd, 0, SEEK_END) < 0) {
-                fprintf(stderr, "lseek: %s\n", strerror(errno));
+                MYLOGE("lseek: %s\n", strerror(errno));
             } else {
                 static uint16_t timeout_failures = 0;
                 uint64_t start = DurationReporter::nanotime();
@@ -961,14 +989,14 @@
     }
 
     if (dalvik_found == 0) {
-        fprintf(stderr, "Warning: no Dalvik processes found to dump stacks\n");
+        MYLOGE("Warning: no Dalvik processes found to dump stacks\n");
     }
 
     static char dump_traces_path[PATH_MAX];
     strlcpy(dump_traces_path, traces_path, sizeof(dump_traces_path));
     strlcat(dump_traces_path, ".bugreport", sizeof(dump_traces_path));
     if (rename(traces_path, dump_traces_path)) {
-        fprintf(stderr, "rename(%s, %s): %s\n", traces_path, dump_traces_path, strerror(errno));
+        MYLOGE("rename(%s, %s): %s\n", traces_path, dump_traces_path, strerror(errno));
         goto error_close_ifd;
     }
     result = dump_traces_path;
@@ -1021,7 +1049,7 @@
     // adjusts max on the fly
     if (progress > weight_total) {
         int new_total = weight_total * 1.2;
-        fprintf(stderr, "Adjusting total weight from %d to %d\n", weight_total, new_total);
+        MYLOGD("Adjusting total weight from %d to %d\n", weight_total, new_total);
         weight_total = new_total;
         sprintf(key, "dumpstate.%d.max", getpid());
         sprintf(value, "%d", weight_total);
@@ -1035,9 +1063,14 @@
     sprintf(key, "dumpstate.%d.progress", getpid());
     sprintf(value, "%d", progress);
 
-    // stderr is ignored on normal invocations, but useful when calling /system/bin/dumpstate
-    // directly for debuggging.
-    fprintf(stderr, "Setting progress (%s): %s/%d\n", key, value, weight_total);
+    if (progress % 100 == 0) {
+        // We don't want to spam logcat, so only log multiples of 100.
+        MYLOGD("Setting progress (%s): %s/%d\n", key, value, weight_total);
+    } else {
+        // stderr is ignored on normal invocations, but useful when calling /system/bin/dumpstate
+        // directly for debuggging.
+        fprintf(stderr, "Setting progress (%s): %s/%d\n", key, value, weight_total);
+    }
 
     int status = property_set(key, value);
     if (status) {
@@ -1189,11 +1222,28 @@
     printf("\n");
 }
 
-void log_args(const std::string& message, int argc, const char *argv[]) {
-    std::string args;
+// TODO: refactor all those commands that convert args
+void format_args(int argc, const char *argv[], std::string *args) {
+    LOG_ALWAYS_FATAL_IF(args == nullptr);
     for (int i = 0; i < argc; i++) {
-        args.append(argv[i]);
-        args.append(" ");
+        args->append(argv[i]);
+        if (i < argc -1) {
+          args->append(" ");
+        }
     }
-    MYLOGI("%s: %s\n", message.c_str(), args.c_str());
+}
+void format_args(const char* command, const char *args[], std::string *string) {
+    LOG_ALWAYS_FATAL_IF(args == nullptr || command == nullptr);
+    string->append(command);
+    if (args[0] == nullptr) return;
+    string->append(" ");
+
+    for (int arg = 1; arg <= 1000; ++arg) {
+        if (args[arg] == nullptr) return;
+        string->append(args[arg]);
+        if (args[arg+1] != nullptr) {
+            string->append(" ");
+        }
+    }
+    MYLOGE("internal error: missing NULL entry on %s", string->c_str());
 }
diff --git a/cmds/dumpsys/Android.mk b/cmds/dumpsys/Android.mk
index 9be0901..8335c14 100644
--- a/cmds/dumpsys/Android.mk
+++ b/cmds/dumpsys/Android.mk
@@ -5,10 +5,11 @@
 	dumpsys.cpp
 
 LOCAL_SHARED_LIBRARIES := \
+	libbase \
 	libutils \
 	liblog \
 	libbinder
-	
+
 
 ifeq ($(TARGET_OS),linux)
 	LOCAL_CFLAGS += -DXP_UNIX
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index ef009da..003fcc3 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -5,21 +5,33 @@
 
 #define LOG_TAG "dumpsys"
 
-#include <utils/Log.h>
+#include <algorithm>
+#include <chrono>
+#include <thread>
+
+#include <android-base/file.h>
+#include <android-base/unique_fd.h>
+#include <binder/IServiceManager.h>
 #include <binder/Parcel.h>
 #include <binder/ProcessState.h>
-#include <binder/IServiceManager.h>
 #include <binder/TextOutput.h>
+#include <utils/Log.h>
 #include <utils/Vector.h>
 
+#include <fcntl.h>
 #include <getopt.h>
-#include <stdlib.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
 #include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 using namespace android;
+using android::base::unique_fd;
+using android::base::WriteFully;
 
 static int sort_func(const String16* lhs, const String16* rhs)
 {
@@ -121,23 +133,107 @@
         return 0;
     }
 
-    for (size_t i=0; i<N; i++) {
-        if (IsSkipped(skippedServices, services[i])) continue;
+    for (size_t i = 0; i < N; i++) {
+        String16 service_name = std::move(services[i]);
+        if (IsSkipped(skippedServices, service_name)) continue;
 
-        sp<IBinder> service = sm->checkService(services[i]);
+        sp<IBinder> service = sm->checkService(service_name);
         if (service != NULL) {
+            int sfd[2];
+
+            if (pipe(sfd) != 0) {
+                aerr << "Failed to create pipe to dump service info for " << service_name
+                     << ": " << strerror(errno) << endl;
+                continue;
+            }
+
+            unique_fd local_end(sfd[0]);
+            unique_fd remote_end(sfd[1]);
+            sfd[0] = sfd[1] = -1;
+
             if (N > 1) {
                 aout << "------------------------------------------------------------"
                         "-------------------" << endl;
-                aout << "DUMP OF SERVICE " << services[i] << ":" << endl;
+                aout << "DUMP OF SERVICE " << service_name << ":" << endl;
             }
-            int err = service->dump(STDOUT_FILENO, args);
-            if (err != 0) {
-                aerr << "Error dumping service info: (" << strerror(err)
-                        << ") " << services[i] << endl;
+
+            // dump blocks until completion, so spawn a thread..
+            std::thread dump_thread([=, remote_end { std::move(remote_end) }]() mutable {
+                int err = service->dump(remote_end.get(), args);
+
+                // It'd be nice to be able to close the remote end of the socketpair before the dump
+                // call returns, to terminate our reads if the other end closes their copy of the
+                // file descriptor, but then hangs for some reason. There doesn't seem to be a good
+                // way to do this, though.
+                remote_end.clear();
+
+                if (err != 0) {
+                    aerr << "Error dumping service info: (" << strerror(err) << ") " << service_name
+                         << endl;
+                }
+            });
+
+            // TODO: Make this configurable at runtime.
+            constexpr auto timeout = std::chrono::seconds(10);
+            auto end = std::chrono::steady_clock::now() + timeout;
+
+            struct pollfd pfd = {
+                .fd = local_end.get(),
+                .events = POLLIN
+            };
+
+            bool timed_out = false;
+            bool error = false;
+            while (true) {
+                // Wrap this in a lambda so that TEMP_FAILURE_RETRY recalculates the timeout.
+                auto time_left_ms = [end]() {
+                    auto now = std::chrono::steady_clock::now();
+                    auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
+                    return std::max(diff.count(), 0ll);
+                };
+
+                int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
+                if (rc < 0) {
+                    aerr << "Error in poll while dumping service " << service_name << " : "
+                         << strerror(errno) << endl;
+                    error = true;
+                    break;
+                } else if (rc == 0) {
+                    timed_out = true;
+                    break;
+                }
+
+                char buf[4096];
+                rc = TEMP_FAILURE_RETRY(read(local_end.get(), buf, sizeof(buf)));
+                if (rc < 0) {
+                    aerr << "Failed to read while dumping service " << service_name << ": "
+                         << strerror(errno) << endl;
+                    error = true;
+                    break;
+                } else if (rc == 0) {
+                    // EOF.
+                    break;
+                }
+
+                if (!WriteFully(STDOUT_FILENO, buf, rc)) {
+                    aerr << "Failed to write while dumping service " << service_name << ": "
+                         << strerror(errno) << endl;
+                    error = true;
+                    break;
+                }
+            }
+
+            if (timed_out) {
+                aout << endl << "*** SERVICE DUMP TIMEOUT EXPIRED ***" << endl << endl;
+            }
+
+            if (timed_out || error) {
+                dump_thread.detach();
+            } else {
+                dump_thread.join();
             }
         } else {
-            aerr << "Can't find service: " << services[i] << endl;
+            aerr << "Can't find service: " << service_name << endl;
         }
     }
 
diff --git a/cmds/installd/Android.mk b/cmds/installd/Android.mk
index 65bcf39..d35099a 100644
--- a/cmds/installd/Android.mk
+++ b/cmds/installd/Android.mk
@@ -80,6 +80,36 @@
 LOCAL_CLANG := true
 include $(BUILD_EXECUTABLE)
 
+# OTA chroot tool
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := otapreopt_chroot
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := $(common_cflags)
+
+LOCAL_SRC_FILES := otapreopt_chroot.cpp
+LOCAL_SHARED_LIBRARIES := \
+    libbase \
+    liblog \
+
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+LOCAL_CLANG := true
+include $(BUILD_EXECUTABLE)
+
+# OTA postinstall script
+
+include $(CLEAR_VARS)
+LOCAL_MODULE:= otapreopt_script
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_SRC_FILES := otapreopt_script.sh
+
+# Let this depend on otapreopt and the chroot tool, so we just have to mention one in a
+# configuration.
+LOCAL_REQUIRED_MODULES := otapreopt otapreopt_chroot
+
+include $(BUILD_PREBUILT)
+
 # Tests.
 
 include $(LOCAL_PATH)/tests/Android.mk
\ No newline at end of file
diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp
index e31c6e2..77bcfc2 100644
--- a/cmds/installd/commands.cpp
+++ b/cmds/installd/commands.cpp
@@ -161,28 +161,39 @@
     return StringPrintf("%s/%s", profile_dir.c_str(), PRIMARY_PROFILE_NAME);
 }
 
-static void unlink_reference_profile(const char* pkgname) {
+static bool unlink_reference_profile(const char* pkgname) {
     std::string reference_profile_dir = create_data_ref_profile_package_path(pkgname);
     std::string reference_profile = create_primary_profile(reference_profile_dir);
     if (unlink(reference_profile.c_str()) != 0) {
-        PLOG(WARNING) << "Could not unlink " << reference_profile;
+        if (errno != ENOENT) {
+            PLOG(WARNING) << "Could not unlink " << reference_profile;
+            return false;
+        }
     }
+    return true;
 }
 
-static void unlink_current_profiles(const char* pkgname) {
+static bool unlink_current_profiles(const char* pkgname) {
+    bool success = true;
     std::vector<userid_t> users = get_known_users(/*volume_uuid*/ nullptr);
     for (auto user : users) {
         std::string profile_dir = create_data_user_profile_package_path(user, pkgname);
         std::string profile = create_primary_profile(profile_dir);
         if (unlink(profile.c_str()) != 0) {
-            PLOG(WARNING) << "Could not unlink " << profile;
+            if (errno != ENOENT) {
+                PLOG(WARNING) << "Could not unlink " << profile;
+                success = false;
+            }
         }
     }
+    return success;
 }
 
-static void unlink_all_profiles(const char* pkgname) {
-    unlink_reference_profile(pkgname);
-    unlink_current_profiles(pkgname);
+static bool unlink_all_profiles(const char* pkgname) {
+    bool success = true;
+    success &= unlink_reference_profile(pkgname);
+    success &= unlink_current_profiles(pkgname);
+    return success;
 }
 
 int clear_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags) {
@@ -815,7 +826,9 @@
         strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=interpret-only");
         have_dex2oat_compiler_filter_flag = true;
     } else if (extract_only) {
-        strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=verify-at-runtime");
+        // Temporarily make extract-only mean interpret-only, so extracted files will be verified.
+        // b/26833007
+        strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=interpret-only");
         have_dex2oat_compiler_filter_flag = true;
     } else if (have_dex2oat_compiler_filter_flag) {
         sprintf(dex2oat_compiler_filter_arg, "--compiler-filter=%s", dex2oat_compiler_filter_flag);
@@ -1276,12 +1289,20 @@
     char in_odex_path[PKG_PATH_MAX];
     int res;
     fd_t input_fd=-1, out_fd=-1, image_fd=-1, swap_fd=-1;
-    bool is_public = (dexopt_flags & DEXOPT_PUBLIC) != 0;
+    bool is_public = ((dexopt_flags & DEXOPT_PUBLIC) != 0);
     bool vm_safe_mode = (dexopt_flags & DEXOPT_SAFEMODE) != 0;
     bool debuggable = (dexopt_flags & DEXOPT_DEBUGGABLE) != 0;
     bool boot_complete = (dexopt_flags & DEXOPT_BOOTCOMPLETE) != 0;
     bool extract_only = (dexopt_flags & DEXOPT_EXTRACTONLY) != 0;
     fd_t reference_profile_fd = -1;
+
+    if (is_public && use_profiles) {
+        // We should not give public access to apks compiled with profile information.
+        // Log an error and return early if are asked to do so.
+        ALOGE("use_profiles should not be used with is_public.");
+        return -1;
+    }
+
     if (use_profiles) {
         if (analyse_profiles(uid, pkgname)) {
             // Open again reference profile in read only mode as dex2oat does not get write
@@ -1749,6 +1770,11 @@
     return delete_dir_contents(apk_path, 1 /* also_delete_dir */ , NULL /* exclusion_predicate */);
 }
 
+int rm_profiles(const char* pkgname)
+{
+    return unlink_all_profiles(pkgname) ? 0 : -1;
+}
+
 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];
@@ -1774,5 +1800,84 @@
     return 0;
 }
 
+// Helper for move_ab, so that we can have common failure-case cleanup.
+static bool unlink_and_rename(const char* from, const char* to) {
+    // Check whether "from" exists, and if so whether it's regular. If it is, unlink. Otherwise,
+    // return a failure.
+    struct stat s;
+    if (stat(to, &s) == 0) {
+        if (!S_ISREG(s.st_mode)) {
+            LOG(ERROR) << from << " is not a regular file to replace for A/B.";
+            return false;
+        }
+        if (unlink(to) != 0) {
+            LOG(ERROR) << "Could not unlink " << to << " to move A/B.";
+            return false;
+        }
+    } else {
+        // This may be a permission problem. We could investigate the error code, but we'll just
+        // let the rename failure do the work for us.
+    }
+
+    // Try to rename "to" to "from."
+    if (rename(from, to) != 0) {
+        PLOG(ERROR) << "Could not rename " << from << " to " << to;
+        return false;
+    }
+
+    return true;
+}
+
+int move_ab(const char* apk_path, const char* instruction_set, const char* oat_dir) {
+    if (apk_path == nullptr || instruction_set == nullptr || oat_dir == nullptr) {
+        LOG(ERROR) << "Cannot move_ab with null input";
+        return -1;
+    }
+    if (validate_apk_path(apk_path) != 0) {
+        LOG(ERROR) << "invalid apk_path " << apk_path;
+        return -1;
+    }
+    if (validate_apk_path(oat_dir) != 0) {
+        LOG(ERROR) << "invalid oat_dir " << oat_dir;
+        return -1;
+    }
+
+    char a_path[PKG_PATH_MAX];
+    if (!calculate_oat_file_path(a_path, oat_dir, apk_path, instruction_set)) {
+        return -1;
+    }
+
+    // B path = A path + ".b"
+    std::string b_path = StringPrintf("%s.b", a_path);
+
+    // Check whether B exists.
+    {
+        struct stat s;
+        if (stat(b_path.c_str(), &s) != 0) {
+            // Silently ignore for now. The service calling this isn't smart enough to understand
+            // lack of artifacts at the moment.
+            return -1;
+        }
+        if (!S_ISREG(s.st_mode)) {
+            LOG(ERROR) << "A/B artifact " << b_path << " is not a regular file.";
+            // Try to unlink, but swallow errors.
+            unlink(b_path.c_str());
+            return -1;
+        }
+    }
+
+    // Rename B to A.
+    if (!unlink_and_rename(b_path.c_str(), a_path)) {
+        // Delete the b_path so we don't try again (or fail earlier).
+        if (unlink(b_path.c_str()) != 0) {
+            PLOG(ERROR) << "Could not unlink " << b_path;
+        }
+
+        return -1;
+    }
+
+    return 0;
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/commands.h b/cmds/installd/commands.h
index fe03397..b473e3e 100644
--- a/cmds/installd/commands.h
+++ b/cmds/installd/commands.h
@@ -56,8 +56,12 @@
 int idmap(const char *target_path, const char *overlay_path, uid_t uid);
 int create_oat_dir(const char* oat_dir, const char *instruction_set);
 int rm_package_dir(const char* apk_path);
+int rm_profiles(const char* pkgname);
 int link_file(const char *relative_path, const char *from_base, const char *to_base);
 
+// Move a B version over to the A location. Only works for oat_dir != nullptr.
+int move_ab(const char *apk_path, const char *instruction_set, const char* oat_dir);
+
 }  // namespace installd
 }  // namespace android
 
diff --git a/cmds/installd/file_parsing.h b/cmds/installd/file_parsing.h
new file mode 100644
index 0000000..3e2f815
--- /dev/null
+++ b/cmds/installd/file_parsing.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OTAPREOPT_FILE_PARSING_H_
+#define OTAPREOPT_FILE_PARSING_H_
+
+#include <fstream>
+#include <functional>
+#include <string>
+
+namespace android {
+namespace installd {
+
+bool ParseFile(const std::string& strFile, std::function<bool (const std::string&)> parse) {
+    std::ifstream input_stream(strFile);
+
+    if (!input_stream.is_open()) {
+        return false;
+    }
+
+    while (!input_stream.eof()) {
+        // Read the next line.
+        std::string line;
+        getline(input_stream, line);
+
+        // Is the line empty? Simplifies the next check.
+        if (line.empty()) {
+            continue;
+        }
+
+        // Is this a comment (starts with pound)?
+        if (line[0] == '#') {
+            continue;
+        }
+
+        if (!parse(line)) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+}  // namespace installd
+}  // namespace android
+
+#endif  // OTAPREOPT_FILE_PARSING_H_
diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp
index 63290a9..2bf27a2 100644
--- a/cmds/installd/installd.cpp
+++ b/cmds/installd/installd.cpp
@@ -128,13 +128,13 @@
 bool create_cache_path(char path[PKG_PATH_MAX],
                        const char *src,
                        const char *instruction_set) {
-    size_t srclen = strlen(src);
-
-        /* demand that we are an absolute path */
-    if ((src == 0) || (src[0] != '/') || strstr(src,"..")) {
+    /* demand that we are an absolute path */
+    if ((src == nullptr) || (src[0] != '/') || strstr(src,"..")) {
         return false;
     }
 
+    size_t srclen = strlen(src);
+
     if (srclen > PKG_PATH_MAX) {        // XXX: PKG_NAME_MAX?
         return false;
     }
@@ -216,29 +216,40 @@
     return destroy_app_data(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]));
 }
 
-static int do_ota_dexopt(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
-  // Time to fork and run otapreopt.
-  pid_t pid = fork();
-  if (pid == 0) {
-    const char* argv[1 + 9 + 1];
-    argv[0] = "/system/bin/otapreopt";
-    for (size_t i = 1; i <= 9; ++i) {
-      argv[i] = arg[i - 1];
-    }
-    argv[10] = nullptr;
+// We use otapreopt_chroot to get into the chroot.
+static constexpr const char* kOtaPreopt = "/system/bin/otapreopt_chroot";
 
-    execv(argv[0], (char * const *)argv);
-    ALOGE("execv(OTAPREOPT) failed: %s\n", strerror(errno));
-    exit(99);
-  } else {
-    int res = wait_child(pid);
-    if (res == 0) {
-      ALOGV("DexInv: --- END OTAPREOPT (success) ---\n");
-    } else {
-      ALOGE("DexInv: --- END OTAPREOPT --- status=0x%04x, process failed\n", res);
+static int do_ota_dexopt(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
+    // Time to fork and run otapreopt.
+
+    // Check that the tool exists.
+    struct stat s;
+    if (stat(kOtaPreopt, &s) != 0) {
+        LOG(ERROR) << "Otapreopt chroot tool not found.";
+        return -1;
     }
-    return res;
-  }
+
+    pid_t pid = fork();
+    if (pid == 0) {
+        const char* argv[1 + 9 + 1];
+        argv[0] = kOtaPreopt;
+        for (size_t i = 1; i <= 9; ++i) {
+            argv[i] = arg[i - 1];
+        }
+        argv[10] = nullptr;
+
+        execv(argv[0], (char * const *)argv);
+        PLOG(ERROR) << "execv(OTAPREOPT_CHROOT) failed";
+        exit(99);
+    } else {
+        int res = wait_child(pid);
+        if (res == 0) {
+            ALOGV("DexInv: --- END OTAPREOPT (success) ---\n");
+        } else {
+            ALOGE("DexInv: --- END OTAPREOPT --- status=0x%04x, process failed\n", res);
+        }
+        return res;
+    }
 }
 
 static int do_dexopt(char **arg, char reply[REPLY_MAX])
@@ -330,12 +341,23 @@
     return rm_package_dir(arg[0]);
 }
 
+static int do_rm_profiles(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED)
+{
+    /* package_name */
+    return rm_profiles(arg[0]);
+}
+
 static int do_link_file(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED)
 {
     /* relative_path, from_base, to_base */
     return link_file(arg[0], arg[1], arg[2]);
 }
 
+static int do_move_ab(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
+    // apk_path, instruction_set, oat_dir
+    return move_ab(arg[0], arg[1], arg[2]);
+}
+
 struct cmdinfo {
     const char *name;
     unsigned numargs;
@@ -363,7 +385,9 @@
     { "idmap",                3, do_idmap },
     { "createoatdir",         2, do_create_oat_dir },
     { "rmpackagedir",         1, do_rm_package_dir },
+    { "rmprofiles",           1, do_rm_profiles },
     { "linkfile",             3, do_link_file },
+    { "move_ab",              3, do_move_ab },
 };
 
 static int readx(int s, void *_buf, int count)
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 3aac48b..89a4225 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -17,6 +17,7 @@
 #include <algorithm>
 #include <inttypes.h>
 #include <random>
+#include <regex>
 #include <selinux/android.h>
 #include <selinux/avc.h>
 #include <stdlib.h>
@@ -35,6 +36,7 @@
 #include <private/android_filesystem_config.h>
 
 #include <commands.h>
+#include <file_parsing.h>
 #include <globals.h>
 #include <installd_deps.h>  // Need to fill in requirements of commands.
 #include <string_helpers.h>
@@ -54,8 +56,8 @@
 namespace android {
 namespace installd {
 
-static constexpr const char* kBootClassPathPropertyName = "env.BOOTCLASSPATH";
-static constexpr const char* kAndroidRootPathPropertyName = "env.ANDROID_ROOT";
+static constexpr const char* kBootClassPathPropertyName = "BOOTCLASSPATH";
+static constexpr const char* kAndroidRootPathPropertyName = "ANDROID_ROOT";
 static constexpr const char* kOTARootDirectory = "/system-b";
 static constexpr size_t kISAIndex = 3;
 
@@ -131,41 +133,55 @@
 
 private:
     bool ReadSystemProperties() {
-        // TODO(agampe): What to do about the things in default.prop? It's only heap sizes, so it's easy
-        //               to emulate for now, but has issues (e.g., vendors modifying the boot classpath
-        //               may require larger values here - revisit). That's why this goes first, so that
-        //               if those dummy values are overridden in build.prop, that's what we'll get.
-        //
-        // Note: It seems we'll get access to the B root partition, so we should read the default.prop
-        //       file.
-        // if (!system_properties_.Load(b_mount_path_ + "/default.prop") {
-        //   return false;
-        // }
-        system_properties_.SetProperty("dalvik.vm.image-dex2oat-Xms", "64m");
-        system_properties_.SetProperty("dalvik.vm.image-dex2oat-Xmx", "64m");
-        system_properties_.SetProperty("dalvik.vm.dex2oat-Xms", "64m");
-        system_properties_.SetProperty("dalvik.vm.dex2oat-Xmx", "512m");
+        static constexpr const char* kPropertyFiles[] = {
+                "/default.prop", "/system/build.prop"
+        };
 
-        // TODO(agampe): Do this properly/test.
-        return system_properties_.Load(b_mount_path_ + "/system/build.prop");
+        for (size_t i = 0; i < arraysize(kPropertyFiles); ++i) {
+            if (!system_properties_.Load(kPropertyFiles[i])) {
+                return false;
+            }
+        }
+
+        return true;
     }
 
     bool ReadEnvironment() {
-        // Read important environment variables. For simplicity, store them as
-        // system properties.
-        // TODO(agampe): We'll have to parse init.environ.rc for BOOTCLASSPATH.
-        //               For now, just the A version.
-        const char* boot_classpath = getenv("BOOTCLASSPATH");
-        if (boot_classpath == nullptr) {
-            return false;
-        }
-        system_properties_.SetProperty(kBootClassPathPropertyName, boot_classpath);
+        // Parse the environment variables from init.environ.rc, which have the form
+        //   export NAME VALUE
+        // For simplicity, don't respect string quotation. The values we are interested in can be
+        // encoded without them.
+        std::regex export_regex("\\s*export\\s+(\\S+)\\s+(\\S+)");
+        bool parse_result = ParseFile("/init.environ.rc", [&](const std::string& line) {
+            std::smatch export_match;
+            if (!std::regex_match(line, export_match, export_regex)) {
+                return true;
+            }
 
-        const char* root_path = getenv("ANDROID_ROOT");
-        if (root_path == nullptr) {
+            if (export_match.size() != 3) {
+                return true;
+            }
+
+            std::string name = export_match[1].str();
+            std::string value = export_match[2].str();
+
+            system_properties_.SetProperty(name, value);
+
+            return true;
+        });
+        if (!parse_result) {
             return false;
         }
-        system_properties_.SetProperty(kAndroidRootPathPropertyName, b_mount_path_ + root_path);
+
+        // Check that we found important properties.
+        constexpr const char* kRequiredProperties[] = {
+                kBootClassPathPropertyName, kAndroidRootPathPropertyName
+        };
+        for (size_t i = 0; i < arraysize(kRequiredProperties); ++i) {
+            if (system_properties_.GetProperty(kRequiredProperties[i]) == nullptr) {
+                return false;
+            }
+        }
 
         return true;
     }
@@ -239,9 +255,7 @@
         // TODO: Delete files, just for a blank slate.
         const std::string& boot_cp = *system_properties_.GetProperty(kBootClassPathPropertyName);
 
-        std::string preopted_boot_art_path = StringPrintf("%s/system/framework/%s/boot.art",
-                                                          b_mount_path_.c_str(),
-                                                          isa);
+        std::string preopted_boot_art_path = StringPrintf("/system/framework/%s/boot.art", isa);
         if (access(preopted_boot_art_path.c_str(), F_OK) == 0) {
           return PatchoatBootImage(art_path, isa);
         } else {
@@ -254,7 +268,7 @@
         // This needs to be kept in sync with ART, see art/runtime/gc/space/image_space.cc.
 
         std::vector<std::string> cmd;
-        cmd.push_back(b_mount_path_ + "/system/bin/patchoat");
+        cmd.push_back("/system/bin/patchoat");
 
         cmd.push_back("--input-image-location=/system/framework/boot.art");
         cmd.push_back(StringPrintf("--output-image-file=%s", art_path.c_str()));
@@ -279,7 +293,7 @@
                           const char* isa) {
         // This needs to be kept in sync with ART, see art/runtime/gc/space/image_space.cc.
         std::vector<std::string> cmd;
-        cmd.push_back(b_mount_path_ + "/system/bin/dex2oat");
+        cmd.push_back("/system/bin/dex2oat");
         cmd.push_back(StringPrintf("--image=%s", art_path.c_str()));
         for (const std::string& boot_part : Split(boot_cp, ':')) {
             cmd.push_back(StringPrintf("--dex-file=%s", boot_part.c_str()));
@@ -305,8 +319,7 @@
                 "--compiler-filter=",
                 false,
                 cmd);
-        cmd.push_back(StringPrintf("--image-classes=%s/system/etc/preloaded-classes",
-                                   b_mount_path_.c_str()));
+        cmd.push_back("--image-classes=/system/etc/preloaded-classes");
         // TODO: Compiled-classes.
         const std::string* extra_opts =
                 system_properties_.GetProperty("dalvik.vm.image-dex2oat-flags");
@@ -468,10 +481,6 @@
         }
     }
 
-    // The path where the B partitions are mounted.
-    // TODO(agampe): If we're running this *inside* the change-root, we wouldn't need this.
-    std::string b_mount_path_;
-
     // Stores the system properties read out of the B partition. We need to use these properties
     // to compile, instead of the A properties we could get from init/get_property.
     SystemProperties system_properties_;
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
new file mode 100644
index 0000000..f7f69a9
--- /dev/null
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -0,0 +1,99 @@
+/*
+ ** Copyright 2016, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#include <linux/unistd.h>
+#include <sys/mount.h>
+#include <sys/wait.h>
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <android-base/stringprintf.h>
+
+#ifndef LOG_TAG
+#define LOG_TAG "otapreopt"
+#endif
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace installd {
+
+static int otapreopt_chroot(const int argc, char **arg) {
+    // We need to run the otapreopt tool from the postinstall partition. As such, set up a
+    // mount namespace and change root.
+
+    // Create our own mount namespace.
+    if (unshare(CLONE_NEWNS) != 0) {
+        PLOG(ERROR) << "Failed to unshare() for otapreopt.";
+        exit(200);
+    }
+
+    // Make postinstall private, so that our changes don't propagate.
+    if (mount("", "/postinstall", nullptr, MS_PRIVATE, nullptr) != 0) {
+        PLOG(ERROR) << "Failed to mount private.";
+        exit(201);
+    }
+
+    // Bind mount necessary directories.
+    constexpr const char* kBindMounts[] = {
+            "/data", "/dev", "/proc", "/sys"
+    };
+    for (size_t i = 0; i < arraysize(kBindMounts); ++i) {
+        std::string trg = StringPrintf("/postinstall%s", kBindMounts[i]);
+        if (mount(kBindMounts[i], trg.c_str(), nullptr, MS_BIND, nullptr) != 0) {
+            PLOG(ERROR) << "Failed to bind-mount " << kBindMounts[i];
+            exit(202);
+        }
+    }
+
+    // Chdir into /postinstall.
+    if (chdir("/postinstall") != 0) {
+        PLOG(ERROR) << "Unable to chdir into /postinstall.";
+        exit(203);
+    }
+
+    // Make /postinstall the root in our mount namespace.
+    if (chroot(".")  != 0) {
+        PLOG(ERROR) << "Failed to chroot";
+        exit(204);
+    }
+
+    if (chdir("/") != 0) {
+        PLOG(ERROR) << "Unable to chdir into /.";
+        exit(205);
+    }
+
+    // Now go on and run otapreopt.
+
+    const char* argv[1 + 9 + 1];
+    CHECK_EQ(argc, 10);
+    argv[0] = "/system/bin/otapreopt";
+    for (size_t i = 1; i <= 9; ++i) {
+        argv[i] = arg[i];
+    }
+    argv[10] = nullptr;
+
+    execv(argv[0], (char * const *)argv);
+    PLOG(ERROR) << "execv(OTAPREOPT) failed.";
+    exit(99);
+}
+
+}  // namespace installd
+}  // namespace android
+
+int main(const int argc, char *argv[]) {
+    return android::installd::otapreopt_chroot(argc, argv);
+}
diff --git a/cmds/installd/otapreopt_script.sh b/cmds/installd/otapreopt_script.sh
new file mode 100644
index 0000000..a31734a
--- /dev/null
+++ b/cmds/installd/otapreopt_script.sh
@@ -0,0 +1,50 @@
+#!/system/bin/sh
+
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# This script will run as a postinstall step to drive otapreopt.
+
+# Maximum number of packages/steps.
+MAXIMUM_PACKAGES=1000
+
+PREPARE=$(cmd otadexopt prepare)
+if [ "$PREPARE" != "Success" ] ; then
+  echo "Failed to prepare."
+  exit 1
+fi
+
+i=0
+while ((i<MAXIMUM_PACKAGES)) ; do
+  cmd otadexopt step
+  DONE=$(cmd otadexopt done)
+  if [ "$DONE" = "OTA complete." ] ; then
+    break
+  fi
+  sleep 1
+  i=$((i+1))
+done
+
+DONE=$(cmd otadexopt done)
+if [ "$DONE" = "OTA incomplete." ] ; then
+  echo "Incomplete."
+else
+  echo "Complete or error."
+fi
+
+cmd otadexopt cleanup
+
+exit 0
diff --git a/cmds/installd/system_properties.h b/cmds/installd/system_properties.h
index 1b5fb3a..2d940a3 100644
--- a/cmds/installd/system_properties.h
+++ b/cmds/installd/system_properties.h
@@ -21,6 +21,8 @@
 #include <string>
 #include <unordered_map>
 
+#include <file_parsing.h>
+
 namespace android {
 namespace installd {
 
@@ -28,31 +30,11 @@
 class SystemProperties {
  public:
     bool Load(const std::string& strFile) {
-        std::ifstream input_stream(strFile);
-
-        if (!input_stream.is_open()) {
-            return false;
-        }
-
-        while (!input_stream.eof()) {
-            // Read the next line.
-            std::string line;
-            getline(input_stream, line);
-
-            // Is the line empty? Simplifies the next check.
-            if (line.empty()) {
-                continue;
-            }
-
-            // Is this a comment (starts with pound)?
-            if (line[0] == '#') {
-                continue;
-            }
-
+        return ParseFile(strFile, [&](const std::string& line) {
             size_t equals_pos = line.find('=');
             if (equals_pos == std::string::npos || equals_pos == 0) {
                 // Did not find equals sign, or it's the first character - isn't a valid line.
-                continue;
+                return true;
             }
 
             std::string key = line.substr(0, equals_pos);
@@ -60,9 +42,9 @@
                                             line.length() - equals_pos + 1);
 
             properties_.insert(std::make_pair(key, value));
-        }
 
-        return true;
+            return true;
+        });
     }
 
     // Look up the key in the map. Returns null if the key isn't mapped.
diff --git a/cmds/servicemanager/binder.c b/cmds/servicemanager/binder.c
index 9e99085..01218c9 100644
--- a/cmds/servicemanager/binder.c
+++ b/cmds/servicemanager/binder.c
@@ -167,20 +167,27 @@
     return res;
 }
 
-void binder_send_reply(struct binder_state *bs,
-                       struct binder_io *reply,
-                       binder_uintptr_t buffer_to_free,
-                       int status)
+void binder_free_buffer(struct binder_state *bs,
+                        binder_uintptr_t buffer_to_free)
 {
     struct {
         uint32_t cmd_free;
         binder_uintptr_t buffer;
+    } __attribute__((packed)) data;
+    data.cmd_free = BC_FREE_BUFFER;
+    data.buffer = buffer_to_free;
+    binder_write(bs, &data, sizeof(data));
+}
+
+void binder_send_reply(struct binder_state *bs,
+                       struct binder_io *reply,
+                       int status)
+{
+    struct {
         uint32_t cmd_reply;
         struct binder_transaction_data txn;
     } __attribute__((packed)) data;
 
-    data.cmd_free = BC_FREE_BUFFER;
-    data.buffer = buffer_to_free;
     data.cmd_reply = BC_REPLY;
     data.txn.target.ptr = 0;
     data.txn.cookie = 0;
@@ -243,7 +250,9 @@
                 bio_init(&reply, rdata, sizeof(rdata), 4);
                 bio_init_from_txn(&msg, txn);
                 res = func(bs, txn, &msg, &reply);
-                binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
+                binder_free_buffer(bs, txn->data.ptr.buffer);
+                if ((txn->flags & TF_ONE_WAY) == 0)
+                    binder_send_reply(bs, &reply, res);
             }
             ptr += sizeof(*txn);
             break;
diff --git a/include/android/sensor.h b/include/android/sensor.h
index f2647be..5a61213 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -393,6 +393,13 @@
 /*****************************************************************************/
 
 /**
+ * Enable the selected sensor with a specified sampling period and max batch report latency.
+ * Returns a negative error code on failure.
+ */
+int ASensorEventQueue_registerSensor(ASensorEventQueue* queue, ASensor const* sensor,
+        int32_t samplingPeriodUs, int maxBatchReportLatencyUs);
+
+/**
  * Enable the selected sensor. Returns a negative error code on failure.
  */
 int ASensorEventQueue_enableSensor(ASensorEventQueue* queue, ASensor const* sensor);
diff --git a/include/binder/MemoryDealer.h b/include/binder/MemoryDealer.h
index aa415d5..60a624c 100644
--- a/include/binder/MemoryDealer.h
+++ b/include/binder/MemoryDealer.h
@@ -41,6 +41,9 @@
     virtual void        deallocate(size_t offset);
     virtual void        dump(const char* what) const;
 
+    // allocations are aligned to some value. return that value so clients can account for it.
+    static size_t      getAllocationAlignment();
+
     sp<IMemoryHeap> getMemoryHeap() const { return heap(); }
 
 protected:
diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
index 2645d09..1b950ab 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -32,7 +32,6 @@
 
 #include <list>
 #include <set>
-#include <vector>
 
 #define BQ_LOGV(x, ...) ALOGV("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
 #define BQ_LOGD(x, ...) ALOGD("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
@@ -68,8 +67,13 @@
     // consumer can run asynchronously.
     enum { MAX_MAX_ACQUIRED_BUFFERS = BufferQueueDefs::NUM_BUFFER_SLOTS - 2 };
 
-    // The default API number used to indicate that no producer is connected
-    enum { NO_CONNECTED_API = 0 };
+    enum {
+        // The API number used to indicate the currently connected producer
+        CURRENTLY_CONNECTED_API = -1,
+
+        // The API number used to indicate that no producer is connected
+        NO_CONNECTED_API        = 0,
+    };
 
     typedef Vector<BufferItem> Fifo;
 
@@ -121,9 +125,8 @@
     void freeAllBuffersLocked();
 
     // If delta is positive, makes more slots available. If negative, takes
-    // away slots. Returns false if the request can't be met. Any slots that
-    // were freed will be appended to freedSlots.
-    bool adjustAvailableSlotsLocked(int delta, std::vector<int>* freedSlots);
+    // away slots. Returns false if the request can't be met.
+    bool adjustAvailableSlotsLocked(int delta);
 
     // waitWhileAllocatingLocked blocks until mIsAllocating is false.
     void waitWhileAllocatingLocked() const;
@@ -289,9 +292,6 @@
     bool mAsyncMode;
 
     // mSingleBufferMode indicates whether or not single buffer mode is enabled.
-    // In single buffer mode, the last buffer that was dequeued is cached and
-    // returned to all calls to dequeueBuffer and acquireBuffer. This allows the
-    // consumer and producer to access the same buffer simultaneously.
     bool mSingleBufferMode;
 
     // When single buffer mode is enabled, this indicates whether the consumer
diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h
index 1b63552..9307a26 100644
--- a/include/gui/ConsumerBase.h
+++ b/include/gui/ConsumerBase.h
@@ -26,8 +26,6 @@
 #include <utils/threads.h>
 #include <gui/IConsumerListener.h>
 
-#include <queue>
-
 namespace android {
 // ----------------------------------------------------------------------------
 
@@ -110,18 +108,18 @@
     // from the derived class.
     virtual void onLastStrongRef(const void* id);
 
-    // Handlers for the IConsumerListener interface, these will be called from
-    // the message queue thread. These calls are used to notify the ConsumerBase
-    // of asynchronous events in the BufferQueue.  The onFrameAvailableHandler,
-    // onFrameReplacedHandler, and onBuffersReleasedHandler 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 onSidebandStreamChangedHandler does nothing and
-    // can be overriden by derived classes if they want the notification.
-    virtual void onFrameAvailableHandler(const BufferItem& item);
-    virtual void onFrameReplacedHandler(const BufferItem& item);
-    virtual void onBuffersReleasedHandler();
-    virtual void onSidebandStreamChangedHandler();
+    // Implementation of the IConsumerListener interface.  These
+    // calls are used to notify the ConsumerBase of asynchronous events in the
+    // 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
@@ -246,35 +244,6 @@
     //
     // This mutex is intended to be locked by derived classes.
     mutable Mutex mMutex;
-
-    // Implements the ConsumerListener interface
-    virtual void onFrameAvailable(const BufferItem& item) override;
-    virtual void onFrameReplaced(const BufferItem& item) override;
-    virtual void onBuffersReleased() override;
-    virtual void onSidebandStreamChanged() override;
-
-    enum MessageType {
-        ON_FRAME_AVAILABLE,
-        ON_FRAME_REPLACED,
-        ON_BUFFERS_RELEASED,
-        ON_SIDEBAND_STREAM_CHANGED,
-        EXIT,
-    };
-
-    mutable Mutex mMessageQueueLock;
-    Condition mMessageAvailable;
-    std::queue<std::pair<MessageType, BufferItem>> mMessageQueue;
-
-    class MessageThread : public Thread {
-    public:
-        MessageThread(ConsumerBase* consumerBase) :
-            mConsumerBase(consumerBase) {};
-    protected:
-        virtual bool threadLoop() override;
-        ConsumerBase* mConsumerBase;
-    };
-
-    sp<MessageThread> mMessageThread;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index f6b4230..fee7c63 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -526,9 +526,10 @@
 
     // Used to enable/disable single buffer mode.
     //
-    // In single buffer mode the last buffer that was dequeued will be cached
-    // and returned to all calls to dequeueBuffer and acquireBuffer. This allows
-    // the producer and consumer to simultaneously access the same buffer.
+    // When single buffer mode is enabled the first buffer that is queued or
+    // dequeued will be cached and returned to all subsequent calls to
+    // dequeueBuffer and acquireBuffer. This allows the producer and consumer to
+    // simultaneously access the same buffer.
     virtual status_t setSingleBufferMode(bool singleBufferMode) = 0;
 
     // Used to enable/disable auto-refresh.
diff --git a/include/gui/IProducerListener.h b/include/gui/IProducerListener.h
index 895da4b..3848a6c 100644
--- a/include/gui/IProducerListener.h
+++ b/include/gui/IProducerListener.h
@@ -41,9 +41,6 @@
     // This is called without any lock held and can be called concurrently by
     // multiple threads.
     virtual void onBufferReleased() = 0; // Asynchronous
-
-    // onSlotFreed is called when the BufferQueue frees a buffer in a slot.
-    virtual void onSlotFreed(int /*slot*/) {}; // Asynchronous
 };
 
 class IProducerListener : public ProducerListener, public IInterface
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index 3afdaae..9f51cdd 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -23,6 +23,8 @@
 #include <ui/ANativeObjectBase.h>
 #include <ui/Region.h>
 
+#include <binder/Parcelable.h>
+
 #include <utils/RefBase.h>
 #include <utils/threads.h>
 #include <utils/KeyedVector.h>
@@ -348,6 +350,43 @@
     bool mSharedBufferHasBeenQueued;
 };
 
+namespace view {
+
+/**
+ * A simple holder for an IGraphicBufferProducer, to match the managed-side
+ * android.view.Surface parcelable behavior.
+ *
+ * This implements android/view/Surface.aidl
+ *
+ * TODO: Convert IGraphicBufferProducer into AIDL so that it can be directly
+ * used in managed Binder calls.
+ */
+class Surface : public Parcelable {
+  public:
+
+    String16 name;
+    sp<IGraphicBufferProducer> graphicBufferProducer;
+
+    virtual status_t writeToParcel(Parcel* parcel) const override;
+    virtual status_t readFromParcel(const Parcel* parcel) override;
+
+    // nameAlreadyWritten set to true by Surface.java, because it splits
+    // Parceling itself between managed and native code, so it only wants a part
+    // of the full parceling to happen on its native side.
+    status_t writeToParcel(Parcel* parcel, bool nameAlreadyWritten) const;
+
+    // nameAlreadyRead set to true by Surface.java, because it splits
+    // Parceling itself between managed and native code, so it only wants a part
+    // of the full parceling to happen on its native side.
+    status_t readFromParcel(const Parcel* parcel, bool nameAlreadyRead);
+
+  private:
+
+    static String16 readMaybeEmptyString16(const Parcel* parcel);
+};
+
+} // namespace view
+
 }; // namespace android
 
 #endif  // ANDROID_GUI_SURFACE_H
diff --git a/include/gui/SurfaceControl.h b/include/gui/SurfaceControl.h
index 993a92f..76ce68d 100644
--- a/include/gui/SurfaceControl.h
+++ b/include/gui/SurfaceControl.h
@@ -57,6 +57,9 @@
     // release surface data from java
     void        clear();
 
+    // disconnect any api that's connected
+    void        disconnect();
+
     status_t    setLayerStack(uint32_t layerStack);
     status_t    setLayer(uint32_t layer);
     status_t    setPosition(float x, float y);
diff --git a/include/media/hardware/HardwareAPI.h b/include/media/hardware/HardwareAPI.h
index feec509..654773d 100644
--- a/include/media/hardware/HardwareAPI.h
+++ b/include/media/hardware/HardwareAPI.h
@@ -23,6 +23,8 @@
 #include <system/window.h>
 #include <utils/RefBase.h>
 
+#include "VideoAPI.h"
+
 #include <OMX_Component.h>
 
 namespace android {
@@ -225,79 +227,6 @@
     OMX_BOOL bEnable;
 };
 
-// Structure describing a media image (frame)
-// Currently only supporting YUV
-// @deprecated. Use MediaImage2 instead
-struct MediaImage {
-    enum Type {
-        MEDIA_IMAGE_TYPE_UNKNOWN = 0,
-        MEDIA_IMAGE_TYPE_YUV,
-    };
-
-    enum PlaneIndex {
-        Y = 0,
-        U,
-        V,
-        MAX_NUM_PLANES
-    };
-
-    Type mType;
-    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 {
-        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];
-};
-
-struct MediaImage2 {
-    enum Type : uint32_t {
-        MEDIA_IMAGE_TYPE_UNKNOWN = 0,
-        MEDIA_IMAGE_TYPE_YUV,
-        MEDIA_IMAGE_TYPE_YUVA,
-        MEDIA_IMAGE_TYPE_RGB,
-        MEDIA_IMAGE_TYPE_RGBA,
-        MEDIA_IMAGE_TYPE_Y,
-    };
-
-    enum PlaneIndex : uint32_t {
-        Y = 0,
-        U = 1,
-        V = 2,
-        R = 0,
-        G = 1,
-        B = 2,
-        A = 3,
-        MAX_NUM_PLANES = 4,
-    };
-
-    Type mType;
-    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 (always MSB)
-    uint32_t mBitDepthAllocated;      // bits per component (must be 8 or 16)
-
-    struct PlaneInfo {
-        uint32_t mOffset;             // offset of first pixel of the plane in bytes
-                                      // from buffer offset
-        int32_t mColInc;              // column increment in bytes
-        int32_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];
-
-    void initFromV1(const MediaImage&); // for internal use only
-};
-
 // A pointer to this struct is passed to OMX_GetParameter when the extension
 // index for the 'OMX.google.android.index.describeColorFormat'
 // extension is given.  This method can be called from any component state
@@ -386,109 +315,108 @@
     OMX_PTR pSidebandWindow;    // OUT
 };
 
-// Color description parameters. This is passed via OMX_SetConfig or OMX_GetConfig
-// to video encoders and decoders when the
-// 'OMX.google.android.index.describeColorAspects' extension is given.
+// Color space description (aspects) parameters.
+// This is passed via OMX_SetConfig or OMX_GetConfig to video encoders and decoders when the
+// 'OMX.google.android.index.describeColorAspects' extension is given. Component SHALL behave
+// as described below if it supports this extension.
 //
-// Video encoders: the framework uses OMX_SetConfig to specify color aspects
-// of the coded video before the component transitions to idle state.
+// bDataSpaceChanged and bRequestingDataSpace is assumed to be OMX_FALSE unless noted otherwise.
 //
-// Video decoders: the framework uses OMX_SetConfig to specify color aspects
-// of the coded video parsed from the container before the component transitions
-// to idle state. If the bitstream contains color information, the component should
-// update the appropriate color aspects - unless the bitstream contains the
-// "unspecified" value. For "reserved" values, the component should set the aspect
-// to "Other".
+// VIDEO ENCODERS: the framework uses OMX_SetConfig to specify color aspects of the coded video.
+// This may happen:
+//   a) before the component transitions to idle state
+//   b) before the input frame is sent via OMX_EmptyThisBuffer in executing state
+//   c) during execution, just before an input frame with a different color aspect information
+//      is sent.
 //
-// The framework subsequently uses OMX_GetConfig to get any updates of the
-// color aspects from the decoder. If the color aspects change at any time
-// during the processing of the stream, the component shall signal a
-// OMX_EventPortSettingsChanged event with data2 set to the extension index
-// (or OMX_IndexConfigCommonOutputCrop, as it is handled identically). Component
-// shall not signal a separate event purely for color aspect change, if it occurs
-// together with a port definition (e.g. size) or crop change.
+// The framework also uses OMX_GetConfig to
+//   d) verify the color aspects that will be written to the stream
+//   e) (optional) verify the color aspects that should be reported to the container for a
+//      given dataspace/pixelformat received
 //
-// NOTE: this structure is expected to grow in the future if new color aspects are
-// added to codec bitstreams. OMX component should not require a specific nSize
-// though could verify that nSize is at least the size of the structure at the
-// time of implementation. All new fields will be added at the end of the structure
-// ensuring backward compatibility.
-
+// 1. Encoders SHOULD maintain an internal color aspect state, initialized to Unspecified values.
+//    This represents the values that will be written into the bitstream.
+// 2. Upon OMX_SetConfig, they SHOULD update their internal state to the aspects received
+//    (including Unspecified values). For specific aspect values that are not supported by the
+//    codec standard, encoders SHOULD substitute Unspecified values; or they MAY use a suitable
+//    alternative (e.g. to suggest the use of BT.709 EOTF instead of SMPTE 240M.)
+// 3. OMX_GetConfig SHALL return the internal state (values that will be written).
+// 4. OMX_SetConfig SHALL always succeed before receiving the first frame. It MAY fail afterwards,
+//    but only if the configured values would change AND the component does not support updating the
+//    color information to those values mid-stream. If component supports updating a portion of
+//    the color information, those values should be updated in the internal state, and OMX_SetConfig
+//    SHALL succeed. Otherwise, the internal state SHALL remain intact and OMX_SetConfig SHALL fail
+//    with OMX_ErrorUnsupportedSettings.
+// 5. When the framework receives an input frame with an unexpected dataspace, it will query
+//    encoders for the color aspects that should be reported to the container using OMX_GetConfig
+//    with bDataSpaceChanged set to OMX_TRUE, and nPixelFormat/nDataSpace containing the new
+//    format/dataspace values. This allows vendors to use extended dataspace during capture and
+//    composition (e.g. screenrecord) - while performing color-space conversion inside the encoder -
+//    and encode and report a different color-space information in the bitstream/container.
+//    sColorAspects contains the requested color aspects by the client for reference, which may
+//    include aspects not supported by the encoding. This is used together with guidance for
+//    dataspace selection; see 6. below.
+//
+// VIDEO DECODERS: the framework uses OMX_SetConfig to specify the default color aspects to use
+// for the video.
+// This may happen:
+//   f) before the component transitions to idle state
+//   g) during execution, when the resolution or the default color aspects change.
+//
+// The framework also uses OMX_GetConfig to
+//   h) get the final color aspects reported by the coded bitstream after taking the default values
+//      into account.
+//
+// 1. Decoders should maintain two color aspect states - the default state as reported by the
+//    framework, and the coded state as reported by the bitstream - as each state can change
+//    independently from the other.
+// 2. Upon OMX_SetConfig, it SHALL update its default state regardless of whether such aspects
+//    could be supplied by the component bitstream. (E.g. it should blindly support all enumeration
+//    values, even unknown ones, and the Other value). This SHALL always succeed.
+// 3. Upon OMX_GetConfig, the component SHALL return the final color aspects by replacing
+//    Unspecified coded values with the default values. This SHALL always succeed.
+// 4. Whenever the component processes color aspect information in the bitstream even with an
+//    Unspecified value, it SHOULD update its internal coded state with that information just before
+//    the frame with the new information would be outputted, and the component SHALL signal an
+//    OMX_EventPortSettingsChanged event with data2 set to the extension index.
+// NOTE: Component SHOULD NOT signal a separate event purely for color aspect change, if it occurs
+//    together with a port definition (e.g. size) or crop change.
+// 5. If the aspects a component encounters in the bitstream cannot be represented with enumeration
+//    values as defined below, the component SHALL set those aspects to Other. Restricted values in
+//    the bitstream SHALL be treated as defined by the relevant bitstream specifications/standards,
+//    or as Unspecified, if not defined.
+//
+// BOTH DECODERS AND ENCODERS: the framework uses OMX_GetConfig during idle and executing state to
+//   i) (optional) get guidance for the dataspace to set for given color aspects, by setting
+//      bRequestingDataSpace to OMX_TRUE. The component SHALL return OMX_ErrorUnsupportedSettings
+//      IF it does not support this request.
+//
+// 6. This is an information request that can happen at any time, independent of the normal
+//    configuration process. This allows vendors to use extended dataspace during capture, playback
+//    and composition - while performing color-space conversion inside the component. Component
+//    SHALL set the desired dataspace into nDataSpace. Otherwise, it SHALL return
+//    OMX_ErrorUnsupportedSettings to let the framework choose a nearby standard dataspace.
+//
+// 6.a. For encoders, this query happens before the first frame is received using surface encoding.
+//    This allows the encoder to use a specific dataspace for the color aspects (e.g. because the
+//    device supports additional dataspaces, or because it wants to perform color-space extension
+//    to facilitate a more optimal rendering/capture pipeline.).
+//
+// 6.b. For decoders, this query happens before the first frame, and every time the color aspects
+//    change, while using surface buffers. This allows the decoder to use a specific dataspace for
+//    the color aspects (e.g. because the device supports additional dataspaces, or because it wants
+//    to perform color-space extension by inline color-space conversion to facilitate a more optimal
+//    rendering pipeline.).
+//
 struct DescribeColorAspectsParams {
-    OMX_U32 nSize;              // IN
-    OMX_VERSIONTYPE nVersion;   // IN
-    OMX_U32 nPortIndex;         // IN
-    OMX_U32 nRange;             // IN/OUT (one of the ColorAspects.Range enums)
-    OMX_U32 nPrimaries;         // IN/OUT (one of the ColorAspects.Primaries enums)
-    OMX_U32 nTransfer;          // IN/OUT (one of the ColorAspects.Transfer enums)
-    OMX_U32 nMatrixCoeffs;      // IN/OUT (one of the ColorAspects.MatrixCoeffs enums)
-};
-
-struct ColorAspects {
-    // this is in sync with the range values in graphics.h
-    enum Range : uint32_t {
-        RangeUnspecified,
-        RangeFull,
-        RangeLimited,
-        RangeOther = 0xff,
-    };
-
-    enum Primaries : uint32_t {
-        PrimariesUnspecified,
-        PrimariesBT709_5,       // Rec.ITU-R BT.709-5 or equivalent
-        PrimariesBT470_6M,      // Rec.ITU-R BT.470-6 System M or equivalent
-        PrimariesBT601_6_625,   // Rec.ITU-R BT.601-6 625 or equivalent
-        PrimariesBT601_6_525,   // Rec.ITU-R BT.601-6 525 or equivalent
-        PrimariesGenericFilm,   // Generic Film
-        PrimariesBT2020,        // Rec.ITU-R BT.2020 or equivalent
-        PrimariesOther = 0xff,
-    };
-
-    // this partially in sync with the transfer values in graphics.h prior to the transfers
-    // unlikely to be required by Android section
-    enum Transfer : uint32_t {
-        TransferUnspecified,
-        TransferLinear,         // Linear transfer characteristics
-        TransferSRGB,           // sRGB or equivalent
-        TransferSMPTE170M,      // SMPTE 170M or equivalent (e.g. BT.601/709/2020)
-        TransferGamma22,        // Assumed display gamma 2.2
-        TransferGamma28,        // Assumed display gamma 2.8
-        TransferST2084,         // SMPTE ST 2084 for 10/12/14/16 bit systems
-        TransferHLG,            // ARIB STD-B67 hybrid-log-gamma
-
-        // transfers unlikely to be required by Android
-        TransferSMPTE240M = 0x40, // SMPTE 240M
-        TransferXvYCC,          // IEC 61966-2-4
-        TransferBT1361,         // Rec.ITU-R BT.1361 extended gamut
-        TransferST428,          // SMPTE ST 428-1
-        TransferOther = 0xff,
-    };
-
-    enum MatrixCoeffs : uint32_t {
-        MatrixUnspecified,
-        MatrixBT709_5,          // Rec.ITU-R BT.709-5 or equivalent
-        MatrixBT470_6M,         // KR=0.30, KB=0.11 or equivalent
-        MatrixBT601_6,          // Rec.ITU-R BT.601-6 625 or equivalent
-        MatrixSMPTE240M,        // SMPTE 240M or equivalent
-        MatrixBT2020,           // Rec.ITU-R BT.2020 non-constant luminance
-        MatrixBT2020Constant,   // Rec.ITU-R BT.2020 constant luminance
-        MatrixOther = 0xff,
-    };
-
-    // this is in sync with the standard values in graphics.h
-    enum Standard : uint32_t {
-        StandardUnspecified,
-        StandardBT709,                  // PrimariesBT709_5 and MatrixBT709_5
-        StandardBT601_625,              // PrimariesBT601_6_625 and MatrixBT601_6
-        StandardBT601_625_Unadjusted,   // PrimariesBT601_6_625 and KR=0.222, KB=0.071
-        StandardBT601_525,              // PrimariesBT601_6_525 and MatrixBT601_6
-        StandardBT601_525_Unadjusted,   // PrimariesBT601_6_525 and MatrixSMPTE240M
-        StandardBT2020,                 // PrimariesBT2020 and MatrixBT2020
-        StandardBT2020Constant,         // PrimariesBT2020 and MatrixBT2020Constant
-        StandardBT470M,                 // PrimariesBT470_6M and MatrixBT470_6M
-        StandardFilm,                   // PrimariesGenericFilm and KR=0.253, KB=0.068
-        StandardOther = 0xff,
-    };
+    OMX_U32 nSize;                 // IN
+    OMX_VERSIONTYPE nVersion;      // IN
+    OMX_U32 nPortIndex;            // IN
+    OMX_BOOL bRequestingDataSpace; // IN
+    OMX_BOOL bDataSpaceChanged;    // IN
+    OMX_U32 nPixelFormat;          // IN
+    OMX_U32 nDataSpace;            // OUT
+    ColorAspects sAspects;         // IN/OUT
 };
 
 }  // namespace android
diff --git a/include/media/hardware/VideoAPI.h b/include/media/hardware/VideoAPI.h
new file mode 100644
index 0000000..481cc67
--- /dev/null
+++ b/include/media/hardware/VideoAPI.h
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VIDEO_API_H_
+
+#define VIDEO_API_H_
+
+namespace android {
+
+/**
+ * Structure describing a media image (frame)
+ * Currently only supporting YUV
+ * @deprecated. Use MediaImage2 instead
+ */
+struct MediaImage {
+    enum Type {
+        MEDIA_IMAGE_TYPE_UNKNOWN = 0,
+        MEDIA_IMAGE_TYPE_YUV,
+    };
+
+    enum PlaneIndex {
+        Y = 0,
+        U,
+        V,
+        MAX_NUM_PLANES
+    };
+
+    Type mType;
+    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 {
+        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];
+};
+
+/**
+ * Structure describing a media image (frame)
+ */
+struct MediaImage2 {
+    enum Type : uint32_t {
+        MEDIA_IMAGE_TYPE_UNKNOWN = 0,
+        MEDIA_IMAGE_TYPE_YUV,
+        MEDIA_IMAGE_TYPE_YUVA,
+        MEDIA_IMAGE_TYPE_RGB,
+        MEDIA_IMAGE_TYPE_RGBA,
+        MEDIA_IMAGE_TYPE_Y,
+    };
+
+    enum PlaneIndex : uint32_t {
+        Y = 0,
+        U = 1,
+        V = 2,
+        R = 0,
+        G = 1,
+        B = 2,
+        A = 3,
+        MAX_NUM_PLANES = 4,
+    };
+
+    Type mType;
+    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 (always MSB)
+    uint32_t mBitDepthAllocated;      // bits per component (must be 8 or 16)
+
+    struct PlaneInfo {
+        uint32_t mOffset;             // offset of first pixel of the plane in bytes
+                                      // from buffer offset
+        int32_t mColInc;              // column increment in bytes
+        int32_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];
+
+    void initFromV1(const MediaImage&); // for internal use only
+};
+
+/**
+ * Aspects of color.
+ */
+
+// NOTE: this structure is expected to grow in the future if new color aspects are
+// added to codec bitstreams. OMX component should not require a specific nSize
+// though could verify that nSize is at least the size of the structure at the
+// time of implementation. All new fields will be added at the end of the structure
+// ensuring backward compatibility.
+struct ColorAspects {
+    // this is in sync with the range values in graphics.h
+    enum Range : uint32_t {
+        RangeUnspecified,
+        RangeFull,
+        RangeLimited,
+        RangeOther = 0xff,
+    };
+
+    enum Primaries : uint32_t {
+        PrimariesUnspecified,
+        PrimariesBT709_5,       // Rec.ITU-R BT.709-5 or equivalent
+        PrimariesBT470_6M,      // Rec.ITU-R BT.470-6 System M or equivalent
+        PrimariesBT601_6_625,   // Rec.ITU-R BT.601-6 625 or equivalent
+        PrimariesBT601_6_525,   // Rec.ITU-R BT.601-6 525 or equivalent
+        PrimariesGenericFilm,   // Generic Film
+        PrimariesBT2020,        // Rec.ITU-R BT.2020 or equivalent
+        PrimariesOther = 0xff,
+    };
+
+    // this partially in sync with the transfer values in graphics.h prior to the transfers
+    // unlikely to be required by Android section
+    enum Transfer : uint32_t {
+        TransferUnspecified,
+        TransferLinear,         // Linear transfer characteristics
+        TransferSRGB,           // sRGB or equivalent
+        TransferSMPTE170M,      // SMPTE 170M or equivalent (e.g. BT.601/709/2020)
+        TransferGamma22,        // Assumed display gamma 2.2
+        TransferGamma28,        // Assumed display gamma 2.8
+        TransferST2084,         // SMPTE ST 2084 for 10/12/14/16 bit systems
+        TransferHLG,            // ARIB STD-B67 hybrid-log-gamma
+
+        // transfers unlikely to be required by Android
+        TransferSMPTE240M = 0x40, // SMPTE 240M
+        TransferXvYCC,          // IEC 61966-2-4
+        TransferBT1361,         // Rec.ITU-R BT.1361 extended gamut
+        TransferST428,          // SMPTE ST 428-1
+        TransferOther = 0xff,
+    };
+
+    enum MatrixCoeffs : uint32_t {
+        MatrixUnspecified,
+        MatrixBT709_5,          // Rec.ITU-R BT.709-5 or equivalent
+        MatrixBT470_6M,         // KR=0.30, KB=0.11 or equivalent
+        MatrixBT601_6,          // Rec.ITU-R BT.601-6 625 or equivalent
+        MatrixSMPTE240M,        // SMPTE 240M or equivalent
+        MatrixBT2020,           // Rec.ITU-R BT.2020 non-constant luminance
+        MatrixBT2020Constant,   // Rec.ITU-R BT.2020 constant luminance
+        MatrixOther = 0xff,
+    };
+
+    // this is in sync with the standard values in graphics.h
+    enum Standard : uint32_t {
+        StandardUnspecified,
+        StandardBT709,                  // PrimariesBT709_5 and MatrixBT709_5
+        StandardBT601_625,              // PrimariesBT601_6_625 and MatrixBT601_6
+        StandardBT601_625_Unadjusted,   // PrimariesBT601_6_625 and KR=0.222, KB=0.071
+        StandardBT601_525,              // PrimariesBT601_6_525 and MatrixBT601_6
+        StandardBT601_525_Unadjusted,   // PrimariesBT601_6_525 and MatrixSMPTE240M
+        StandardBT2020,                 // PrimariesBT2020 and MatrixBT2020
+        StandardBT2020Constant,         // PrimariesBT2020 and MatrixBT2020Constant
+        StandardBT470M,                 // PrimariesBT470_6M and MatrixBT470_6M
+        StandardFilm,                   // PrimariesGenericFilm and KR=0.253, KB=0.068
+        StandardOther = 0xff,
+    };
+
+    Range mRange;                // IN/OUT
+    Primaries mPrimaries;        // IN/OUT
+    Transfer mTransfer;          // IN/OUT
+    MatrixCoeffs mMatrixCoeffs;  // IN/OUT
+};
+
+#ifdef STRINGIFY_ENUMS
+
+inline static const char *asString(MediaImage::Type i, const char *def = "??") {
+    switch (i) {
+        case MediaImage::MEDIA_IMAGE_TYPE_UNKNOWN: return "Unknown";
+        case MediaImage::MEDIA_IMAGE_TYPE_YUV:     return "YUV";
+        default:                                   return def;
+    }
+}
+
+inline static const char *asString(MediaImage::PlaneIndex i, const char *def = "??") {
+    switch (i) {
+        case MediaImage::Y: return "Y";
+        case MediaImage::U: return "U";
+        case MediaImage::V: return "V";
+        default:            return def;
+    }
+}
+
+inline static const char *asString(MediaImage2::Type i, const char *def = "??") {
+    switch (i) {
+        case MediaImage2::MEDIA_IMAGE_TYPE_UNKNOWN: return "Unknown";
+        case MediaImage2::MEDIA_IMAGE_TYPE_YUV:     return "YUV";
+        case MediaImage2::MEDIA_IMAGE_TYPE_YUVA:    return "YUVA";
+        case MediaImage2::MEDIA_IMAGE_TYPE_RGB:     return "RGB";
+        case MediaImage2::MEDIA_IMAGE_TYPE_RGBA:    return "RGBA";
+        case MediaImage2::MEDIA_IMAGE_TYPE_Y:       return "Y";
+        default:                                    return def;
+    }
+}
+
+inline static char asChar2(
+        MediaImage2::PlaneIndex i, MediaImage2::Type j, char def = '?') {
+    const char *planes = asString(j, NULL);
+    // handle unknown values
+    if (j == MediaImage2::MEDIA_IMAGE_TYPE_UNKNOWN || planes == NULL || i >= strlen(planes)) {
+        return def;
+    }
+    return planes[i];
+}
+
+inline static const char *asString(ColorAspects::Range i, const char *def = "??") {
+    switch (i) {
+        case ColorAspects::RangeUnspecified: return "Unspecified";
+        case ColorAspects::RangeFull:        return "Full";
+        case ColorAspects::RangeLimited:     return "Limited";
+        case ColorAspects::RangeOther:       return "Other";
+        default:                             return def;
+    }
+}
+
+inline static const char *asString(ColorAspects::Primaries i, const char *def = "??") {
+    switch (i) {
+        case ColorAspects::PrimariesUnspecified: return "Unspecified";
+        case ColorAspects::PrimariesBT709_5:     return "BT709_5";
+        case ColorAspects::PrimariesBT470_6M:    return "BT470_6M";
+        case ColorAspects::PrimariesBT601_6_625: return "BT601_6_625";
+        case ColorAspects::PrimariesBT601_6_525: return "BT601_6_525";
+        case ColorAspects::PrimariesGenericFilm: return "GenericFilm";
+        case ColorAspects::PrimariesBT2020:      return "BT2020";
+        case ColorAspects::PrimariesOther:       return "Other";
+        default:                                 return def;
+    }
+}
+
+inline static const char *asString(ColorAspects::Transfer i, const char *def = "??") {
+    switch (i) {
+        case ColorAspects::TransferUnspecified: return "Unspecified";
+        case ColorAspects::TransferLinear:      return "Linear";
+        case ColorAspects::TransferSRGB:        return "SRGB";
+        case ColorAspects::TransferSMPTE170M:   return "SMPTE170M";
+        case ColorAspects::TransferGamma22:     return "Gamma22";
+        case ColorAspects::TransferGamma28:     return "Gamma28";
+        case ColorAspects::TransferST2084:      return "ST2084";
+        case ColorAspects::TransferHLG:         return "HLG";
+        case ColorAspects::TransferSMPTE240M:   return "SMPTE240M";
+        case ColorAspects::TransferXvYCC:       return "XvYCC";
+        case ColorAspects::TransferBT1361:      return "BT1361";
+        case ColorAspects::TransferST428:       return "ST428";
+        case ColorAspects::TransferOther:       return "Other";
+        default:                                return def;
+    }
+}
+
+inline static const char *asString(ColorAspects::MatrixCoeffs i, const char *def = "??") {
+    switch (i) {
+        case ColorAspects::MatrixUnspecified:    return "Unspecified";
+        case ColorAspects::MatrixBT709_5:        return "BT709_5";
+        case ColorAspects::MatrixBT470_6M:       return "BT470_6M";
+        case ColorAspects::MatrixBT601_6:        return "BT601_6";
+        case ColorAspects::MatrixSMPTE240M:      return "SMPTE240M";
+        case ColorAspects::MatrixBT2020:         return "BT2020";
+        case ColorAspects::MatrixBT2020Constant: return "BT2020Constant";
+        case ColorAspects::MatrixOther:          return "Other";
+        default:                                 return def;
+    }
+}
+
+inline static const char *asString(ColorAspects::Standard i, const char *def = "??") {
+    switch (i) {
+        case ColorAspects::StandardUnspecified:          return "Unspecified";
+        case ColorAspects::StandardBT709:                return "BT709";
+        case ColorAspects::StandardBT601_625:            return "BT601_625";
+        case ColorAspects::StandardBT601_625_Unadjusted: return "BT601_625_Unadjusted";
+        case ColorAspects::StandardBT601_525:            return "BT601_525";
+        case ColorAspects::StandardBT601_525_Unadjusted: return "BT601_525_Unadjusted";
+        case ColorAspects::StandardBT2020:               return "BT2020";
+        case ColorAspects::StandardBT2020Constant:       return "BT2020Constant";
+        case ColorAspects::StandardBT470M:               return "BT470M";
+        case ColorAspects::StandardFilm:                 return "Film";
+        case ColorAspects::StandardOther:                return "Other";
+        default:                                         return def;
+    }
+}
+
+#endif
+
+}  // namespace android
+
+#endif  // VIDEO_API_H_
diff --git a/include/media/openmax/OMX_AsString.h b/include/media/openmax/OMX_AsString.h
index a741f6d..5fb8ca8 100644
--- a/include/media/openmax/OMX_AsString.h
+++ b/include/media/openmax/OMX_AsString.h
@@ -18,6 +18,10 @@
    Each section has its own include guard.  This file should be included AFTER
    the OMX include files. */
 
+#ifdef ANDROID
+namespace android {
+#endif
+
 #ifdef OMX_Audio_h
 /* asString definitions if media/openmax/OMX_Audio.h was included */
 
@@ -288,6 +292,7 @@
 //      case OMX_EventDynamicResourcesAvailable: return "DynamicResourcesAvailable";
 //      case OMX_EventPortFormatDetected:        return "PortFormatDetected";
         case OMX_EventOutputRendered:            return "OutputRendered";
+        case OMX_EventDataSpaceChanged:          return "DataSpaceChanged";
         default:                                 return def;
     }
 }
@@ -904,10 +909,11 @@
 
 inline static const char *asString(OMX_VIDEO_HEVCPROFILETYPE i, const char *def = "!!") {
     switch (i) {
-        case OMX_VIDEO_HEVCProfileUnknown: return "Unknown";  // unused
-        case OMX_VIDEO_HEVCProfileMain:    return "Main";
-        case OMX_VIDEO_HEVCProfileMain10:  return "Main10";
-        default:                           return def;
+        case OMX_VIDEO_HEVCProfileUnknown:      return "Unknown";  // unused
+        case OMX_VIDEO_HEVCProfileMain:         return "Main";
+        case OMX_VIDEO_HEVCProfileMain10:       return "Main10";
+        case OMX_VIDEO_HEVCProfileMain10HDR10:  return "Main10HDR10";
+        default:                                return def;
     }
 }
 
@@ -947,3 +953,7 @@
 #endif // AS_STRING_FOR_OMX_VIDEOEXT_H
 
 #endif // OMX_VideoExt_h
+
+#ifdef ANDROID
+} // namespace android
+#endif
diff --git a/include/media/openmax/OMX_Audio.h b/include/media/openmax/OMX_Audio.h
index a0cbd3b..d8bee76 100644
--- a/include/media/openmax/OMX_Audio.h
+++ b/include/media/openmax/OMX_Audio.h
@@ -178,7 +178,7 @@
     OMX_VERSIONTYPE nVersion;         /**< OMX specification version information */
     OMX_U32 nPortIndex;               /**< port that this structure applies to */
     OMX_U32 nChannels;                /**< Number of channels (e.g. 2 for stereo) */
-    OMX_NUMERICALDATATYPE eNumData;   /**< indicates PCM data as signed or unsigned */
+    OMX_NUMERICALDATATYPE eNumData;   /**< indicates PCM data as signed, unsigned or floating pt. */
     OMX_ENDIANTYPE eEndian;           /**< indicates PCM data as little or big endian */
     OMX_BOOL bInterleaved;            /**< True for normal interleaved data; false for
                                            non-interleaved data (e.g. block data) */
diff --git a/include/media/openmax/OMX_Core.h b/include/media/openmax/OMX_Core.h
index f746a69..99a7622 100644
--- a/include/media/openmax/OMX_Core.h
+++ b/include/media/openmax/OMX_Core.h
@@ -524,6 +524,21 @@
      *  frame.
      */
     OMX_EventOutputRendered = 0x7F000001,
+
+    /** For framework internal use only: event sent by OMXNodeInstance when it receives a graphic
+     *  input buffer with a new dataspace for encoding. |arg1| will contain the dataspace. |arg2|
+     *  will contain the ColorAspects requested by the component (or framework defaults) using
+     *  the following bitfield layout:
+     *
+     *       +----------+-------------+----------------+------------+
+     *       |   Range  |  Primaries  |  MatrixCoeffs  |  Transfer  |
+     *       +----------+-------------+----------------+------------+
+     *  bits:  31....24   23.......16   15...........8   7........0
+     *
+     *  TODO: We would really need to tie this to an output buffer, but OMX does not provide a
+     *  fool-proof way to do that for video encoders.
+     */
+    OMX_EventDataSpaceChanged,
     OMX_EventMax = 0x7FFFFFFF
 } OMX_EVENTTYPE;
 
diff --git a/include/media/openmax/OMX_Types.h b/include/media/openmax/OMX_Types.h
index 5afaba0..515e002 100644
--- a/include/media/openmax/OMX_Types.h
+++ b/include/media/openmax/OMX_Types.h
@@ -280,12 +280,18 @@
 
 
 /** The OMX_NUMERICALDATATYPE enumeration is used to indicate if data
-    is signed or unsigned
+    is signed, unsigned or floating point (Android extension).
+
+    Android floating point support policy:
+    If component does not support floating point raw audio, it can reset
+    configuration to signed 16-bit integer (support for which is required.)
+    nBitsPerSample will be set to 32 for float data.
  */
 typedef enum OMX_NUMERICALDATATYPE
 {
     OMX_NumericalDataSigned, /**< signed data */
     OMX_NumericalDataUnsigned, /**< unsigned data */
+    OMX_NumericalDataFloat = 0x7F000001, /**< floating point data */
     OMX_NumercialDataMax = 0x7FFFFFFF
 } OMX_NUMERICALDATATYPE;
 
diff --git a/include/media/openmax/OMX_VideoExt.h b/include/media/openmax/OMX_VideoExt.h
index 836a153..1a2f0b5 100644
--- a/include/media/openmax/OMX_VideoExt.h
+++ b/include/media/openmax/OMX_VideoExt.h
@@ -177,10 +177,12 @@
 
 /** HEVC Profile enum type */
 typedef enum OMX_VIDEO_HEVCPROFILETYPE {
-    OMX_VIDEO_HEVCProfileUnknown = 0x0,
-    OMX_VIDEO_HEVCProfileMain    = 0x1,
-    OMX_VIDEO_HEVCProfileMain10  = 0x2,
-    OMX_VIDEO_HEVCProfileMax     = 0x7FFFFFFF
+    OMX_VIDEO_HEVCProfileUnknown      = 0x0,
+    OMX_VIDEO_HEVCProfileMain         = 0x1,
+    OMX_VIDEO_HEVCProfileMain10       = 0x2,
+    // Main10 profile with HDR SEI support.
+    OMX_VIDEO_HEVCProfileMain10HDR10  = 0x1000,
+    OMX_VIDEO_HEVCProfileMax          = 0x7FFFFFFF
 } OMX_VIDEO_HEVCPROFILETYPE;
 
 /** HEVC Level enum type */
diff --git a/include/powermanager/PowerManager.h b/include/powermanager/PowerManager.h
index cbddc11..3268b45 100644
--- a/include/powermanager/PowerManager.h
+++ b/include/powermanager/PowerManager.h
@@ -28,8 +28,9 @@
     USER_ACTIVITY_EVENT_OTHER = 0,
     USER_ACTIVITY_EVENT_BUTTON = 1,
     USER_ACTIVITY_EVENT_TOUCH = 2,
+    USER_ACTIVITY_EVENT_ACCESSIBILITY = 3,
 
-    USER_ACTIVITY_EVENT_LAST = USER_ACTIVITY_EVENT_TOUCH, // Last valid event code.
+    USER_ACTIVITY_EVENT_LAST = USER_ACTIVITY_EVENT_ACCESSIBILITY, // Last valid event code.
 };
 
 }; // namespace android
diff --git a/libs/binder/MemoryDealer.cpp b/libs/binder/MemoryDealer.cpp
index 8739625..51eac11 100644
--- a/libs/binder/MemoryDealer.cpp
+++ b/libs/binder/MemoryDealer.cpp
@@ -135,6 +135,8 @@
     void        dump(const char* what) const;
     void        dump(String8& res, const char* what) const;
 
+    static size_t getAllocationAlignment() { return kMemoryAlign; }
+
 private:
 
     struct chunk_t {
@@ -264,6 +266,12 @@
     return mAllocator;
 }
 
+// static
+size_t MemoryDealer::getAllocationAlignment()
+{
+    return SimpleBestFitAllocator::getAllocationAlignment();
+}
+
 // ----------------------------------------------------------------------------
 
 // align all the memory blocks on a cache-line boundary
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index aacbed5..4029496 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -277,51 +277,35 @@
     ATRACE_CALL();
     ATRACE_BUFFER_INDEX(slot);
     BQ_LOGV("detachBuffer: slot %d", slot);
+    Mutex::Autolock lock(mCore->mMutex);
 
-    sp<IConsumerListener> consumerListener;
-    sp<IProducerListener> producerListener;
-    {
-        Mutex::Autolock lock(mCore->mMutex);
-
-        if (mCore->mIsAbandoned) {
-            BQ_LOGE("detachBuffer: BufferQueue has been abandoned");
-            return NO_INIT;
-        }
-
-        if (mCore->mSingleBufferMode || slot == mCore->mSingleBufferSlot) {
-            BQ_LOGE("detachBuffer: detachBuffer not allowed in single buffer"
-                    "mode");
-            return BAD_VALUE;
-        }
-
-        if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
-            BQ_LOGE("detachBuffer: slot index %d out of range [0, %d)",
-                    slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
-            return BAD_VALUE;
-        } else if (!mSlots[slot].mBufferState.isAcquired()) {
-            BQ_LOGE("detachBuffer: slot %d is not owned by the consumer "
-                    "(state = %s)", slot, mSlots[slot].mBufferState.string());
-            return BAD_VALUE;
-        }
-
-        mSlots[slot].mBufferState.detachConsumer();
-        mCore->mActiveBuffers.erase(slot);
-        mCore->mFreeSlots.insert(slot);
-        mCore->clearBufferSlotLocked(slot);
-        mCore->mDequeueCondition.broadcast();
-        VALIDATE_CONSISTENCY();
-        producerListener = mCore->mConnectedProducerListener;
-        consumerListener = mCore->mConsumerListener;
+    if (mCore->mIsAbandoned) {
+        BQ_LOGE("detachBuffer: BufferQueue has been abandoned");
+        return NO_INIT;
     }
 
-    // Call back without lock held
-    if (producerListener != NULL) {
-        producerListener->onSlotFreed(slot);
-    }
-    if (consumerListener != NULL) {
-        consumerListener->onBuffersReleased();
+    if (mCore->mSingleBufferMode || slot == mCore->mSingleBufferSlot) {
+        BQ_LOGE("detachBuffer: detachBuffer not allowed in single buffer"
+                "mode");
+        return BAD_VALUE;
     }
 
+    if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
+        BQ_LOGE("detachBuffer: slot index %d out of range [0, %d)",
+                slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
+        return BAD_VALUE;
+    } else if (!mSlots[slot].mBufferState.isAcquired()) {
+        BQ_LOGE("detachBuffer: slot %d is not owned by the consumer "
+                "(state = %s)", slot, mSlots[slot].mBufferState.string());
+        return BAD_VALUE;
+    }
+
+    mSlots[slot].mBufferState.detachConsumer();
+    mCore->mActiveBuffers.erase(slot);
+    mCore->mFreeSlots.insert(slot);
+    mCore->clearBufferSlotLocked(slot);
+    mCore->mDequeueCondition.broadcast();
+    VALIDATE_CONSISTENCY();
 
     return NO_ERROR;
 }
@@ -592,40 +576,30 @@
         return BAD_VALUE;
     }
 
-    sp<IConsumerListener> listener;
-    {
-        Mutex::Autolock lock(mCore->mMutex);
-        if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
-            BQ_LOGE("setMaxBufferCount: producer is already connected");
-            return INVALID_OPERATION;
-        }
+    Mutex::Autolock lock(mCore->mMutex);
 
-        if (bufferCount < mCore->mMaxAcquiredBufferCount) {
-            BQ_LOGE("setMaxBufferCount: invalid buffer count (%d) less than"
-                    "mMaxAcquiredBufferCount (%d)", bufferCount,
-                    mCore->mMaxAcquiredBufferCount);
-            return BAD_VALUE;
-        }
-
-        int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode,
-                mCore->mDequeueBufferCannotBlock, bufferCount) -
-                mCore->getMaxBufferCountLocked();
-        if (!mCore->adjustAvailableSlotsLocked(delta, nullptr)) {
-            BQ_LOGE("setMaxBufferCount: BufferQueue failed to adjust the number"
-                    " of available slots. Delta = %d", delta);
-            return BAD_VALUE;
-        }
-
-        mCore->mMaxBufferCount = bufferCount;
-        if (delta < 0) {
-            listener = mCore->mConsumerListener;
-        }
+    if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
+        BQ_LOGE("setMaxBufferCount: producer is already connected");
+        return INVALID_OPERATION;
     }
 
-    // Call back without lock held
-    if (listener != NULL) {
-        listener->onBuffersReleased();
+    if (bufferCount < mCore->mMaxAcquiredBufferCount) {
+        BQ_LOGE("setMaxBufferCount: invalid buffer count (%d) less than"
+                "mMaxAcquiredBufferCount (%d)", bufferCount,
+                mCore->mMaxAcquiredBufferCount);
+        return BAD_VALUE;
     }
+
+    int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode,
+            mCore->mDequeueBufferCannotBlock, bufferCount) -
+            mCore->getMaxBufferCountLocked();
+    if (!mCore->adjustAvailableSlotsLocked(delta)) {
+        BQ_LOGE("setMaxBufferCount: BufferQueue failed to adjust the number of "
+                "available slots. Delta = %d", delta);
+        return BAD_VALUE;
+    }
+
+    mCore->mMaxBufferCount = bufferCount;
     return NO_ERROR;
 }
 
@@ -640,9 +614,7 @@
         return BAD_VALUE;
     }
 
-    sp<IConsumerListener> consumerListener;
-    sp<IProducerListener> producerListener;
-    std::vector<int> freedSlots;
+    sp<IConsumerListener> listener;
     { // Autolock scope
         Mutex::Autolock lock(mCore->mMutex);
         mCore->waitWhileAllocatingLocked();
@@ -679,7 +651,7 @@
         }
 
         int delta = maxAcquiredBuffers - mCore->mMaxAcquiredBufferCount;
-        if (!mCore->adjustAvailableSlotsLocked(delta, &freedSlots)) {
+        if (!mCore->adjustAvailableSlotsLocked(delta)) {
             return BAD_VALUE;
         }
 
@@ -687,19 +659,12 @@
         mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers;
         VALIDATE_CONSISTENCY();
         if (delta < 0) {
-            consumerListener = mCore->mConsumerListener;
-            producerListener = mCore->mConnectedProducerListener;
+            listener = mCore->mConsumerListener;
         }
     }
-
     // Call back without lock held
-    if (consumerListener != NULL) {
-        consumerListener->onBuffersReleased();
-    }
-    if (producerListener != NULL) {
-        for (int i : freedSlots) {
-            producerListener->onSlotFreed(i);
-        }
+    if (listener != NULL) {
+        listener->onBuffersReleased();
     }
 
     return NO_ERROR;
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index fc3ffed..ba07362 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -226,8 +226,7 @@
     VALIDATE_CONSISTENCY();
 }
 
-bool BufferQueueCore::adjustAvailableSlotsLocked(int delta,
-        std::vector<int>* freedSlots) {
+bool BufferQueueCore::adjustAvailableSlotsLocked(int delta) {
     if (delta >= 0) {
         // If we're going to fail, do so before modifying anything
         if (delta > static_cast<int>(mUnusedSlots.size())) {
@@ -254,17 +253,11 @@
                 clearBufferSlotLocked(*slot);
                 mUnusedSlots.push_back(*slot);
                 mFreeSlots.erase(slot);
-                if (freedSlots) {
-                    freedSlots->push_back(*slot);
-                }
             } else if (!mFreeBuffers.empty()) {
                 int slot = mFreeBuffers.back();
                 clearBufferSlotLocked(slot);
                 mUnusedSlots.push_back(slot);
                 mFreeBuffers.pop_back();
-                if (freedSlots) {
-                    freedSlots->push_back(slot);
-                }
             } else {
                 return false;
             }
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index cb5d773..4fd8b89 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -90,9 +90,7 @@
     BQ_LOGV("setMaxDequeuedBufferCount: maxDequeuedBuffers = %d",
             maxDequeuedBuffers);
 
-    sp<IConsumerListener> consumerListener;
-    sp<IProducerListener> producerListener;
-    std::vector<int> freedSlots;
+    sp<IConsumerListener> listener;
     { // Autolock scope
         Mutex::Autolock lock(mCore->mMutex);
         mCore->waitWhileAllocatingLocked();
@@ -144,26 +142,20 @@
         }
 
         int delta = maxDequeuedBuffers - mCore->mMaxDequeuedBufferCount;
-        if (!mCore->adjustAvailableSlotsLocked(delta, &freedSlots)) {
+        if (!mCore->adjustAvailableSlotsLocked(delta)) {
             return BAD_VALUE;
         }
         mCore->mMaxDequeuedBufferCount = maxDequeuedBuffers;
         VALIDATE_CONSISTENCY();
         if (delta < 0) {
-            consumerListener = mCore->mConsumerListener;
-            producerListener = mCore->mConnectedProducerListener;
+            listener = mCore->mConsumerListener;
         }
         mCore->mDequeueCondition.broadcast();
     } // Autolock scope
 
     // Call back without lock held
-    if (consumerListener != NULL) {
-        consumerListener->onBuffersReleased();
-    }
-    if (producerListener != NULL) {
-        for (int i : freedSlots) {
-            producerListener->onSlotFreed(i);
-        }
+    if (listener != NULL) {
+        listener->onBuffersReleased();
     }
 
     return NO_ERROR;
@@ -173,9 +165,7 @@
     ATRACE_CALL();
     BQ_LOGV("setAsyncMode: async = %d", async);
 
-    sp<IConsumerListener> consumerListener;
-    sp<IProducerListener> producerListener;
-    std::vector<int> freedSlots;
+    sp<IConsumerListener> listener;
     { // Autolock scope
         Mutex::Autolock lock(mCore->mMutex);
         mCore->waitWhileAllocatingLocked();
@@ -201,7 +191,7 @@
                 mCore->mDequeueBufferCannotBlock, mCore->mMaxBufferCount)
                 - mCore->getMaxBufferCountLocked();
 
-        if (!mCore->adjustAvailableSlotsLocked(delta, &freedSlots)) {
+        if (!mCore->adjustAvailableSlotsLocked(delta)) {
             BQ_LOGE("setAsyncMode: BufferQueue failed to adjust the number of "
                     "available slots. Delta = %d", delta);
             return BAD_VALUE;
@@ -209,20 +199,12 @@
         mCore->mAsyncMode = async;
         VALIDATE_CONSISTENCY();
         mCore->mDequeueCondition.broadcast();
-        if (delta < 0) {
-            consumerListener = mCore->mConsumerListener;
-            producerListener = mCore->mConnectedProducerListener;
-        }
+        listener = mCore->mConsumerListener;
     } // Autolock scope
 
     // Call back without lock held
-    if (consumerListener != NULL) {
-        consumerListener->onBuffersReleased();
-    }
-    if (producerListener != NULL) {
-        for (int i : freedSlots) {
-            producerListener->onSlotFreed(i);
-        }
+    if (listener != NULL) {
+        listener->onBuffersReleased();
     }
     return NO_ERROR;
 }
@@ -379,9 +361,6 @@
     EGLSyncKHR eglFence = EGL_NO_SYNC_KHR;
     bool attachedByConsumer = false;
 
-    sp<IConsumerListener> consumerListener;
-    sp<IProducerListener> producerListener;
-    int found = BufferItem::INVALID_BUFFER_SLOT;
     { // Autolock scope
         Mutex::Autolock lock(mCore->mMutex);
         mCore->waitWhileAllocatingLocked();
@@ -399,6 +378,7 @@
             height = mCore->mDefaultHeight;
         }
 
+        int found = BufferItem::INVALID_BUFFER_SLOT;
         while (found == BufferItem::INVALID_BUFFER_SLOT) {
             status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue,
                     &found);
@@ -428,8 +408,6 @@
                     mCore->mFreeSlots.insert(found);
                     mCore->clearBufferSlotLocked(found);
                     found = BufferItem::INVALID_BUFFER_SLOT;
-                    consumerListener = mCore->mConsumerListener;
-                    producerListener = mCore->mConnectedProducerListener;
                     continue;
                 }
             }
@@ -466,10 +444,6 @@
         if ((buffer == NULL) ||
                 buffer->needsReallocation(width, height, format, usage))
         {
-            if (buffer != NULL) {
-                consumerListener = mCore->mConsumerListener;
-                producerListener = mCore->mConnectedProducerListener;
-            }
             mSlots[found].mAcquireCalled = false;
             mSlots[found].mGraphicBuffer = NULL;
             mSlots[found].mRequestBufferCalled = false;
@@ -557,14 +531,6 @@
             mSlots[*outSlot].mFrameNumber,
             mSlots[*outSlot].mGraphicBuffer->handle, returnFlags);
 
-    // Call back without lock held
-    if (consumerListener != NULL) {
-        consumerListener->onBuffersReleased();
-    }
-    if (producerListener != NULL) {
-        producerListener->onSlotFreed(found);
-    }
-
     return returnFlags;
 }
 
@@ -572,60 +538,44 @@
     ATRACE_CALL();
     ATRACE_BUFFER_INDEX(slot);
     BQ_LOGV("detachBuffer: slot %d", slot);
+    Mutex::Autolock lock(mCore->mMutex);
 
-    sp<IConsumerListener> consumerListener;
-    sp<IProducerListener> producerListener;
-    {
-        Mutex::Autolock lock(mCore->mMutex);
-
-        if (mCore->mIsAbandoned) {
-            BQ_LOGE("detachBuffer: BufferQueue has been abandoned");
-            return NO_INIT;
-        }
-
-        if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
-            BQ_LOGE("detachBuffer: BufferQueue has no connected producer");
-            return NO_INIT;
-        }
-
-        if (mCore->mSingleBufferMode || mCore->mSingleBufferSlot == slot) {
-            BQ_LOGE("detachBuffer: cannot detach a buffer in single buffer "
-                    "mode");
-            return BAD_VALUE;
-        }
-
-        if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
-            BQ_LOGE("detachBuffer: slot index %d out of range [0, %d)",
-                    slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
-            return BAD_VALUE;
-        } else if (!mSlots[slot].mBufferState.isDequeued()) {
-            BQ_LOGE("detachBuffer: slot %d is not owned by the producer "
-                    "(state = %s)", slot, mSlots[slot].mBufferState.string());
-            return BAD_VALUE;
-        } else if (!mSlots[slot].mRequestBufferCalled) {
-            BQ_LOGE("detachBuffer: buffer in slot %d has not been requested",
-                    slot);
-            return BAD_VALUE;
-        }
-
-        mSlots[slot].mBufferState.detachProducer();
-        mCore->mActiveBuffers.erase(slot);
-        mCore->mFreeSlots.insert(slot);
-        mCore->clearBufferSlotLocked(slot);
-        mCore->mDequeueCondition.broadcast();
-        VALIDATE_CONSISTENCY();
-        producerListener = mCore->mConnectedProducerListener;
-        consumerListener = mCore->mConsumerListener;
+    if (mCore->mIsAbandoned) {
+        BQ_LOGE("detachBuffer: BufferQueue has been abandoned");
+        return NO_INIT;
     }
 
-    // Call back without lock held
-    if (consumerListener != NULL) {
-        consumerListener->onBuffersReleased();
+    if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
+        BQ_LOGE("detachBuffer: BufferQueue has no connected producer");
+        return NO_INIT;
     }
-    if (producerListener != NULL) {
-        producerListener->onSlotFreed(slot);
+
+    if (mCore->mSingleBufferMode || mCore->mSingleBufferSlot == slot) {
+        BQ_LOGE("detachBuffer: cannot detach a buffer in single buffer mode");
+        return BAD_VALUE;
     }
 
+    if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
+        BQ_LOGE("detachBuffer: slot index %d out of range [0, %d)",
+                slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
+        return BAD_VALUE;
+    } else if (!mSlots[slot].mBufferState.isDequeued()) {
+        BQ_LOGE("detachBuffer: slot %d is not owned by the producer "
+                "(state = %s)", slot, mSlots[slot].mBufferState.string());
+        return BAD_VALUE;
+    } else if (!mSlots[slot].mRequestBufferCalled) {
+        BQ_LOGE("detachBuffer: buffer in slot %d has not been requested",
+                slot);
+        return BAD_VALUE;
+    }
+
+    mSlots[slot].mBufferState.detachProducer();
+    mCore->mActiveBuffers.erase(slot);
+    mCore->mFreeSlots.insert(slot);
+    mCore->clearBufferSlotLocked(slot);
+    mCore->mDequeueCondition.broadcast();
+    VALIDATE_CONSISTENCY();
+
     return NO_ERROR;
 }
 
@@ -641,55 +591,41 @@
         return BAD_VALUE;
     }
 
-    sp<IConsumerListener> consumerListener;
-    sp<IProducerListener> producerListener;
-    int found = BufferQueueCore::INVALID_BUFFER_SLOT;
-    {
-        Mutex::Autolock lock(mCore->mMutex);
-        if (mCore->mIsAbandoned) {
-            BQ_LOGE("detachNextBuffer: BufferQueue has been abandoned");
-            return NO_INIT;
-        }
+    Mutex::Autolock lock(mCore->mMutex);
 
-        if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
-            BQ_LOGE("detachNextBuffer: BufferQueue has no connected producer");
-            return NO_INIT;
-        }
-
-        if (mCore->mSingleBufferMode) {
-            BQ_LOGE("detachNextBuffer: cannot detach a buffer in single buffer"
-                    "mode");
-            return BAD_VALUE;
-        }
-
-        mCore->waitWhileAllocatingLocked();
-
-        if (mCore->mFreeBuffers.empty()) {
-            return NO_MEMORY;
-        }
-
-        found = mCore->mFreeBuffers.front();
-        mCore->mFreeBuffers.remove(found);
-        mCore->mFreeSlots.insert(found);
-
-        BQ_LOGV("detachNextBuffer detached slot %d", found);
-
-        *outBuffer = mSlots[found].mGraphicBuffer;
-        *outFence = mSlots[found].mFence;
-        mCore->clearBufferSlotLocked(found);
-        VALIDATE_CONSISTENCY();
-        consumerListener = mCore->mConsumerListener;
-        producerListener = mCore->mConnectedProducerListener;
+    if (mCore->mIsAbandoned) {
+        BQ_LOGE("detachNextBuffer: BufferQueue has been abandoned");
+        return NO_INIT;
     }
 
-    // Call back without lock held
-    if (consumerListener != NULL) {
-        consumerListener->onBuffersReleased();
+    if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
+        BQ_LOGE("detachNextBuffer: BufferQueue has no connected producer");
+        return NO_INIT;
     }
-    if (producerListener != NULL) {
-        producerListener->onSlotFreed(found);
+
+    if (mCore->mSingleBufferMode) {
+        BQ_LOGE("detachNextBuffer: cannot detach a buffer in single buffer"
+                "mode");
+        return BAD_VALUE;
     }
 
+    mCore->waitWhileAllocatingLocked();
+
+    if (mCore->mFreeBuffers.empty()) {
+        return NO_MEMORY;
+    }
+
+    int found = mCore->mFreeBuffers.front();
+    mCore->mFreeBuffers.remove(found);
+    mCore->mFreeSlots.insert(found);
+
+    BQ_LOGV("detachNextBuffer detached slot %d", found);
+
+    *outBuffer = mSlots[found].mGraphicBuffer;
+    *outFence = mSlots[found].mFence;
+    mCore->clearBufferSlotLocked(found);
+    VALIDATE_CONSISTENCY();
+
     return NO_ERROR;
 }
 
@@ -825,6 +761,14 @@
             return BAD_VALUE;
         }
 
+        // If single buffer mode has just been enabled, cache the slot of the
+        // first buffer that is queued and mark it as the shared buffer.
+        if (mCore->mSingleBufferMode && mCore->mSingleBufferSlot ==
+                BufferQueueCore::INVALID_BUFFER_SLOT) {
+            mCore->mSingleBufferSlot = slot;
+            mSlots[slot].mBufferState.mShared = true;
+        }
+
         BQ_LOGV("queueBuffer: slot=%d/%" PRIu64 " time=%" PRIu64 " dataSpace=%d"
                 " crop=[%d,%d,%d,%d] transform=%#x scale=%s",
                 slot, mCore->mFrameCounter + 1, timestamp, dataSpace,
@@ -1084,102 +1028,82 @@
 status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener,
         int api, bool producerControlledByApp, QueueBufferOutput *output) {
     ATRACE_CALL();
+    Mutex::Autolock lock(mCore->mMutex);
+    mConsumerName = mCore->mConsumerName;
+    BQ_LOGV("connect: api=%d producerControlledByApp=%s", api,
+            producerControlledByApp ? "true" : "false");
+
+    if (mCore->mIsAbandoned) {
+        BQ_LOGE("connect: BufferQueue has been abandoned");
+        return NO_INIT;
+    }
+
+    if (mCore->mConsumerListener == NULL) {
+        BQ_LOGE("connect: BufferQueue has no consumer");
+        return NO_INIT;
+    }
+
+    if (output == NULL) {
+        BQ_LOGE("connect: output was NULL");
+        return BAD_VALUE;
+    }
+
+    if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
+        BQ_LOGE("connect: already connected (cur=%d req=%d)",
+                mCore->mConnectedApi, api);
+        return BAD_VALUE;
+    }
+
+    int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode,
+            mDequeueTimeout < 0 ?
+            mCore->mConsumerControlledByApp && producerControlledByApp : false,
+            mCore->mMaxBufferCount) -
+            mCore->getMaxBufferCountLocked();
+    if (!mCore->adjustAvailableSlotsLocked(delta)) {
+        BQ_LOGE("connect: BufferQueue failed to adjust the number of available "
+                "slots. Delta = %d", delta);
+        return BAD_VALUE;
+    }
+
     int status = NO_ERROR;
-    sp<IConsumerListener> consumerListener;
-    sp<IProducerListener> producerListener;
-    std::vector<int> freedSlots;
-    {
-        Mutex::Autolock lock(mCore->mMutex);
-        mConsumerName = mCore->mConsumerName;
-        BQ_LOGV("connect: api=%d producerControlledByApp=%s", api,
-                producerControlledByApp ? "true" : "false");
+    switch (api) {
+        case NATIVE_WINDOW_API_EGL:
+        case NATIVE_WINDOW_API_CPU:
+        case NATIVE_WINDOW_API_MEDIA:
+        case NATIVE_WINDOW_API_CAMERA:
+            mCore->mConnectedApi = api;
+            output->inflate(mCore->mDefaultWidth, mCore->mDefaultHeight,
+                    mCore->mTransformHint,
+                    static_cast<uint32_t>(mCore->mQueue.size()));
 
-        if (mCore->mIsAbandoned) {
-            BQ_LOGE("connect: BufferQueue has been abandoned");
-            return NO_INIT;
-        }
-
-        if (mCore->mConsumerListener == NULL) {
-            BQ_LOGE("connect: BufferQueue has no consumer");
-            return NO_INIT;
-        }
-
-        if (output == NULL) {
-            BQ_LOGE("connect: output was NULL");
-            return BAD_VALUE;
-        }
-
-        if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
-            BQ_LOGE("connect: already connected (cur=%d req=%d)",
-                    mCore->mConnectedApi, api);
-            return BAD_VALUE;
-        }
-
-        bool dequeueBufferCannotBlock = mDequeueTimeout < 0 ?
-                mCore->mConsumerControlledByApp && producerControlledByApp :
-                false;
-        int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode,
-                dequeueBufferCannotBlock, mCore->mMaxBufferCount) -
-                mCore->getMaxBufferCountLocked();
-
-        if (!mCore->adjustAvailableSlotsLocked(delta, &freedSlots)) {
-            BQ_LOGE("connect: BufferQueue failed to adjust the number of "
-                    "available slots. Delta = %d", delta);
-            return BAD_VALUE;
-        }
-
-        switch (api) {
-            case NATIVE_WINDOW_API_EGL:
-            case NATIVE_WINDOW_API_CPU:
-            case NATIVE_WINDOW_API_MEDIA:
-            case NATIVE_WINDOW_API_CAMERA:
-                mCore->mConnectedApi = api;
-                output->inflate(mCore->mDefaultWidth, mCore->mDefaultHeight,
-                        mCore->mTransformHint,
-                        static_cast<uint32_t>(mCore->mQueue.size()));
-
-                // Set up a death notification so that we can disconnect
-                // automatically if the remote producer dies
-                if (listener != NULL &&
-                        IInterface::asBinder(listener)->remoteBinder() !=
-                        NULL) {
-                    status = IInterface::asBinder(listener)->linkToDeath(
-                            static_cast<IBinder::DeathRecipient*>(this));
-                    if (status != NO_ERROR) {
-                        BQ_LOGE("connect: linkToDeath failed: %s (%d)",
-                                strerror(-status), status);
-                    }
+            // Set up a death notification so that we can disconnect
+            // automatically if the remote producer dies
+            if (listener != NULL &&
+                    IInterface::asBinder(listener)->remoteBinder() != NULL) {
+                status = IInterface::asBinder(listener)->linkToDeath(
+                        static_cast<IBinder::DeathRecipient*>(this));
+                if (status != NO_ERROR) {
+                    BQ_LOGE("connect: linkToDeath failed: %s (%d)",
+                            strerror(-status), status);
                 }
-                mCore->mConnectedProducerListener = listener;
-                break;
-            default:
-                BQ_LOGE("connect: unknown API %d", api);
-                status = BAD_VALUE;
-                break;
-        }
-
-        mCore->mBufferHasBeenQueued = false;
-        mCore->mDequeueBufferCannotBlock = dequeueBufferCannotBlock;
-
-        mCore->mAllowAllocation = true;
-        VALIDATE_CONSISTENCY();
-
-        if (delta < 0) {
-            consumerListener = mCore->mConsumerListener;
-            producerListener = listener;
-        }
+            }
+            mCore->mConnectedProducerListener = listener;
+            break;
+        default:
+            BQ_LOGE("connect: unknown API %d", api);
+            status = BAD_VALUE;
+            break;
     }
 
-    // Call back without lock held
-    if (consumerListener != NULL) {
-        consumerListener->onBuffersReleased();
-    }
-    if (producerListener != NULL) {
-        for (int i : freedSlots) {
-            producerListener->onSlotFreed(i);
-        }
+    mCore->mBufferHasBeenQueued = false;
+    mCore->mDequeueBufferCannotBlock = false;
+    if (mDequeueTimeout < 0) {
+        mCore->mDequeueBufferCannotBlock =
+                mCore->mConsumerControlledByApp && producerControlledByApp;
     }
 
+    mCore->mAllowAllocation = true;
+    VALIDATE_CONSISTENCY();
     return status;
 }
 
@@ -1199,6 +1123,15 @@
             return NO_ERROR;
         }
 
+        if (api == BufferQueueCore::CURRENTLY_CONNECTED_API) {
+            api = mCore->mConnectedApi;
+            // If we're asked to disconnect the currently connected api but
+            // nobody is connected, it's not really an error.
+            if (api == BufferQueueCore::NO_CONNECTED_API) {
+                return NO_ERROR;
+            }
+        }
+
         switch (api) {
             case NATIVE_WINDOW_API_EGL:
             case NATIVE_WINDOW_API_CPU:
@@ -1407,40 +1340,19 @@
     ATRACE_CALL();
     BQ_LOGV("setDequeueTimeout: %" PRId64, timeout);
 
-    sp<IConsumerListener> consumerListener;
-    sp<IProducerListener> producerListener;
-    std::vector<int> freedSlots;
-    {
-        Mutex::Autolock lock(mCore->mMutex);
-        int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode, false,
-                mCore->mMaxBufferCount) - mCore->getMaxBufferCountLocked();
-        if (!mCore->adjustAvailableSlotsLocked(delta, &freedSlots)) {
-            BQ_LOGE("setDequeueTimeout: BufferQueue failed to adjust the number"
-                    " of available slots. Delta = %d", delta);
-            return BAD_VALUE;
-        }
-
-        mDequeueTimeout = timeout;
-        mCore->mDequeueBufferCannotBlock = false;
-
-        VALIDATE_CONSISTENCY();
-
-        if (delta < 0) {
-            consumerListener = mCore->mConsumerListener;
-            producerListener = mCore->mConnectedProducerListener;
-        }
+    Mutex::Autolock lock(mCore->mMutex);
+    int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode, false,
+            mCore->mMaxBufferCount) - mCore->getMaxBufferCountLocked();
+    if (!mCore->adjustAvailableSlotsLocked(delta)) {
+        BQ_LOGE("setDequeueTimeout: BufferQueue failed to adjust the number of "
+                "available slots. Delta = %d", delta);
+        return BAD_VALUE;
     }
 
-    // Call back without lock held
-    if (consumerListener != NULL) {
-        consumerListener->onBuffersReleased();
-    }
-    if (producerListener != NULL) {
-        for (int i : freedSlots) {
-            producerListener->onSlotFreed(i);
-        }
-    }
+    mDequeueTimeout = timeout;
+    mCore->mDequeueBufferCannotBlock = false;
 
+    VALIDATE_CONSISTENCY();
     return NO_ERROR;
 }
 
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index a22b81b..2187e5e 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -74,26 +74,12 @@
     } else {
         mConsumer->setConsumerName(mName);
     }
-
-    mMessageThread = new MessageThread(this);
-    mMessageThread->run();
 }
 
 ConsumerBase::~ConsumerBase() {
     CB_LOGV("~ConsumerBase");
-
-    mMessageThread->requestExit();
-    {
-        Mutex::Autolock lock(mMessageQueueLock);
-        mMessageQueue.emplace(std::piecewise_construct,
-                std::forward_as_tuple(EXIT),
-                std::forward_as_tuple());
-        mMessageAvailable.signal();
-    }
-
-    mMessageThread->join();
-
     Mutex::Autolock lock(mMutex);
+
     // Verify that abandon() has been called before we get here.  This should
     // be done by ConsumerBase::onLastStrongRef(), but it's possible for a
     // derived class to override that method and not call
@@ -114,13 +100,6 @@
 }
 
 void ConsumerBase::onFrameAvailable(const BufferItem& item) {
-    Mutex::Autolock lock(mMessageQueueLock);
-    mMessageQueue.emplace(std::piecewise_construct,
-            std::forward_as_tuple(ON_FRAME_AVAILABLE),
-            std::forward_as_tuple(item));
-    mMessageAvailable.signal();
-}
-void ConsumerBase::onFrameAvailableHandler(const BufferItem& item) {
     CB_LOGV("onFrameAvailable");
 
     sp<FrameAvailableListener> listener;
@@ -136,14 +115,6 @@
 }
 
 void ConsumerBase::onFrameReplaced(const BufferItem &item) {
-    Mutex::Autolock lock(mMessageQueueLock);
-    mMessageQueue.emplace(std::piecewise_construct,
-            std::forward_as_tuple(ON_FRAME_REPLACED),
-            std::forward_as_tuple(item));
-    mMessageAvailable.signal();
-}
-
-void ConsumerBase::onFrameReplacedHandler(const BufferItem &item) {
     CB_LOGV("onFrameReplaced");
 
     sp<FrameAvailableListener> listener;
@@ -159,14 +130,6 @@
 }
 
 void ConsumerBase::onBuffersReleased() {
-    Mutex::Autolock lock(mMessageQueueLock);
-    mMessageQueue.emplace(std::piecewise_construct,
-            std::forward_as_tuple(ON_BUFFERS_RELEASED),
-            std::forward_as_tuple());
-    mMessageAvailable.signal();
-}
-
-void ConsumerBase::onBuffersReleasedHandler() {
     Mutex::Autolock lock(mMutex);
 
     CB_LOGV("onBuffersReleased");
@@ -186,45 +149,6 @@
 }
 
 void ConsumerBase::onSidebandStreamChanged() {
-    Mutex::Autolock lock(mMessageQueueLock);
-    mMessageQueue.emplace(std::piecewise_construct,
-            std::forward_as_tuple(ON_SIDEBAND_STREAM_CHANGED),
-            std::forward_as_tuple());
-    mMessageAvailable.signal();
-}
-
-void ConsumerBase::onSidebandStreamChangedHandler() {
-}
-
-bool ConsumerBase::MessageThread::threadLoop() {
-    Mutex::Autolock lock(mConsumerBase->mMessageQueueLock);
-
-    if (mConsumerBase->mMessageQueue.empty()) {
-        mConsumerBase->mMessageAvailable.wait(mConsumerBase->mMessageQueueLock);
-    }
-
-    while (!mConsumerBase->mMessageQueue.empty()) {
-        auto nextMessage = mConsumerBase->mMessageQueue.front();
-
-        switch (nextMessage.first) {
-            case ON_FRAME_AVAILABLE:
-                mConsumerBase->onFrameAvailableHandler(nextMessage.second);
-                break;
-            case ON_FRAME_REPLACED:
-                mConsumerBase->onFrameReplacedHandler(nextMessage.second);
-                break;
-            case ON_BUFFERS_RELEASED:
-                mConsumerBase->onBuffersReleasedHandler();
-                break;
-            case ON_SIDEBAND_STREAM_CHANGED:
-                mConsumerBase->onSidebandStreamChangedHandler();
-                break;
-            case EXIT:
-                break;
-        }
-        mConsumerBase->mMessageQueue.pop();
-    }
-    return true;
 }
 
 void ConsumerBase::abandon() {
@@ -238,7 +162,7 @@
 }
 
 void ConsumerBase::abandonLocked() {
-	CB_LOGV("abandonLocked");
+    CB_LOGV("abandonLocked");
     for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
         freeBufferLocked(i);
     }
diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp
index a75569f..cb1ad35 100644
--- a/libs/gui/IGraphicBufferConsumer.cpp
+++ b/libs/gui/IGraphicBufferConsumer.cpp
@@ -338,7 +338,7 @@
         }
         case GET_RELEASED_BUFFERS: {
             CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
-            uint64_t slotMask;
+            uint64_t slotMask = 0;
             status_t result = getReleasedBuffers(&slotMask);
             reply->writeInt64(static_cast<int64_t>(slotMask));
             reply->writeInt32(result);
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index c66694d..3101f3a 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -513,6 +513,7 @@
             QueueBufferOutput* const output =
                     reinterpret_cast<QueueBufferOutput *>(
                             reply->writeInplace(sizeof(QueueBufferOutput)));
+            memset(output, 0, sizeof(QueueBufferOutput));
             status_t res = connect(listener, api, producerControlledByApp, output);
             reply->writeInt32(res);
             return NO_ERROR;
diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp
index 39c1da8..81adc95 100644
--- a/libs/gui/IProducerListener.cpp
+++ b/libs/gui/IProducerListener.cpp
@@ -22,7 +22,6 @@
 
 enum {
     ON_BUFFER_RELEASED = IBinder::FIRST_CALL_TRANSACTION,
-    ON_SLOT_FREED,
 };
 
 class BpProducerListener : public BpInterface<IProducerListener>
@@ -38,17 +37,6 @@
         data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor());
         remote()->transact(ON_BUFFER_RELEASED, data, &reply, IBinder::FLAG_ONEWAY);
     }
-
-    virtual void onSlotFreed(int slot) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor());
-        data.writeInt32(slot);
-        status_t err = remote()->transact(ON_SLOT_FREED, data, &reply,
-                IBinder::FLAG_ONEWAY);
-        if (err != NO_ERROR) {
-            ALOGE("onSlotFreed failed to transact %d", err);
-        }
-    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -64,12 +52,6 @@
             CHECK_INTERFACE(IProducerListener, data, reply);
             onBufferReleased();
             return NO_ERROR;
-        case ON_SLOT_FREED: {
-            CHECK_INTERFACE(IProducerListener, data, reply);
-            int slot = data.readInt32();
-            onSlotFreed(slot);
-            return NO_ERROR;
-        }
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
diff --git a/libs/gui/SensorEventQueue.cpp b/libs/gui/SensorEventQueue.cpp
index 4b7986e..5983a6c 100644
--- a/libs/gui/SensorEventQueue.cpp
+++ b/libs/gui/SensorEventQueue.cpp
@@ -125,7 +125,7 @@
 }
 
 status_t SensorEventQueue::enableSensor(Sensor const* sensor) const {
-    return mSensorEventConnection->enableDisable(sensor->getHandle(), true, 0, 0, false);
+    return mSensorEventConnection->enableDisable(sensor->getHandle(), true, us2ns(200000), 0, false);
 }
 
 status_t SensorEventQueue::disableSensor(Sensor const* sensor) const {
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index c295684..8025ca5 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -1259,4 +1259,57 @@
     return err;
 }
 
+namespace view {
+
+status_t Surface::writeToParcel(Parcel* parcel) const {
+    return writeToParcel(parcel, false);
+}
+
+status_t Surface::writeToParcel(Parcel* parcel, bool nameAlreadyWritten) const {
+    if (parcel == nullptr) return BAD_VALUE;
+
+    status_t res = OK;
+
+    if (!nameAlreadyWritten) res = parcel->writeString16(name);
+
+    if (res == OK) {
+        res = parcel->writeStrongBinder(
+                IGraphicBufferProducer::asBinder(graphicBufferProducer));
+    }
+    return res;
+}
+
+status_t Surface::readFromParcel(const Parcel* parcel) {
+    return readFromParcel(parcel, false);
+}
+
+status_t Surface::readFromParcel(const Parcel* parcel, bool nameAlreadyRead) {
+    if (parcel == nullptr) return BAD_VALUE;
+
+    if (!nameAlreadyRead) {
+        name = readMaybeEmptyString16(parcel);
+    }
+
+    sp<IBinder> binder;
+
+    status_t res = parcel->readStrongBinder(&binder);
+    if (res != OK) return res;
+
+    graphicBufferProducer = interface_cast<IGraphicBufferProducer>(binder);
+
+    return OK;
+}
+
+String16 Surface::readMaybeEmptyString16(const Parcel* parcel) {
+    size_t len;
+    const char16_t* str = parcel->readString16Inplace(&len);
+    if (str != nullptr) {
+        return String16(str, len);
+    } else {
+        return String16();
+    }
+}
+
+} // namespace view
+
 }; // namespace android
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index a945358..e1a951c 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -33,6 +33,7 @@
 #include <ui/GraphicBuffer.h>
 #include <ui/Rect.h>
 
+#include <gui/BufferQueueCore.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
@@ -81,6 +82,13 @@
     destroy();
 }
 
+void SurfaceControl::disconnect() {
+    if (mGraphicBufferProducer != NULL) {
+        mGraphicBufferProducer->disconnect(
+                BufferQueueCore::CURRENTLY_CONNECTED_API);
+    }
+}
+
 bool SurfaceControl::isSameSurface(
         const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs)
 {
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index b6af166..7790762 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -661,6 +661,57 @@
     }
 }
 
+TEST_F(BufferQueueTest, TestSingleBufferModeUsingAlreadyDequeuedBuffer) {
+    createBufferQueue();
+    sp<DummyConsumer> dc(new DummyConsumer);
+    ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true));
+    IGraphicBufferProducer::QueueBufferOutput output;
+    ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
+            NATIVE_WINDOW_API_CPU, true, &output));
+
+    // Dequeue a buffer
+    int singleSlot;
+    sp<Fence> fence;
+    sp<GraphicBuffer> buffer;
+    ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
+            mProducer->dequeueBuffer(&singleSlot, &fence, 0, 0, 0, 0));
+    ASSERT_EQ(OK, mProducer->requestBuffer(singleSlot, &buffer));
+
+    // Enable single buffer mode
+    ASSERT_EQ(OK, mProducer->setSingleBufferMode(true));
+
+    // Queue the buffer
+    IGraphicBufferProducer::QueueBufferInput input(0, false,
+            HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1),
+            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
+    ASSERT_EQ(OK, mProducer->queueBuffer(singleSlot, input, &output));
+
+    // Repeatedly queue and dequeue a buffer from the producer side, it should
+    // always return the same one. And we won't run out of buffers because it's
+    // always the same one and because async mode gets enabled.
+    int slot;
+    for (int i = 0; i < 5; i++) {
+        ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0));
+        ASSERT_EQ(singleSlot, slot);
+        ASSERT_EQ(OK, mProducer->queueBuffer(singleSlot, input, &output));
+    }
+
+    // acquire the buffer
+    BufferItem item;
+    ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
+    ASSERT_EQ(singleSlot, item.mSlot);
+    testBufferItem(input, item);
+    ASSERT_EQ(true, item.mQueuedBuffer);
+    ASSERT_EQ(false, item.mAutoRefresh);
+
+    ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
+            EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
+
+    // attempt to acquire a second time should return no buffer available
+    ASSERT_EQ(IGraphicBufferConsumer::NO_BUFFER_AVAILABLE,
+            mConsumer->acquireBuffer(&item, 0));
+}
+
 TEST_F(BufferQueueTest, TestTimeouts) {
     createBufferQueue();
     sp<DummyConsumer> dc(new DummyConsumer);
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index fad0baa..45b6463 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -727,55 +727,4 @@
     ASSERT_EQ(NO_INIT, mProducer->attachBuffer(&slot, buffer));
 }
 
-struct TestListener : public BnProducerListener {
-    virtual void onBufferReleased() {}
-    virtual void onSlotFreed(int slot) {
-        ASSERT_EQ(1, slot);
-    }
-};
-
-TEST_F(IGraphicBufferProducerTest, SlotFreedListenerReturnsCorrectSlot) {
-    const ::testing::TestInfo* const testInfo =
-        ::testing::UnitTest::GetInstance()->current_test_info();
-    ALOGV("Begin test: %s.%s", testInfo->test_case_name(),
-            testInfo->name());
-
-    BufferQueue::createBufferQueue(&mProducer, &mConsumer);
-
-    sp<DummyConsumer> consumerListener = new DummyConsumer;
-    ASSERT_OK(mConsumer->consumerConnect(consumerListener, false));
-
-    sp<TestListener> producerListener = new TestListener;
-    IGraphicBufferProducer::QueueBufferOutput output;
-    ASSERT_OK(mProducer->connect(producerListener, TEST_API,
-            TEST_CONTROLLED_BY_APP, &output));
-
-    ASSERT_OK(mProducer->setMaxDequeuedBufferCount(2));
-
-    DequeueBufferResult buffer0;
-    sp<GraphicBuffer> buf;
-    ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            dequeueBuffer(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
-            TEST_PRODUCER_USAGE_BITS, &buffer0));
-    ASSERT_OK(mProducer->requestBuffer(buffer0.slot, &buf));
-
-    DequeueBufferResult buffer1;
-    ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            dequeueBuffer(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
-            TEST_PRODUCER_USAGE_BITS, &buffer1));
-
-    IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
-    ASSERT_OK(mProducer->queueBuffer(buffer0.slot, input, &output));
-
-    DequeueBufferResult buffer2;
-    ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
-            dequeueBuffer(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
-            TEST_PRODUCER_USAGE_BITS, &buffer2));
-
-    ASSERT_OK(mProducer->cancelBuffer(buffer1.slot, Fence::NO_FENCE));
-
-    ASSERT_OK(mProducer->setMaxDequeuedBufferCount(1));
-}
-
-
 } // namespace android
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index 2356f54..a1578f6 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -564,7 +564,7 @@
 
     ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
     ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1));
-    thread->run();
+    thread->run("MyThread");
     ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
     ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1], -1));
     //ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[2]));
diff --git a/libs/gui/tests/SurfaceTextureGLThreadToGL.h b/libs/gui/tests/SurfaceTextureGLThreadToGL.h
index 14e42ac..2ce20eb 100644
--- a/libs/gui/tests/SurfaceTextureGLThreadToGL.h
+++ b/libs/gui/tests/SurfaceTextureGLThreadToGL.h
@@ -171,7 +171,7 @@
         mProducerThread = producerThread;
         producerThread->setEglObjects(mEglDisplay, mProducerEglSurface,
                 mProducerEglContext);
-        producerThread->run();
+        producerThread->run("ProducerThread");
     }
 
     sp<ProducerThread> mProducerThread;
diff --git a/libs/gui/tests/SurfaceTextureGLToGL_test.cpp b/libs/gui/tests/SurfaceTextureGLToGL_test.cpp
index b8a7a90..c28b4d1 100644
--- a/libs/gui/tests/SurfaceTextureGLToGL_test.cpp
+++ b/libs/gui/tests/SurfaceTextureGLToGL_test.cpp
@@ -192,10 +192,6 @@
     ASSERT_EQ(EGL_SUCCESS, eglGetError());
     mProducerEglSurface = EGL_NO_SURFACE;
 
-    // sleep for 10ms to allow any asynchronous operations to complete before
-    // checking the reference counts
-    usleep(10000);
-
     // This test should have the only reference to buffer 0.
     EXPECT_EQ(1, buffers[0]->getStrongCount());
 
diff --git a/libs/gui/tests/SurfaceTextureGL_test.cpp b/libs/gui/tests/SurfaceTextureGL_test.cpp
index 1a904b5..dddcf92 100644
--- a/libs/gui/tests/SurfaceTextureGL_test.cpp
+++ b/libs/gui/tests/SurfaceTextureGL_test.cpp
@@ -295,7 +295,7 @@
     };
 
     sp<Thread> pt(new ProducerThread(mANW, testPixels));
-    pt->run();
+    pt->run("ProducerThread");
 
     glViewport(0, 0, texWidth, texHeight);
 
@@ -484,7 +484,7 @@
 
 
     sp<Thread> pt(new ProducerThread(mANW));
-    pt->run();
+    pt->run("ProducerThread");
 
     // eat a frame so GLConsumer will own an at least one slot
     dw->waitForFrame();
@@ -681,7 +681,7 @@
     };
 
     sp<Thread> pt(new ProducerThread(mANW));
-    pt->run();
+    pt->run("ProducerThread");
 
     mFW->waitForFrame();
     mFW->waitForFrame();
diff --git a/libs/ui/Rect.cpp b/libs/ui/Rect.cpp
index 99cbedc..d8702e5 100644
--- a/libs/ui/Rect.cpp
+++ b/libs/ui/Rect.cpp
@@ -127,13 +127,13 @@
         if (!(mask & (mask - 1))) {
             // power-of-2, i.e.: just one bit is set
             if (mask & 1) {
-                result.right = exclude.left;
+                result.right = min(result.right, exclude.left);
             } else if (mask & 2) {
-                result.bottom = exclude.top;
+                result.bottom = min(result.bottom, exclude.top);
             } else if (mask & 4) {
-                result.left = exclude.right;
+                result.left = max(result.left, exclude.right);
             } else if (mask & 8) {
-                result.top = exclude.bottom;
+                result.top = max(result.top, exclude.bottom);
             }
         }
     }
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 267f8af..5d838e6 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -611,6 +611,12 @@
 #endif
 #endif
 
+#ifndef EGL_ANDROID_front_buffer_auto_refresh
+#define EGL_ANDROID_front_buffer_auto_refresh 1
+#define EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID 0x314C
+#endif
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 05700f8..e7703d8 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -72,7 +72,7 @@
  * The rest (gExtensionString) depend on support in the EGL driver, and are
  * only available if the driver supports them. However, some of these must be
  * supported because they are used by the Android system itself; these are
- * listd as mandatory below and are required by the CDD. The system *assumes*
+ * listed as mandatory below and are required by the CDD. The system *assumes*
  * the mandatory extensions are present and may not function properly if some
  * are missing.
  *
@@ -83,6 +83,7 @@
         "EGL_ANDROID_presentation_time "
         "EGL_KHR_swap_buffers_with_damage "
         "EGL_ANDROID_create_native_client_buffer "
+        "EGL_ANDROID_front_buffer_auto_refresh "
         ;
 extern char const * const gExtensionString  =
         "EGL_KHR_image "                        // mandatory
@@ -1194,12 +1195,11 @@
 
     egl_surface_t const * const s = get_surface(surface);
 
-    //XXX: temporary hack for the EGL hook-up for single buffer mode
-    if (attribute == EGL_RENDER_BUFFER && (value == EGL_BACK_BUFFER ||
-            value == EGL_SINGLE_BUFFER)) {
-        native_window_set_auto_refresh(s->win.get(), true);
-        return (native_window_set_single_buffer_mode(s->win.get(),
-                value == EGL_SINGLE_BUFFER)) ? EGL_TRUE : EGL_FALSE;
+    if (attribute == EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID) {
+        int err = native_window_set_auto_refresh(s->win.get(),
+            value ? true : false);
+        return (err == NO_ERROR) ? EGL_TRUE :
+            setError(EGL_BAD_SURFACE, EGL_FALSE);
     }
 
     if (s->cnx->egl.eglSurfaceAttrib) {
diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp
index f368d75..8c135c8 100644
--- a/opengl/libs/EGL/egl_cache.cpp
+++ b/opengl/libs/EGL/egl_cache.cpp
@@ -165,7 +165,7 @@
             // running, so there's no need to keep a ref around.
             sp<Thread> deferredSaveThread(new DeferredSaveThread());
             mSavePending = true;
-            deferredSaveThread->run();
+            deferredSaveThread->run("DeferredSaveThread");
         }
     }
 }
diff --git a/opengl/specs/EGL_ANDROID_front_buffer_auto_refresh.txt b/opengl/specs/EGL_ANDROID_front_buffer_auto_refresh.txt
new file mode 100644
index 0000000..4c0e64c
--- /dev/null
+++ b/opengl/specs/EGL_ANDROID_front_buffer_auto_refresh.txt
@@ -0,0 +1,70 @@
+Name
+
+    ANDROID_front_buffer_auto_refresh
+
+Name Strings
+
+    EGL_ANDROID_front_buffer_auto_refresh
+
+Contributors
+
+    Pablo Ceballos
+
+Contact
+
+    Pablo Ceballos, Google Inc. (pceballos 'at' google.com)
+
+Status
+
+    Draft
+
+Version
+
+    Version 1, February 3, 2016
+
+Number
+
+    EGL Extension #XXX
+
+Dependencies
+
+    Requires EGL 1.2
+
+    This extension is written against the wording of the EGL 1.5 Specification
+
+Overview
+
+    This extension is intended for latency-sensitive applications that are doing
+    front-buffer rendering. It allows them to indicate to the Android compositor
+    that it should perform composition every time the display refreshes. This
+    removes the overhead of having to notify the compositor that the window
+    surface has been updated, but it comes at the cost of doing potentially
+    unneeded composition work if the window surface has not been updated.
+
+New Types
+
+    None
+
+New Procedures and Functions
+
+    None
+
+New Tokens
+
+    EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID 0x314C
+
+Add to the list of supported tokens for eglSurfaceAttrib in section 3.5.6
+"Surface Attributes", page 43:
+
+    If attribute is EGL_ANDROID_front_buffer_auto_refresh, then value specifies
+    whether to enable or disable auto-refresh in the Android compositor when
+    doing front-buffer rendering.
+
+Issues
+
+    None
+
+Revision History
+
+#1 (Pablo Ceballos, February 3, 2016)
+    - Initial draft.
diff --git a/opengl/specs/README b/opengl/specs/README
index f4de1b3..8f1eaf3 100644
--- a/opengl/specs/README
+++ b/opengl/specs/README
@@ -6,10 +6,10 @@
 
      Value                       Extension
 ----------------     ----------------------------------
-0x3140               EGL_ANDROID_image_native_buffer
-0x3141               (unused)
+0x3140               EGL_NATIVE_BUFFER_ANDROID (EGL_ANDROID_image_native_buffer)
+0x3141               EGL_PLATFORM_ANDROID_KHR (KHR_platform_android)
 0x3142               EGL_RECORDABLE_ANDROID (EGL_ANDROID_recordable)
-0x3143               EGL_VERSION_HW_ANDROID (internal use)
+0x3143               EGL_NATIVE_BUFFER_USAGE_ANDROID (EGL_ANDROID_create_native_client_buffer)
 0x3144               EGL_SYNC_NATIVE_FENCE_ANDROID (EGL_ANDROID_native_fence_sync)
 0x3145               EGL_SYNC_NATIVE_FENCE_FD_ANDROID (EGL_ANDROID_native_fence_sync)
 0x3146               EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID (EGL_ANDROID_native_fence_sync)
@@ -18,4 +18,5 @@
 0x3149               EGL_IMAGE_CROP_TOP_ANDROID (EGL_ANDROID_image_crop)
 0x314A               EGL_IMAGE_CROP_RIGHT_ANDROID (EGL_ANDROID_image_crop)
 0x314B               EGL_IMAGE_CROP_BOTTOM_ANDROID (EGL_ANDROID_image_crop)
-0x314C - 0x314F      (unused)
+0x314C               EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID (EGL_ANDROID_front_buffer_auto_refresh)
+0x314D - 0x314F      (unused)
diff --git a/opengl/tools/glgen/stubs/gles11/glCreateShaderProgramv.cpp b/opengl/tools/glgen/stubs/gles11/glCreateShaderProgramv.cpp
index e701481..52295a1 100644
--- a/opengl/tools/glgen/stubs/gles11/glCreateShaderProgramv.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glCreateShaderProgramv.cpp
@@ -2,7 +2,67 @@
 static jint
 android_glCreateShaderProgramv
   (JNIEnv *_env, jobject _this, jint type, jobjectArray strings) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    GLsizei _count;
+    const GLchar** _strings = NULL;
+    jstring* _jstrings = NULL;
+    GLuint _returnValue = 0;
 
-    jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented");
-    return 0;
+    if (!strings) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "strings == null";
+        goto exit;
+    }
+
+    _count = _env->GetArrayLength(strings);
+
+    _strings = (const GLchar**) calloc(_count, sizeof(const GLchar*));
+    if (!_strings) {
+        _exception = 1;
+        _exceptionType = "java/lang/OutOfMemoryError";
+        _exceptionMessage = "out of memory";
+        goto exit;
+    }
+
+    _jstrings = (jstring*) calloc(_count, sizeof(jstring));
+    if (!_jstrings) {
+        _exception = 1;
+        _exceptionType = "java/lang/OutOfMemoryError";
+        _exceptionMessage = "out of memory";
+        goto exit;
+    }
+
+    for(int i = 0; i < _count; i++) {
+        _jstrings[i] = (jstring) _env->GetObjectArrayElement(strings, i);
+        if (!_jstrings[i]) {
+            _exception = 1;
+            _exceptionType = "java/lang/IllegalArgumentException";
+            _exceptionMessage = "strings == null";
+            goto exit;
+        }
+        _strings[i] = _env->GetStringUTFChars(_jstrings[i], 0);
+    }
+
+    _returnValue = glCreateShaderProgramv((GLenum)type, _count, _strings);
+exit:
+    if (_strings && _jstrings) {
+        for(int i = 0; i < _count; i++) {
+            if (_strings[i] && _jstrings[i]) {
+                _env->ReleaseStringUTFChars(_jstrings[i], _strings[i]);
+            }
+        }
+    }
+    if (_strings) {
+        free(_strings);
+    }
+    if (_jstrings) {
+        free(_jstrings);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+    return (jint)_returnValue;
 }
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index f91dac5..66ef4eb 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -1278,6 +1278,9 @@
 }
 
 int SensorService::getNumEventsForSensorType(int sensor_event_type) {
+    if (sensor_event_type >= SENSOR_TYPE_DEVICE_PRIVATE_BASE) {
+        return 16;
+    }
     switch (sensor_event_type) {
         case SENSOR_TYPE_ROTATION_VECTOR:
         case SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR:
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index e0d7339..5ba387d 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -322,7 +322,6 @@
     mNumResyncSamples = 0;
     mFirstResyncSample = 0;
     mNumResyncSamplesSincePresent = 0;
-    mNumPresentWithoutResyncSamples = 0;
     resetErrorLocked();
 }
 
@@ -347,15 +346,6 @@
 
     updateErrorLocked();
 
-    // This is a workaround for b/25845510.
-    // If we have no resync samples after many presents, something is wrong with
-    // HW vsync. Tell SF to disable HW vsync now and re-enable it next time.
-    if (mNumResyncSamples == 0 &&
-        mNumPresentWithoutResyncSamples++ > MAX_PRESENT_WITHOUT_RESYNC_SAMPLES) {
-        mNumPresentWithoutResyncSamples = 0;
-        return false;
-    }
-
     return !mModelUpdated || mError > kErrorThreshold;
 }
 
@@ -364,7 +354,6 @@
 
     mModelUpdated = false;
     mNumResyncSamples = 0;
-    mNumPresentWithoutResyncSamples = 0;
 }
 
 bool DispSync::addResyncSample(nsecs_t timestamp) {
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index 1ee0865..a8524b9 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -140,7 +140,6 @@
     enum { MIN_RESYNC_SAMPLES_FOR_UPDATE = 3 };
     enum { NUM_PRESENT_SAMPLES = 8 };
     enum { MAX_RESYNC_SAMPLES_WITHOUT_PRESENT = 4 };
-    enum { MAX_PRESENT_WITHOUT_RESYNC_SAMPLES = 8 };
 
     // mPeriod is the computed period of the modeled vsync events in
     // nanoseconds.
@@ -169,7 +168,6 @@
     size_t mFirstResyncSample;
     size_t mNumResyncSamples;
     int mNumResyncSamplesSincePresent;
-    int mNumPresentWithoutResyncSamples;
 
     // These member variables store information about the present fences used
     // to validate the currently computed model.
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 04256e1..42d0810 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -116,6 +116,7 @@
 
     mCurrentState.active.w = w;
     mCurrentState.active.h = h;
+    mCurrentState.active.transform.set(0, 0);
     mCurrentState.active.crop.makeInvalid();
     mCurrentState.z = 0;
 #ifdef USE_HWC2
@@ -126,7 +127,6 @@
     mCurrentState.layerStack = 0;
     mCurrentState.flags = layerFlags;
     mCurrentState.sequence = 0;
-    mCurrentState.transform.set(0, 0);
     mCurrentState.requested = mCurrentState.active;
 
     // drawing state & current state are identical
@@ -165,6 +165,11 @@
 }
 
 Layer::~Layer() {
+  sp<Client> c(mClientRef.promote());
+    if (c != 0) {
+        c->detachLayer(this);
+    }
+
     for (auto& point : mRemoteSyncPoints) {
         point->setTransactionApplied();
     }
@@ -260,10 +265,6 @@
 // the layer has been remove from the current state list (and just before
 // it's removed from the drawing state list)
 void Layer::onRemoved() {
-    sp<Client> c(mClientRef.promote());
-    if (c != 0) {
-        c->detachLayer(this);
-    }
     mSurfaceFlingerConsumer->abandon();
 }
 
@@ -399,9 +400,9 @@
         activeCrop = s.active.crop;
     }
 
-    activeCrop = s.transform.transform(activeCrop);
+    activeCrop = s.active.transform.transform(activeCrop);
     activeCrop.intersect(hw->getViewport(), &activeCrop);
-    activeCrop = s.transform.inverse().transform(activeCrop);
+    activeCrop = s.active.transform.inverse().transform(activeCrop);
 
     // This needs to be here as transform.transform(Rect) computes the
     // transformed rect and then takes the bounding box of the result before
@@ -534,13 +535,13 @@
     Region activeTransparentRegion(s.activeTransparentRegion);
     if (!s.active.crop.isEmpty()) {
         Rect activeCrop(s.active.crop);
-        activeCrop = s.transform.transform(activeCrop);
+        activeCrop = s.active.transform.transform(activeCrop);
 #ifdef USE_HWC2
         activeCrop.intersect(displayDevice->getViewport(), &activeCrop);
 #else
         activeCrop.intersect(hw->getViewport(), &activeCrop);
 #endif
-        activeCrop = s.transform.inverse().transform(activeCrop);
+        activeCrop = s.active.transform.inverse().transform(activeCrop);
         // This needs to be here as transform.transform(Rect) computes the
         // transformed rect and then takes the bounding box of the result before
         // returning. This means
@@ -557,7 +558,7 @@
         activeTransparentRegion.orSelf(Rect(activeCrop.right, activeCrop.top,
                 s.active.w, activeCrop.bottom));
     }
-    Rect frame(s.transform.transform(computeBounds(activeTransparentRegion)));
+    Rect frame(s.active.transform.transform(computeBounds(activeTransparentRegion)));
 #ifdef USE_HWC2
     frame.intersect(displayDevice->getViewport(), &frame);
     const Transform& tr(displayDevice->getTransform());
@@ -603,7 +604,7 @@
      */
 
     const Transform bufferOrientation(mCurrentTransform);
-    Transform transform(tr * s.transform * bufferOrientation);
+    Transform transform(tr * s.active.transform * bufferOrientation);
 
     if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) {
         /*
@@ -779,7 +780,7 @@
     }
     // Subtract the transparent region and snap to the bounds
     Rect bounds = reduce(win, s.activeTransparentRegion);
-    Rect frame(s.transform.transform(bounds));
+    Rect frame(s.active.transform.transform(bounds));
     frame.intersect(displayDevice->getViewport(), &frame);
     auto& displayTransform(displayDevice->getTransform());
     auto position = displayTransform.transform(frame);
@@ -825,7 +826,7 @@
     }
     // subtract the transparent region and snap to the bounds
     Rect bounds = reduce(win, s.activeTransparentRegion);
-    Rect frame(s.transform.transform(bounds));
+    Rect frame(s.active.transform.transform(bounds));
     frame.intersect(hw->getViewport(), &frame);
     const Transform& tr(hw->getTransform());
     return Rect(tr.transform(frame));
@@ -1120,7 +1121,7 @@
 {
     const Layer::State& s(getDrawingState());
     const Transform tr(useIdentityTransform ?
-            hw->getTransform() : hw->getTransform() * s.transform);
+            hw->getTransform() : hw->getTransform() * s.active.transform);
     const uint32_t hw_h = hw->getHeight();
     Rect win(s.active.w, s.active.h);
     if (!s.active.crop.isEmpty()) {
@@ -1403,8 +1404,8 @@
         this->contentDirty = true;
 
         // we may use linear filtering, if the matrix scales us
-        const uint8_t type = c.transform.getType();
-        mNeedsFiltering = (!c.transform.preserveRects() ||
+        const uint8_t type = c.active.transform.getType();
+        mNeedsFiltering = (!c.active.transform.preserveRects() ||
                 (type >= Transform::SCALE));
     }
 
@@ -1426,10 +1427,10 @@
 }
 
 bool Layer::setPosition(float x, float y) {
-    if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y)
+    if (mCurrentState.requested.transform.tx() == x && mCurrentState.requested.transform.ty() == y)
         return false;
     mCurrentState.sequence++;
-    mCurrentState.transform.set(x, y);
+    mCurrentState.requested.transform.set(x, y);
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
@@ -1467,7 +1468,7 @@
 }
 bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix) {
     mCurrentState.sequence++;
-    mCurrentState.transform.set(
+    mCurrentState.requested.transform.set(
             matrix.dsdx, matrix.dsdy, matrix.dtdx, matrix.dtdy);
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
@@ -1632,7 +1633,7 @@
         recomputeVisibleRegions = true;
 
         const State& s(getDrawingState());
-        return s.transform.transform(Region(Rect(s.active.w, s.active.h)));
+        return s.active.transform.transform(Region(Rect(s.active.w, s.active.h)));
     }
 
     Region outDirtyRegion;
@@ -1938,7 +1939,7 @@
         Region dirtyRegion(Rect(s.active.w, s.active.h));
 
         // transform the dirty region to window-manager space
-        outDirtyRegion = (s.transform.transform(dirtyRegion));
+        outDirtyRegion = (s.active.transform.transform(dirtyRegion));
     }
     return outDirtyRegion;
 }
@@ -2000,13 +2001,13 @@
             "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n"
 #endif
             "      client=%p\n",
-            s.layerStack, s.z, s.transform.tx(), s.transform.ty(), s.active.w, s.active.h,
+            s.layerStack, s.z, s.active.transform.tx(), s.active.transform.ty(), s.active.w, s.active.h,
             s.active.crop.left, s.active.crop.top,
             s.active.crop.right, s.active.crop.bottom,
             isOpaque(s), contentDirty,
             s.alpha, s.flags,
-            s.transform[0][0], s.transform[0][1],
-            s.transform[1][0], s.transform[1][1],
+            s.active.transform[0][0], s.active.transform[0][1],
+            s.active.transform[1][0], s.active.transform[1][1],
             client.get());
 
     sp<const GraphicBuffer> buf0(mActiveBuffer);
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 26e1adb..b0088e6 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -94,6 +94,8 @@
         uint32_t w;
         uint32_t h;
         Rect crop;
+        Transform transform;
+
         inline bool operator ==(const Geometry& rhs) const {
             return (w == rhs.w && h == rhs.h && crop == rhs.crop);
         }
@@ -116,7 +118,6 @@
         uint8_t mask;
         uint8_t reserved[2];
         int32_t sequence; // changes when visible regions can change
-        Transform transform;
         bool modified;
 
         // If set, defers this state update until the Layer identified by handle
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 0a3534f..3a0e21f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1563,7 +1563,7 @@
                 //       compute the actual visible region
                 // TODO: we could cache the transformed region
                 const Layer::State& s(layer->getDrawingState());
-                Region visibleReg = s.transform.transform(
+                Region visibleReg = s.active.transform.transform(
                         Region(Rect(s.active.w, s.active.h)));
                 invalidateLayerStack(s.layerStack, visibleReg);
             }
@@ -1666,12 +1666,12 @@
         // handle hidden surfaces by setting the visible region to empty
         if (CC_LIKELY(layer->isVisible())) {
             const bool translucent = !layer->isOpaque(s);
-            Rect bounds(s.transform.transform(layer->computeBounds()));
+            Rect bounds(s.active.transform.transform(layer->computeBounds()));
             visibleRegion.set(bounds);
             if (!visibleRegion.isEmpty()) {
                 // Remove the transparent area from the visible region
                 if (translucent) {
-                    const Transform tr(s.transform);
+                    const Transform tr(s.active.transform);
                     if (tr.transformed()) {
                         if (tr.preserveRects()) {
                             // transform the transparent region
@@ -1687,7 +1687,7 @@
                 }
 
                 // compute the opaque region
-                const int32_t layerOrientation = s.transform.getOrientation();
+                const int32_t layerOrientation = s.active.transform.getOrientation();
                 if (s.alpha == 1.0f && !translucent &&
                         ((layerOrientation & Transform::ROT_INVALID) == false)) {
                     // the opaque region is the layer's footprint
@@ -3440,14 +3440,18 @@
                     } else {
                         ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES error while taking screenshot");
                         result = INVALID_OPERATION;
+                        window->cancelBuffer(window, buffer, syncFd);
+                        buffer = NULL;
                     }
                     // destroy our image
                     eglDestroyImageKHR(mEGLDisplay, image);
                 } else {
                     result = BAD_VALUE;
                 }
-                // queueBuffer takes ownership of syncFd
-                result = window->queueBuffer(window, buffer, syncFd);
+                if (buffer) {
+                    // queueBuffer takes ownership of syncFd
+                    result = window->queueBuffer(window, buffer, syncFd);
+                }
             }
         } else {
             result = BAD_VALUE;
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 737cc82..d864874 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -1593,7 +1593,7 @@
                 //       compute the actual visible region
                 // TODO: we could cache the transformed region
                 const Layer::State& s(layer->getDrawingState());
-                Region visibleReg = s.transform.transform(
+                Region visibleReg = s.active.transform.transform(
                         Region(Rect(s.active.w, s.active.h)));
                 invalidateLayerStack(s.layerStack, visibleReg);
             }
@@ -1707,12 +1707,12 @@
         // handle hidden surfaces by setting the visible region to empty
         if (CC_LIKELY(layer->isVisible())) {
             const bool translucent = !layer->isOpaque(s);
-            Rect bounds(s.transform.transform(layer->computeBounds()));
+            Rect bounds(s.active.transform.transform(layer->computeBounds()));
             visibleRegion.set(bounds);
             if (!visibleRegion.isEmpty()) {
                 // Remove the transparent area from the visible region
                 if (translucent) {
-                    const Transform tr(s.transform);
+                    const Transform tr(s.active.transform);
                     if (tr.transformed()) {
                         if (tr.preserveRects()) {
                             // transform the transparent region
@@ -1728,7 +1728,7 @@
                 }
 
                 // compute the opaque region
-                const int32_t layerOrientation = s.transform.getOrientation();
+                const int32_t layerOrientation = s.active.transform.getOrientation();
                 if (s.alpha==255 && !translucent &&
                         ((layerOrientation & Transform::ROT_INVALID) == false)) {
                     // the opaque region is the layer's footprint
@@ -3478,14 +3478,18 @@
                     } else {
                         ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES error while taking screenshot");
                         result = INVALID_OPERATION;
+                        window->cancelBuffer(window, buffer, syncFd);
+                        buffer = NULL;
                     }
                     // destroy our image
                     eglDestroyImageKHR(mEGLDisplay, image);
                 } else {
                     result = BAD_VALUE;
                 }
-                // queueBuffer takes ownership of syncFd
-                result = window->queueBuffer(window, buffer, syncFd);
+                if (buffer) {
+                    // queueBuffer takes ownership of syncFd
+                    result = window->queueBuffer(window, buffer, syncFd);
+                }
             }
         } else {
             result = BAD_VALUE;
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index e77952a..aec0fd0 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -394,7 +394,7 @@
     }
 }
 
-const char* LayerRef::GetName() {
+const char* LayerRef::GetName() const {
     return layer_->properties.layerName;
 }
 
diff --git a/vulkan/libvulkan/loader.cpp b/vulkan/libvulkan/loader.cpp
index fc60f35..eba58c6 100644
--- a/vulkan/libvulkan/loader.cpp
+++ b/vulkan/libvulkan/loader.cpp
@@ -265,6 +265,7 @@
 
     const VkAllocationCallbacks* alloc;
     uint32_t num_physical_devices;
+    VkPhysicalDevice physical_devices_top[kMaxPhysicalDevices];
     VkPhysicalDevice physical_devices[kMaxPhysicalDevices];
     DeviceExtensionSet physical_device_driver_extensions[kMaxPhysicalDevices];
 
@@ -450,6 +451,51 @@
     return VK_SUCCESS;
 }
 
+template <class TCreateInfo, class TObject>
+bool AddLayersToCreateInfo(TCreateInfo& local_create_info,
+                           const TObject& object,
+                           const VkAllocationCallbacks* alloc,
+                           bool& allocatedMemory) {
+    // This should never happen and means there is a likely a bug in layer
+    // tracking
+    if (object->active_layers.size() < local_create_info.enabledLayerCount) {
+        ALOGE("Total number of layers is less than those enabled by the app!");
+        return false;
+    }
+    // Check if the total number of layers enabled is greater than those
+    // enabled by the application. If it is then we have system enabled
+    // layers which need to be added to the list of layers passed in through
+    // create.
+    if (object->active_layers.size() > local_create_info.enabledLayerCount) {
+        void* mem = alloc->pfnAllocation(
+            alloc->pUserData, object->active_layers.size() * sizeof(char*),
+            alignof(char*), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
+        if (mem) {
+            local_create_info.enabledLayerCount = 0;
+            const char** names = static_cast<const char**>(mem);
+            for (const auto& layer : object->active_layers) {
+                const char* name = layer.GetName();
+                names[local_create_info.enabledLayerCount++] = name;
+            }
+            local_create_info.ppEnabledLayerNames = names;
+        } else {
+            ALOGE("System layers cannot be enabled: memory allocation failed");
+            return false;
+        }
+        allocatedMemory = true;
+    } else {
+        allocatedMemory = false;
+    }
+    return true;
+}
+
+template <class T>
+void FreeAllocatedLayerCreateInfo(T& local_create_info,
+                                  const VkAllocationCallbacks* alloc) {
+    alloc->pfnFree(alloc->pUserData,
+                   const_cast<char**>(local_create_info.ppEnabledLayerNames));
+}
+
 template <class TCreateInfo>
 bool AddExtensionToCreateInfo(TCreateInfo& local_create_info,
                               const char* extension_name,
@@ -459,7 +505,7 @@
     void* mem = alloc->pfnAllocation(
         alloc->pUserData,
         local_create_info.enabledExtensionCount * sizeof(char*), alignof(char*),
-        VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+        VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
     if (mem) {
         const char** enabled_extensions = static_cast<const char**>(mem);
         for (uint32_t i = 0; i < extension_count; ++i) {
@@ -469,17 +515,16 @@
         enabled_extensions[extension_count] = extension_name;
         local_create_info.ppEnabledExtensionNames = enabled_extensions;
     } else {
-        ALOGW("%s extension cannot be enabled: memory allocation failed",
+        ALOGE("%s extension cannot be enabled: memory allocation failed",
               extension_name);
-        local_create_info.enabledExtensionCount--;
         return false;
     }
     return true;
 }
 
 template <class T>
-void FreeAllocatedCreateInfo(T& local_create_info,
-                             const VkAllocationCallbacks* alloc) {
+void FreeAllocatedExtensionCreateInfo(T& local_create_info,
+                                      const VkAllocationCallbacks* alloc) {
     alloc->pfnFree(
         alloc->pUserData,
         const_cast<char**>(local_create_info.ppEnabledExtensionNames));
@@ -528,17 +573,24 @@
     return create_info;
 }
 
-// Separate out cleaning up the layers and instance storage
-// to avoid code duplication in the many failure cases in
-// in CreateInstance_Top
-void TeardownInstance(
-    VkInstance vkinstance,
-    const VkAllocationCallbacks* /* allocator */) {
-    Instance& instance = GetDispatchParent(vkinstance);
-    instance.active_layers.clear();
-    const VkAllocationCallbacks* alloc = instance.alloc;
-    instance.~Instance();
-    alloc->pfnFree(alloc->pUserData, &instance);
+// Clean up and deallocate an Instance; called from both the failure paths in
+// CreateInstance_Top as well as from DestroyInstance_Top. This function does
+// not call down the dispatch chain; that should be done before calling this
+// function, iff the lower vkCreateInstance call has been made and returned
+// successfully.
+void DestroyInstance(Instance* instance,
+                     const VkAllocationCallbacks* allocator) {
+    if (instance->message) {
+        PFN_vkDestroyDebugReportCallbackEXT destroy_debug_report_callback;
+        destroy_debug_report_callback =
+            reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(
+                GetInstanceProcAddr_Top(instance->handle,
+                                        "vkDestroyDebugReportCallbackEXT"));
+        destroy_debug_report_callback(instance->handle, instance->message,
+                                      allocator);
+    }
+    instance->~Instance();
+    allocator->pfnFree(allocator->pUserData, instance);
 }
 
 }  // anonymous namespace
@@ -941,14 +993,7 @@
     if (instance.drv.instance != VK_NULL_HANDLE &&
         instance.drv.dispatch.DestroyInstance) {
         instance.drv.dispatch.DestroyInstance(instance.drv.instance, allocator);
-    }
-    if (instance.message) {
-        PFN_vkDestroyDebugReportCallbackEXT destroy_debug_report_callback;
-        destroy_debug_report_callback =
-            reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(
-                vkGetInstanceProcAddr(vkinstance,
-                                      "vkDestroyDebugReportCallbackEXT"));
-        destroy_debug_report_callback(vkinstance, instance.message, allocator);
+        instance.drv.instance = VK_NULL_HANDLE;
     }
 }
 
@@ -1042,7 +1087,7 @@
         ALOGV("  no layer");
         Instance& instance = GetDispatchParent(gpu);
         size_t gpu_idx = 0;
-        while (instance.physical_devices[gpu_idx] != gpu)
+        while (instance.physical_devices_top[gpu_idx] != gpu)
             gpu_idx++;
         const DeviceExtensionSet driver_extensions =
             instance.physical_device_driver_extensions[gpu_idx];
@@ -1093,8 +1138,7 @@
 
     result = ActivateAllLayers(create_info, instance, instance);
     if (result != VK_SUCCESS) {
-        DestroyInstance_Bottom(instance->handle, allocator);
-        TeardownInstance(instance->handle, allocator);
+        DestroyInstance(instance, allocator);
         return result;
     }
 
@@ -1115,8 +1159,7 @@
             sizeof(VkLayerInstanceLink) * instance->active_layers.size()));
         if (!layer_instance_link_info) {
             ALOGE("Failed to alloc Instance objects for layers");
-            DestroyInstance_Bottom(instance->handle, allocator);
-            TeardownInstance(instance->handle, allocator);
+            DestroyInstance(instance, allocator);
             return VK_ERROR_OUT_OF_HOST_MEMORY;
         }
 
@@ -1143,8 +1186,7 @@
         reinterpret_cast<PFN_vkCreateInstance>(
             next_gipa(VK_NULL_HANDLE, "vkCreateInstance"));
     if (!create_instance) {
-        DestroyInstance_Bottom(instance->handle, allocator);
-        TeardownInstance(instance->handle, allocator);
+        DestroyInstance(instance, allocator);
         return VK_ERROR_INITIALIZATION_FAILED;
     }
     VkLayerInstanceCreateInfo instance_create_info;
@@ -1164,20 +1206,34 @@
         enable_callback =
             property_get_bool("debug.vulkan.enable_callback", false);
         if (enable_callback) {
-            enable_callback = AddExtensionToCreateInfo(
-                local_create_info, "VK_EXT_debug_report", instance->alloc);
+            if (!AddExtensionToCreateInfo(local_create_info,
+                                          "VK_EXT_debug_report", allocator)) {
+                DestroyInstance(instance, allocator);
+                return VK_ERROR_INITIALIZATION_FAILED;
+            }
         }
     }
+    bool allocatedLayerMem;
+    if (!AddLayersToCreateInfo(local_create_info, instance, allocator,
+                               allocatedLayerMem)) {
+        if (enable_callback) {
+            FreeAllocatedExtensionCreateInfo(local_create_info, allocator);
+        }
+        DestroyInstance(instance, allocator);
+        return VK_ERROR_INITIALIZATION_FAILED;
+    }
 
     result = create_instance(&local_create_info, allocator, &local_instance);
 
+    if (allocatedLayerMem) {
+        FreeAllocatedLayerCreateInfo(local_create_info, allocator);
+    }
     if (enable_callback) {
-        FreeAllocatedCreateInfo(local_create_info, allocator);
+        FreeAllocatedExtensionCreateInfo(local_create_info, allocator);
     }
 
     if (result != VK_SUCCESS) {
-        DestroyInstance_Bottom(instance->handle, allocator);
-        TeardownInstance(instance->handle, allocator);
+        DestroyInstance(instance, allocator);
         return result;
     }
 
@@ -1189,14 +1245,31 @@
         ALOGV("Failed to initialize instance dispatch table");
         PFN_vkDestroyInstance destroy_instance =
             reinterpret_cast<PFN_vkDestroyInstance>(
-                next_gipa(VK_NULL_HANDLE, "vkDestroyInstance"));
+                next_gipa(local_instance, "vkDestroyInstance"));
         if (!destroy_instance) {
             ALOGD("Loader unable to find DestroyInstance");
             return VK_ERROR_INITIALIZATION_FAILED;
         }
         destroy_instance(local_instance, allocator);
-        DestroyInstance_Bottom(instance->handle, allocator);
-        TeardownInstance(instance->handle, allocator);
+        DestroyInstance(instance, allocator);
+        return VK_ERROR_INITIALIZATION_FAILED;
+    }
+
+    // Capture the physical devices from the top of the
+    // chain in case it has been wrapped by a layer.
+    uint32_t num_physical_devices = 0;
+    result = instance_dispatch.EnumeratePhysicalDevices(
+        local_instance, &num_physical_devices, nullptr);
+    if (result != VK_SUCCESS) {
+        DestroyInstance(instance, allocator);
+        return VK_ERROR_INITIALIZATION_FAILED;
+    }
+    num_physical_devices = std::min(num_physical_devices, kMaxPhysicalDevices);
+    result = instance_dispatch.EnumeratePhysicalDevices(
+        local_instance, &num_physical_devices,
+        instance->physical_devices_top);
+    if (result != VK_SUCCESS) {
+        DestroyInstance(instance, allocator);
         return VK_ERROR_INITIALIZATION_FAILED;
     }
     *instance_out = local_instance;
@@ -1244,9 +1317,10 @@
                          const VkAllocationCallbacks* allocator) {
     if (!vkinstance)
         return;
+    if (!allocator)
+        allocator = &kDefaultAllocCallbacks;
     GetDispatchTable(vkinstance).DestroyInstance(vkinstance, allocator);
-
-    TeardownInstance(vkinstance, allocator);
+    DestroyInstance(&(GetDispatchParent(vkinstance)), allocator);
 }
 
 VKAPI_ATTR
@@ -1287,10 +1361,6 @@
         return result;
     }
 
-    size_t gpu_idx = 0;
-    while (instance.physical_devices[gpu_idx] != gpu)
-        gpu_idx++;
-
     uint32_t activated_layers = 0;
     VkLayerDeviceCreateInfo chain_info;
     VkLayerDeviceLink* layer_device_link_info = nullptr;
@@ -1337,7 +1407,7 @@
     }
 
     PFN_vkCreateDevice create_device = reinterpret_cast<PFN_vkCreateDevice>(
-        next_gipa(VK_NULL_HANDLE, "vkCreateDevice"));
+        next_gipa(instance.handle, "vkCreateDevice"));
     if (!create_device) {
         ALOGE("Unable to find vkCreateDevice for driver");
         DestroyDevice(device);
@@ -1355,8 +1425,19 @@
     device_create_info.pNext = local_create_info.pNext;
     local_create_info.pNext = &device_create_info;
 
+    bool allocatedLayerMem;
+    if (!AddLayersToCreateInfo(local_create_info, device, allocator,
+                               allocatedLayerMem)) {
+        DestroyDevice(device);
+        return VK_ERROR_INITIALIZATION_FAILED;
+    }
+
     result = create_device(gpu, &local_create_info, allocator, &local_device);
 
+    if (allocatedLayerMem) {
+        FreeAllocatedLayerCreateInfo(local_create_info, allocator);
+    }
+
     if (result != VK_SUCCESS) {
         DestroyDevice(device);
         return result;
@@ -1374,7 +1455,7 @@
         ALOGV("Failed to initialize device dispatch table");
         PFN_vkDestroyDevice destroy_device =
             reinterpret_cast<PFN_vkDestroyDevice>(
-                next_gipa(VK_NULL_HANDLE, "vkDestroyDevice"));
+                next_gipa(instance.handle, "vkDestroyDevice"));
         ALOG_ASSERT(destroy_device != nullptr,
                     "Loader unable to find DestroyDevice");
         destroy_device(local_device, allocator);
diff --git a/vulkan/libvulkan/loader.h b/vulkan/libvulkan/loader.h
index 77c8ebe..cec0ff6 100644
--- a/vulkan/libvulkan/loader.h
+++ b/vulkan/libvulkan/loader.h
@@ -153,7 +153,7 @@
     LayerRef(const LayerRef&) = delete;
     LayerRef& operator=(const LayerRef&) = delete;
 
-    const char* GetName();
+    const char* GetName() const;
     uint32_t GetSpecVersion();
 
     // provides bool-like behavior