[automerger] DO NOT MERGE Remove window obscurement information. am: edac95e737 am: dda3bdf8a8 am: 3cd049ca28 skipped: 2564b9fdf5 am: 67c9dace8b am: 09c59e7f69 am: a31fb53edd am: b63caaf102 skipped: c2116af15c
am: dfe44a12ab

Change-Id: I90f59bd979e33e39a9f9cfa8ca8f58d93a00994f
diff --git a/cmds/atrace/Android.bp b/cmds/atrace/Android.bp
index 6c5869a..abf7b06 100644
--- a/cmds/atrace/Android.bp
+++ b/cmds/atrace/Android.bp
@@ -7,15 +7,16 @@
     shared_libs: [
         "libbinder",
         "libhwbinder",
-        "android.hidl.manager@1.0",
         "libhidlbase",
         "libhidltransport",
         "liblog",
-        "libcutils",
         "libutils",
         "libz",
         "libbase",
     ],
+    static_libs: [
+        "libpdx_default_transport",
+    ],
 
     init_rc: ["atrace.rc"],
 
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 47e04e7..2d9a98c 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -26,7 +26,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/sendfile.h>
 #include <time.h>
 #include <unistd.h>
 #include <zlib.h>
@@ -40,18 +39,21 @@
 
 #include <android/hidl/manager/1.0/IServiceManager.h>
 #include <hidl/ServiceManagement.h>
-#include <cutils/properties.h>
 
+#include <pdx/default_transport/service_utility.h>
 #include <utils/String8.h>
 #include <utils/Timers.h>
 #include <utils/Tokenizer.h>
 #include <utils/Trace.h>
 #include <android-base/file.h>
+#include <android-base/macros.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
 
 using namespace android;
+using pdx::default_transport::ServiceUtility;
 
 using std::string;
-#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
 
 #define MAX_SYS_FILES 10
 #define MAX_PACKAGES 16
@@ -61,6 +63,7 @@
 const char* k_traceAppsNumberProperty = "debug.atrace.app_number";
 const char* k_traceAppsPropertyTemplate = "debug.atrace.app_%d";
 const char* k_coreServiceCategory = "core_services";
+const char* k_pdxServiceCategory = "pdx";
 const char* k_coreServicesProp = "ro.atrace.core.services";
 
 typedef enum { OPT, REQ } requiredness  ;
@@ -89,7 +92,9 @@
 
 /* Tracing categories */
 static const TracingCategory k_categories[] = {
-    { "gfx",        "Graphics",         ATRACE_TAG_GRAPHICS, { } },
+    { "gfx",        "Graphics",         ATRACE_TAG_GRAPHICS, {
+        { OPT,      "events/mdss/enable" },
+    } },
     { "input",      "Input",            ATRACE_TAG_INPUT, { } },
     { "view",       "View System",      ATRACE_TAG_VIEW, { } },
     { "webview",    "WebView",          ATRACE_TAG_WEBVIEW, { } },
@@ -112,6 +117,7 @@
     { "network",    "Network",          ATRACE_TAG_NETWORK, { } },
     { "adb",        "ADB",              ATRACE_TAG_ADB, { } },
     { k_coreServiceCategory, "Core services", 0, { } },
+    { k_pdxServiceCategory, "PDX services", 0, { } },
     { "sched",      "CPU Scheduling",   0, {
         { REQ,      "events/sched/sched_switch/enable" },
         { REQ,      "events/sched/sched_wakeup/enable" },
@@ -174,6 +180,7 @@
         { REQ,      "events/vmscan/mm_vmscan_direct_reclaim_end/enable" },
         { REQ,      "events/vmscan/mm_vmscan_kswapd_wake/enable" },
         { REQ,      "events/vmscan/mm_vmscan_kswapd_sleep/enable" },
+        { REQ,      "events/lowmemorykiller/enable" },
     } },
     { "regulators",  "Voltage and Current Regulators", 0, {
         { REQ,      "events/regulator/enable" },
@@ -181,11 +188,12 @@
     { "binder_driver", "Binder Kernel driver", 0, {
         { REQ,      "events/binder/binder_transaction/enable" },
         { REQ,      "events/binder/binder_transaction_received/enable" },
+        { OPT,      "events/binder/binder_set_priority/enable" },
     } },
     { "binder_lock", "Binder global lock trace", 0, {
-        { REQ,      "events/binder/binder_lock/enable" },
-        { REQ,      "events/binder/binder_locked/enable" },
-        { REQ,      "events/binder/binder_unlock/enable" },
+        { OPT,      "events/binder/binder_lock/enable" },
+        { OPT,      "events/binder/binder_locked/enable" },
+        { OPT,      "events/binder/binder_unlock/enable" },
     } },
     { "pagecache",  "Page cache", 0, {
         { REQ,      "events/filemap/enable" },
@@ -205,8 +213,9 @@
 static const char* g_outputFile = nullptr;
 
 /* Global state */
+static bool g_tracePdx = false;
 static bool g_traceAborted = false;
-static bool g_categoryEnables[NELEM(k_categories)] = {};
+static bool g_categoryEnables[arraysize(k_categories)] = {};
 static std::string g_traceFolder;
 
 /* Sys file paths */
@@ -361,9 +370,11 @@
 static bool isCategorySupported(const TracingCategory& category)
 {
     if (strcmp(category.name, k_coreServiceCategory) == 0) {
-        char value[PROPERTY_VALUE_MAX];
-        property_get(k_coreServicesProp, value, "");
-        return strlen(value) != 0;
+        return !android::base::GetProperty(k_coreServicesProp, "").empty();
+    }
+
+    if (strcmp(category.name, k_pdxServiceCategory) == 0) {
+        return true;
     }
 
     bool ok = category.tags != 0;
@@ -378,7 +389,7 @@
                     ok = true;
                 }
             } else {
-                ok |= fileIsWritable(path);
+                ok = true;
             }
         }
     }
@@ -564,9 +575,8 @@
 // processes to pick up the new value.
 static bool setTagsProperty(uint64_t tags)
 {
-    char buf[PROPERTY_VALUE_MAX];
-    snprintf(buf, sizeof(buf), "%#" PRIx64, tags);
-    if (property_set(k_traceTagsProperty, buf) < 0) {
+    std::string value = android::base::StringPrintf("%#" PRIx64, tags);
+    if (!android::base::SetProperty(k_traceTagsProperty, value)) {
         fprintf(stderr, "error setting trace tags system property\n");
         return false;
     }
@@ -575,14 +585,13 @@
 
 static void clearAppProperties()
 {
-    char buf[PROPERTY_KEY_MAX];
     for (int i = 0; i < MAX_PACKAGES; i++) {
-        snprintf(buf, sizeof(buf), k_traceAppsPropertyTemplate, i);
-        if (property_set(buf, "") < 0) {
-            fprintf(stderr, "failed to clear system property: %s\n", buf);
+        std::string key = android::base::StringPrintf(k_traceAppsPropertyTemplate, i);
+        if (!android::base::SetProperty(key, "")) {
+            fprintf(stderr, "failed to clear system property: %s\n", key.c_str());
         }
     }
-    if (property_set(k_traceAppsNumberProperty, "") < 0) {
+    if (!android::base::SetProperty(k_traceAppsNumberProperty, "")) {
         fprintf(stderr, "failed to clear system property: %s",
               k_traceAppsNumberProperty);
     }
@@ -592,7 +601,6 @@
 // application-level tracing.
 static bool setAppCmdlineProperty(char* cmdline)
 {
-    char buf[PROPERTY_KEY_MAX];
     int i = 0;
     char* start = cmdline;
     while (start != NULL) {
@@ -606,9 +614,9 @@
             *end = '\0';
             end++;
         }
-        snprintf(buf, sizeof(buf), k_traceAppsPropertyTemplate, i);
-        if (property_set(buf, start) < 0) {
-            fprintf(stderr, "error setting trace app %d property to %s\n", i, buf);
+        std::string key = android::base::StringPrintf(k_traceAppsPropertyTemplate, i);
+        if (!android::base::SetProperty(key, start)) {
+            fprintf(stderr, "error setting trace app %d property to %s\n", i, key.c_str());
             clearAppProperties();
             return false;
         }
@@ -616,9 +624,9 @@
         i++;
     }
 
-    snprintf(buf, sizeof(buf), "%d", i);
-    if (property_set(k_traceAppsNumberProperty, buf) < 0) {
-        fprintf(stderr, "error setting trace app number property to %s\n", buf);
+    std::string value = android::base::StringPrintf("%d", i);
+    if (!android::base::SetProperty(k_traceAppsNumberProperty, value)) {
+        fprintf(stderr, "error setting trace app number property to %s\n", value.c_str());
         clearAppProperties();
         return false;
     }
@@ -628,7 +636,7 @@
 // Disable all /sys/ enable files.
 static bool disableKernelTraceEvents() {
     bool ok = true;
-    for (int i = 0; i < NELEM(k_categories); i++) {
+    for (size_t i = 0; i < arraysize(k_categories); i++) {
         const TracingCategory &c = k_categories[i];
         for (int j = 0; j < MAX_SYS_FILES; j++) {
             const char* path = c.sysfiles[j].path;
@@ -716,7 +724,7 @@
 
 static bool setCategoryEnable(const char* name, bool enable)
 {
-    for (int i = 0; i < NELEM(k_categories); i++) {
+    for (size_t i = 0; i < arraysize(k_categories); i++) {
         const TracingCategory& c = k_categories[i];
         if (strcmp(name, c.name) == 0) {
             if (isCategorySupported(c)) {
@@ -778,7 +786,7 @@
 
     // Set up the tags property.
     uint64_t tags = 0;
-    for (int i = 0; i < NELEM(k_categories); i++) {
+    for (size_t i = 0; i < arraysize(k_categories); i++) {
         if (g_categoryEnables[i]) {
             const TracingCategory &c = k_categories[i];
             tags |= c.tags;
@@ -787,31 +795,38 @@
     ok &= setTagsProperty(tags);
 
     bool coreServicesTagEnabled = false;
-    for (int i = 0; i < NELEM(k_categories); i++) {
+    for (size_t i = 0; i < arraysize(k_categories); i++) {
         if (strcmp(k_categories[i].name, k_coreServiceCategory) == 0) {
             coreServicesTagEnabled = g_categoryEnables[i];
         }
+
+        // Set whether to poke PDX services in this session.
+        if (strcmp(k_categories[i].name, k_pdxServiceCategory) == 0) {
+            g_tracePdx = g_categoryEnables[i];
+        }
     }
 
     std::string packageList(g_debugAppCmdLine);
     if (coreServicesTagEnabled) {
-        char value[PROPERTY_VALUE_MAX];
-        property_get(k_coreServicesProp, value, "");
         if (!packageList.empty()) {
             packageList += ",";
         }
-        packageList += value;
+        packageList += android::base::GetProperty(k_coreServicesProp, "");
     }
     ok &= setAppCmdlineProperty(&packageList[0]);
     ok &= pokeBinderServices();
     pokeHalServices();
 
+    if (g_tracePdx) {
+        ok &= ServiceUtility::PokeServices();
+    }
+
     // Disable all the sysfs enables.  This is done as a separate loop from
     // the enables to allow the same enable to exist in multiple categories.
     ok &= disableKernelTraceEvents();
 
     // Enable all the sysfs enables that are in an enabled category.
-    for (int i = 0; i < NELEM(k_categories); i++) {
+    for (size_t i = 0; i < arraysize(k_categories); i++) {
         if (g_categoryEnables[i]) {
             const TracingCategory &c = k_categories[i];
             for (int j = 0; j < MAX_SYS_FILES; j++) {
@@ -843,6 +858,10 @@
     clearAppProperties();
     pokeBinderServices();
 
+    if (g_tracePdx) {
+        ServiceUtility::PokeServices();
+    }
+
     // Set the options back to their defaults.
     setTraceOverwriteEnable(true);
     setTraceBufferSizeKB(1);
@@ -976,11 +995,16 @@
             fprintf(stderr, "error cleaning up zlib: %d\n", result);
         }
     } else {
-        ssize_t sent = 0;
-        while ((sent = sendfile(outFd, traceFD, NULL, 64*1024*1024)) > 0);
-        if (sent == -1) {
-            fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
-                    errno);
+        char buf[4096];
+        ssize_t rc;
+        while ((rc = TEMP_FAILURE_RETRY(read(traceFD, buf, sizeof(buf)))) > 0) {
+            if (!android::base::WriteFully(outFd, buf, rc)) {
+                fprintf(stderr, "error writing trace: %s\n", strerror(errno));
+                break;
+            }
+        }
+        if (rc == -1) {
+            fprintf(stderr, "error dumping trace: %s\n", strerror(errno));
         }
     }
 
@@ -1008,7 +1032,7 @@
 
 static void listSupportedCategories()
 {
-    for (int i = 0; i < NELEM(k_categories); i++) {
+    for (size_t i = 0; i < arraysize(k_categories); i++) {
         const TracingCategory& c = k_categories[i];
         if (isCategorySupported(c)) {
             printf("  %10s - %s\n", c.name, c.longname);
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index d538145..526fd19 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -53,6 +53,8 @@
     chown root shell /sys/kernel/tracing/events/binder/binder_locked/enable
     chown root shell /sys/kernel/debug/tracing/events/binder/binder_unlock/enable
     chown root shell /sys/kernel/tracing/events/binder/binder_unlock/enable
+    chown root shell /sys/kernel/debug/tracing/events/lowmemorykiller/enable
+    chown root shell /sys/kernel/tracing/events/lowmemorykiller/enable
 
     chown root shell /sys/kernel/debug/tracing/tracing_on
     chown root shell /sys/kernel/tracing/tracing_on
@@ -123,6 +125,8 @@
     chmod 0664 /sys/kernel/tracing/events/i2c/smbus_result/enable
     chmod 0664 /sys/kernel/debug/tracing/events/i2c/smbus_reply/enable
     chmod 0664 /sys/kernel/tracing/events/i2c/smbus_reply/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/lowmemorykiller/enable
+    chmod 0664 /sys/kernel/tracing/events/lowmemorykiller/enable
 
     # Tracing disabled by default
     write /sys/kernel/debug/tracing/tracing_on 0
diff --git a/cmds/bugreportz/Android.mk b/cmds/bugreportz/Android.mk
index 880bc75..10dda56 100644
--- a/cmds/bugreportz/Android.mk
+++ b/cmds/bugreportz/Android.mk
@@ -25,6 +25,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE := bugreportz_test
+LOCAL_COMPATIBILITY_SUITE := device-tests
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_CFLAGS := -Werror -Wall
diff --git a/cmds/bugreportz/AndroidTest.xml b/cmds/bugreportz/AndroidTest.xml
new file mode 100644
index 0000000..38b6276
--- /dev/null
+++ b/cmds/bugreportz/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<configuration description="Config for bugreportz_test">
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="bugreportz_test->/data/local/tmp/bugreportz_test" />
+    </target_preparer>
+    <option name="test-suite-tag" value="apct" />
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="bugreportz_test" />
+    </test>
+</configuration>
diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk
index a407ea2..a1b6a51 100644
--- a/cmds/dumpstate/Android.mk
+++ b/cmds/dumpstate/Android.mk
@@ -16,8 +16,8 @@
         utils.cpp
 COMMON_SHARED_LIBRARIES := \
         android.hardware.dumpstate@1.0 \
-        android.hidl.manager@1.0 \
         libhidlbase \
+        libhidltransport \
         libbase \
         libbinder \
         libcutils \
@@ -138,7 +138,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE := dumpstate_test_fixture
-
+LOCAL_COMPATIBILITY_SUITE := device-tests
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_CFLAGS := $(COMMON_LOCAL_CFLAGS)
diff --git a/cmds/dumpstate/AndroidTest.xml b/cmds/dumpstate/AndroidTest.xml
new file mode 100644
index 0000000..f189489
--- /dev/null
+++ b/cmds/dumpstate/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<configuration description="Config for dumpstate_test_fixture">
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="dumpstate_test_fixture->/data/local/tmp/dumpstate_test_fixture" />
+    </target_preparer>
+    <option name="test-suite-tag" value="apct" />
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="dumpstate_test_fixture" />
+    </test>
+</configuration>
diff --git a/cmds/dumpstate/DumpstateInternal.h b/cmds/dumpstate/DumpstateInternal.h
index 2f7704d..10db5d6 100644
--- a/cmds/dumpstate/DumpstateInternal.h
+++ b/cmds/dumpstate/DumpstateInternal.h
@@ -32,6 +32,12 @@
     ALOGI(__VA_ARGS__);
 #endif
 
+#ifndef MYLOGW
+#define MYLOGW(...)               \
+    fprintf(stderr, __VA_ARGS__); \
+    ALOGW(__VA_ARGS__);
+#endif
+
 #ifndef MYLOGE
 #define MYLOGE(...)               \
     fprintf(stderr, __VA_ARGS__); \
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index f84d86d..4161bd7 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -21,13 +21,9 @@
 #include <fcntl.h>
 #include <libgen.h>
 #include <limits.h>
-#include <memory>
-#include <regex>
-#include <set>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <string>
 #include <string.h>
 #include <sys/prctl.h>
 #include <sys/resource.h>
@@ -35,6 +31,11 @@
 #include <sys/time.h>
 #include <sys/wait.h>
 #include <unistd.h>
+#include <memory>
+#include <regex>
+#include <set>
+#include <string>
+#include <vector>
 
 #include <android-base/file.h>
 #include <android-base/properties.h>
@@ -71,6 +72,7 @@
 
 #define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
 #define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
+#define BLK_DEV_SYS_DIR "/sys/block"
 
 #define RAFT_DIR "/data/misc/raft"
 #define RECOVERY_DIR "/cache/recovery"
@@ -78,19 +80,29 @@
 #define LOGPERSIST_DATA_DIR "/data/misc/logd"
 #define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
 #define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
-#define TOMBSTONE_DIR "/data/tombstones"
-#define TOMBSTONE_FILE_PREFIX TOMBSTONE_DIR "/tombstone_"
-/* Can accomodate a tombstone number up to 9999. */
-#define TOMBSTONE_MAX_LEN (sizeof(TOMBSTONE_FILE_PREFIX) + 4)
-#define NUM_TOMBSTONES  10
 #define WLUTIL "/vendor/xbin/wlutil"
 
-typedef struct {
-  char name[TOMBSTONE_MAX_LEN];
-  int fd;
-} tombstone_data_t;
+// TODO(narayan): Since this information has to be kept in sync
+// with tombstoned, we should just put it in a common header.
+//
+// File: system/core/debuggerd/tombstoned/tombstoned.cpp
+static const std::string TOMBSTONE_DIR = "/data/tombstones/";
+static const std::string TOMBSTONE_FILE_PREFIX = "tombstone_";
+static const std::string ANR_DIR = "/data/anr/";
+static const std::string ANR_FILE_PREFIX = "anr_";
 
-static tombstone_data_t tombstone_data[NUM_TOMBSTONES];
+struct DumpData {
+    std::string name;
+    int fd;
+    time_t mtime;
+};
+
+static bool operator<(const DumpData& d1, const DumpData& d2) {
+    return d1.mtime > d2.mtime;
+}
+
+static std::unique_ptr<std::vector<DumpData>> tombstone_data;
+static std::unique_ptr<std::vector<DumpData>> anr_data;
 
 // TODO: temporary variables and functions used during C++ refactoring
 static Dumpstate& ds = Dumpstate::GetInstance();
@@ -111,7 +123,14 @@
 static const std::string ZIP_ROOT_DIR = "FS";
 
 // Must be hardcoded because dumpstate HAL implementation need SELinux access to it
-static const std::string kDumpstateBoardPath = "/bugreports/dumpstate_board.txt";
+static const std::string kDumpstateBoardPath = "/bugreports/";
+static const std::string kDumpstateBoardFiles[] = {
+    "dumpstate_board.txt",
+    // TODO: rename to dumpstate_board.bin once vendors can handle it
+    "modem_log_all.tar"
+};
+static const int NUM_OF_DUMPS = arraysize(kDumpstateBoardFiles);
+
 static const std::string kLsHalDebugPath = "/bugreports/dumpstate_lshal.txt";
 
 static constexpr char PROPERTY_EXTRA_OPTIONS[] = "dumpstate.options";
@@ -122,23 +141,79 @@
 
 static const CommandOptions AS_ROOT_20 = CommandOptions::WithTimeout(20).AsRoot().Build();
 
-/* 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. */
-static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) {
-    time_t thirty_minutes_ago = ds.now_ - 60 * 30;
-    for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
-        snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i);
-        int fd = TEMP_FAILURE_RETRY(open(data[i].name,
-                                         O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
-        struct stat st;
-        if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) && st.st_size > 0 &&
-            (ds.IsZipping() || st.st_mtime >= thirty_minutes_ago)) {
-            data[i].fd = fd;
-        } else {
-            close(fd);
-            data[i].fd = -1;
+/*
+ * Returns a vector of dump fds under |dir_path| with a given |file_prefix|.
+ * The returned vector is sorted by the mtimes of the dumps. If |limit_by_mtime|
+ * is set, the vector only contains files that were written in the last 30 minutes.
+ */
+static std::vector<DumpData>* GetDumpFds(const std::string& dir_path,
+                                         const std::string& file_prefix,
+                                         bool limit_by_mtime) {
+    const time_t thirty_minutes_ago = ds.now_ - 60 * 30;
+
+    std::unique_ptr<std::vector<DumpData>> dump_data(new std::vector<DumpData>());
+    std::unique_ptr<DIR, decltype(&closedir)> dump_dir(opendir(dir_path.c_str()), closedir);
+
+    struct dirent* entry = nullptr;
+    while ((entry = readdir(dump_dir.get()))) {
+        if (entry->d_type != DT_REG) {
+            continue;
         }
+
+        const std::string base_name(entry->d_name);
+        if (base_name.find(file_prefix) != 0) {
+            continue;
+        }
+
+        const std::string abs_path = dir_path + base_name;
+        android::base::unique_fd fd(
+            TEMP_FAILURE_RETRY(open(abs_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)));
+        if (fd == -1) {
+            MYLOGW("Unable to open dump file: %s %s\n", abs_path.c_str(), strerror(errno));
+            break;
+        }
+
+        struct stat st = {};
+        if (fstat(fd, &st) == -1) {
+            MYLOGW("Unable to stat dump file: %s %s\n", abs_path.c_str(), strerror(errno));
+            continue;
+        }
+
+        if (limit_by_mtime && st.st_mtime >= thirty_minutes_ago) {
+            MYLOGI("Excluding stale dump file: %s\n", abs_path.c_str());
+            continue;
+        }
+
+        DumpData data = {.name = abs_path, .fd = fd.release(), .mtime = st.st_mtime};
+
+        dump_data->push_back(data);
     }
+
+    std::sort(dump_data->begin(), dump_data->end());
+
+    return dump_data.release();
+}
+
+static bool AddDumps(const std::vector<DumpData>::const_iterator start,
+                     const std::vector<DumpData>::const_iterator end,
+                     const char* type_name, const bool add_to_zip) {
+    bool dumped = false;
+    for (auto it = start; it != end; ++it) {
+        const std::string& name = it->name;
+        const int fd = it->fd;
+        dumped = true;
+        if (ds.IsZipping() && add_to_zip) {
+            if (!ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd)) {
+                MYLOGE("Unable to add %s %s to zip file\n", name.c_str(), type_name);
+            }
+        } else {
+            dump_file_from_fd(type_name, name.c_str(), fd);
+        }
+
+        close(fd);
+    }
+
+    return dumped;
 }
 
 // for_each_pid() callback to get mount info about a process.
@@ -377,88 +452,6 @@
     }
 }
 
-/**
- * Finds the last modified file in the directory dir whose name starts with file_prefix.
- *
- * Function returns empty string when it does not find a file
- */
-static std::string GetLastModifiedFileWithPrefix(const std::string& dir,
-                                                 const std::string& file_prefix) {
-    std::unique_ptr<DIR, decltype(&closedir)> d(opendir(dir.c_str()), closedir);
-    if (d == nullptr) {
-        MYLOGD("Error %d opening %s\n", errno, dir.c_str());
-        return "";
-    }
-
-    // Find the newest file matching the file_prefix in dir
-    struct dirent *de;
-    time_t last_modified_time = 0;
-    std::string last_modified_file = "";
-    struct stat s;
-
-    while ((de = readdir(d.get()))) {
-        std::string file = std::string(de->d_name);
-        if (!file_prefix.empty()) {
-            if (!android::base::StartsWith(file, file_prefix.c_str())) continue;
-        }
-        file = dir + "/" + file;
-        int ret = stat(file.c_str(), &s);
-
-        if ((ret == 0) && (s.st_mtime > last_modified_time)) {
-            last_modified_file = file;
-            last_modified_time = s.st_mtime;
-        }
-    }
-
-    return last_modified_file;
-}
-
-static void DumpModemLogs() {
-    DurationReporter durationReporter("DUMP MODEM LOGS");
-    if (PropertiesHelper::IsUserBuild()) {
-        return;
-    }
-
-    if (!ds.IsZipping()) {
-        MYLOGD("Not dumping modem logs. dumpstate is not generating a zipping bugreport\n");
-        return;
-    }
-
-    std::string file_prefix = android::base::GetProperty("ro.radio.log_prefix", "");
-
-    if(file_prefix.empty()) {
-        MYLOGD("No modem log : file_prefix is empty\n");
-        return;
-    }
-
-    // TODO: b/33820081 we need to provide a right way to dump modem logs.
-    std::string radio_bugreport_dir = android::base::GetProperty("ro.radio.log_loc", "");
-    if (radio_bugreport_dir.empty()) {
-        radio_bugreport_dir = dirname(ds.GetPath("").c_str());
-    }
-
-    MYLOGD("DumpModemLogs: directory is %s and file_prefix is %s\n",
-           radio_bugreport_dir.c_str(), file_prefix.c_str());
-
-    std::string modem_log_file = GetLastModifiedFileWithPrefix(radio_bugreport_dir, file_prefix);
-
-    struct stat s;
-    if (modem_log_file.empty() || stat(modem_log_file.c_str(), &s) != 0) {
-        MYLOGD("Modem log %s does not exist\n", modem_log_file.c_str());
-        return;
-    }
-
-    std::string filename = basename(modem_log_file.c_str());
-    if (!ds.AddZipEntry(filename, modem_log_file)) {
-        MYLOGE("Unable to add modem log %s to zip file\n", modem_log_file.c_str());
-    } else {
-        MYLOGD("Modem Log %s is added to zip\n", modem_log_file.c_str());
-        if (remove(modem_log_file.c_str())) {
-            MYLOGE("Error removing modem log %s\n", modem_log_file.c_str());
-        }
-    }
-}
-
 static bool skip_not_stat(const char *path) {
     static const char stat[] = "/stat";
     size_t len = strlen(path);
@@ -472,7 +465,6 @@
     return false;
 }
 
-static const char mmcblk0[] = "/sys/block/mmcblk0/";
 unsigned long worst_write_perf = 20000; /* in KB/s */
 
 //
@@ -586,11 +578,13 @@
         return 0;
     }
 
-    if (!strncmp(path, mmcblk0, sizeof(mmcblk0) - 1)) {
-        path += sizeof(mmcblk0) - 1;
+    if (!strncmp(path, BLK_DEV_SYS_DIR, sizeof(BLK_DEV_SYS_DIR) - 1)) {
+        path += sizeof(BLK_DEV_SYS_DIR) - 1;
     }
 
-    printf("%s: %s\n", path, buffer);
+    printf("%-30s:%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s%9s\n%-30s:\t%s\n", "Block-Dev",
+           "R-IOs", "R-merg", "R-sect", "R-wait", "W-IOs", "W-merg", "W-sect",
+           "W-wait", "in-fli", "activ", "T-wait", path, buffer);
     free(buffer);
 
     if (fields[__STAT_IO_TICKS]) {
@@ -627,9 +621,9 @@
                                  / fields[__STAT_IO_TICKS];
 
         if (!write_perf && !write_ios) {
-            printf("%s: perf(ios) rd: %luKB/s(%lu/s) q: %u\n", path, read_perf, read_ios, queue);
+            printf("%-30s: perf(ios) rd: %luKB/s(%lu/s) q: %u\n", path, read_perf, read_ios, queue);
         } else {
-            printf("%s: perf(ios) rd: %luKB/s(%lu/s) wr: %luKB/s(%lu/s) q: %u\n", path, read_perf,
+            printf("%-30s: perf(ios) rd: %luKB/s(%lu/s) wr: %luKB/s(%lu/s) q: %u\n", path, read_perf,
                    read_ios, write_perf, write_ios, queue);
         }
 
@@ -849,7 +843,7 @@
                         "-d", "*:v"});
 }
 
-static void DumpIpTables() {
+static void DumpIpTablesAsRoot() {
     RunCommand("IPTABLES", {"iptables", "-L", "-nvx"});
     RunCommand("IP6TABLES", {"ip6tables", "-L", "-nvx"});
     RunCommand("IPTABLES NAT", {"iptables", "-t", "nat", "-L", "-nvx"});
@@ -860,11 +854,10 @@
     RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"});
 }
 
-static void AddAnrTraceFiles() {
-    bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR;
+static void AddGlobalAnrTraceFile(const bool add_to_zip, const std::string& anr_traces_file,
+                                  const std::string& anr_traces_dir) {
     std::string dump_traces_dir;
 
-    /* show the traces we collected in main(), if that was done */
     if (dump_traces_path != nullptr) {
         if (add_to_zip) {
             dump_traces_dir = dirname(dump_traces_path);
@@ -877,8 +870,6 @@
         }
     }
 
-    std::string anr_traces_path = android::base::GetProperty("dalvik.vm.stack-trace-file", "");
-    std::string anr_traces_dir = dirname(anr_traces_path.c_str());
 
     // Make sure directory is not added twice.
     // TODO: this is an overzealous check because it's relying on dump_traces_path - which is
@@ -888,65 +879,164 @@
     // be revisited.
     bool already_dumped = anr_traces_dir == dump_traces_dir;
 
-    MYLOGD("AddAnrTraceFiles(): dump_traces_dir=%s, anr_traces_dir=%s, already_dumped=%d\n",
+    MYLOGD("AddGlobalAnrTraceFile(): dump_traces_dir=%s, anr_traces_dir=%s, already_dumped=%d\n",
            dump_traces_dir.c_str(), anr_traces_dir.c_str(), already_dumped);
 
-    if (anr_traces_path.empty()) {
-        printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
+    int fd = TEMP_FAILURE_RETRY(
+        open(anr_traces_file.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
+    if (fd < 0) {
+        printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_file.c_str(), strerror(errno));
     } else {
-        int fd = TEMP_FAILURE_RETRY(
-            open(anr_traces_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
-        if (fd < 0) {
-            printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path.c_str(),
-                   strerror(errno));
-        } else {
-            if (add_to_zip) {
-                if (!already_dumped) {
-                    MYLOGD("Adding dalvik ANR traces (directory %s) to the zip file\n",
-                           anr_traces_dir.c_str());
-                    ds.AddDir(anr_traces_dir, true);
-                    already_dumped = true;
-                }
-            } else {
-                MYLOGD("Dumping last ANR traces (%s) to the main bugreport entry\n",
-                       anr_traces_path.c_str());
-                dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path.c_str(), fd);
+        if (add_to_zip) {
+            if (!already_dumped) {
+                MYLOGD("Adding dalvik ANR traces (directory %s) to the zip file\n",
+                       anr_traces_dir.c_str());
+                ds.AddDir(anr_traces_dir, true);
             }
+        } else {
+            MYLOGD("Dumping last ANR traces (%s) to the main bugreport entry\n",
+                   anr_traces_file.c_str());
+            dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_file.c_str(), fd);
+        }
+    }
+}
+
+static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_dir) {
+    MYLOGD("AddAnrTraceDir(): dump_traces_file=%s, anr_traces_dir=%s\n", dump_traces_path,
+           anr_traces_dir.c_str());
+
+    // If we're here, dump_traces_path will always be a temporary file
+    // (created with mkostemp or similar) that contains dumps taken earlier
+    // on in the process.
+    if (dump_traces_path != nullptr) {
+        if (add_to_zip) {
+            ds.AddZipEntry(ZIP_ROOT_DIR + anr_traces_dir + "/traces-just-now.txt", dump_traces_path);
+        } else {
+            MYLOGD("Dumping current ANR traces (%s) to the main bugreport entry\n",
+                   dump_traces_path);
+            ds.DumpFile("VM TRACES JUST NOW", dump_traces_path);
+        }
+
+        const int ret = unlink(dump_traces_path);
+        if (ret == -1) {
+            MYLOGW("Error unlinking temporary trace path %s: %s\n", dump_traces_path,
+                   strerror(errno));
         }
     }
 
-    if (add_to_zip && already_dumped) {
-        MYLOGD("Already dumped directory %s to the zip file\n", anr_traces_dir.c_str());
+    // Add a specific message for the first ANR Dump.
+    if (anr_data->size() > 0) {
+        AddDumps(anr_data->begin(), anr_data->begin() + 1,
+                 "VM TRACES AT LAST ANR", add_to_zip);
+
+        if (anr_data->size() > 1) {
+            AddDumps(anr_data->begin() + 1, anr_data->end(),
+                     "HISTORICAL ANR", add_to_zip);
+        }
+    } else {
+        printf("*** NO ANRs to dump in %s\n\n", ANR_DIR.c_str());
+    }
+}
+
+static void AddAnrTraceFiles() {
+    const bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR;
+
+    std::string anr_traces_file;
+    std::string anr_traces_dir;
+    bool is_global_trace_file = true;
+
+    // First check whether the stack-trace-dir property is set. When it's set,
+    // each ANR trace will be written to a separate file and not to a global
+    // stack trace file.
+    anr_traces_dir = android::base::GetProperty("dalvik.vm.stack-trace-dir", "");
+    if (anr_traces_dir.empty()) {
+        anr_traces_file = android::base::GetProperty("dalvik.vm.stack-trace-file", "");
+        if (!anr_traces_file.empty()) {
+            anr_traces_dir = dirname(anr_traces_file.c_str());
+        }
+    } else {
+        is_global_trace_file = false;
+    }
+
+    // We have neither configured a global trace file nor a trace directory,
+    // there will be nothing to dump.
+    if (anr_traces_file.empty() && anr_traces_dir.empty()) {
+        printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
         return;
     }
 
+    if (is_global_trace_file) {
+        AddGlobalAnrTraceFile(add_to_zip, anr_traces_file, anr_traces_dir);
+    } else {
+        AddAnrTraceDir(add_to_zip, anr_traces_dir);
+    }
+
     /* slow traces for slow operations */
     struct stat st;
-    if (!anr_traces_path.empty()) {
-        int tail = anr_traces_path.size() - 1;
-        while (tail > 0 && anr_traces_path.at(tail) != '/') {
-            tail--;
-        }
+    if (!anr_traces_dir.empty()) {
         int i = 0;
-        while (1) {
-            anr_traces_path = anr_traces_path.substr(0, tail + 1) +
-                              android::base::StringPrintf("slow%02d.txt", i);
-            if (stat(anr_traces_path.c_str(), &st)) {
+        while (true) {
+            const std::string slow_trace_path =
+                anr_traces_dir + android::base::StringPrintf("slow%02d.txt", i);
+            if (stat(slow_trace_path.c_str(), &st)) {
                 // No traces file at this index, done with the files.
                 break;
             }
-            ds.DumpFile("VM TRACES WHEN SLOW", anr_traces_path.c_str());
+            ds.DumpFile("VM TRACES WHEN SLOW", slow_trace_path.c_str());
             i++;
         }
     }
 }
 
+static void DumpBlockStatFiles() {
+    DurationReporter duration_reporter("DUMP BLOCK STAT");
+
+    std::unique_ptr<DIR, std::function<int(DIR*)>> dirptr(opendir(BLK_DEV_SYS_DIR), closedir);
+
+    if (dirptr == nullptr) {
+        MYLOGE("Failed to open %s: %s\n", BLK_DEV_SYS_DIR, strerror(errno));
+        return;
+    }
+
+    printf("------ DUMP BLOCK STAT ------\n\n");
+    while (struct dirent *d = readdir(dirptr.get())) {
+        if ((d->d_name[0] == '.')
+         && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
+          || (d->d_name[1] == '\0'))) {
+            continue;
+        }
+        const std::string new_path =
+            android::base::StringPrintf("%s/%s", BLK_DEV_SYS_DIR, d->d_name);
+        printf("------ BLOCK STAT (%s) ------\n", new_path.c_str());
+        dump_files("", new_path.c_str(), skip_not_stat, dump_stat_from_fd);
+        printf("\n");
+    }
+     return;
+}
+
+static void DumpPacketStats() {
+    DumpFile("NETWORK DEV INFO", "/proc/net/dev");
+    DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
+    DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
+    DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
+    DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
+}
+
+static void DumpIpAddrAndRules() {
+    /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
+    RunCommand("NETWORK INTERFACES", {"ip", "link"});
+    RunCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
+    RunCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
+    RunCommand("IP RULES", {"ip", "rule", "show"});
+    RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
+}
+
 static void dumpstate() {
     DurationReporter duration_reporter("DUMPSTATE");
 
     dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
     RunCommand("UPTIME", {"uptime"});
-    dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
+    DumpBlockStatFiles();
     dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
     DumpFile("MEMORY INFO", "/proc/meminfo");
     RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
@@ -1010,52 +1100,25 @@
 
     AddAnrTraceFiles();
 
-    int dumped = 0;
-    for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
-        if (tombstone_data[i].fd != -1) {
-            const char *name = tombstone_data[i].name;
-            int fd = tombstone_data[i].fd;
-            dumped = 1;
-            if (ds.IsZipping()) {
-                if (!ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd)) {
-                    MYLOGE("Unable to add tombstone %s to zip file\n", name);
-                }
-            } else {
-                dump_file_from_fd("TOMBSTONE", name, fd);
-            }
-            close(fd);
-            tombstone_data[i].fd = -1;
-        }
-    }
-    if (!dumped) {
-        printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR);
+    // NOTE: tombstones are always added as separate entries in the zip archive
+    // and are not interspersed with the main report.
+    const bool tombstones_dumped = AddDumps(tombstone_data->begin(), tombstone_data->end(),
+                                            "TOMBSTONE", true /* add_to_zip */);
+    if (!tombstones_dumped) {
+        printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR.c_str());
     }
 
-    DumpFile("NETWORK DEV INFO", "/proc/net/dev");
-    DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
-    DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
-    DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
-    DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
+    DumpPacketStats();
 
     DoKmsg();
 
-    /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
-
-    RunCommand("NETWORK INTERFACES", {"ip", "link"});
-
-    RunCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
-    RunCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
-
-    RunCommand("IP RULES", {"ip", "rule", "show"});
-    RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
+    DumpIpAddrAndRules();
 
     dump_route_tables();
 
     RunCommand("ARP CACHE", {"ip", "-4", "neigh", "show"});
     RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"});
     RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"});
-    RunCommand("WIFI NETWORKS", {"wpa_cli", "IFNAME=wlan0", "list_networks"},
-               CommandOptions::WithTimeout(20).Build());
 
     RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
                CommandOptions::WithTimeout(10).Build());
@@ -1150,11 +1213,6 @@
     RunDumpsys("DROPBOX SYSTEM SERVER CRASHES", {"dropbox", "-p", "system_server_crash"});
     RunDumpsys("DROPBOX SYSTEM APP CRASHES", {"dropbox", "-p", "system_app_crash"});
 
-    // DumpModemLogs adds the modem logs if available to the bugreport.
-    // Do this at the end to allow for sufficient time for the modem logs to be
-    // collected.
-    DumpModemLogs();
-
     printf("========================================================\n");
     printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(),
            ds.progress_->GetMax(), ds.progress_->GetInitialMax());
@@ -1163,6 +1221,46 @@
     printf("========================================================\n");
 }
 
+// This method collects dumpsys for telephony debugging only
+static void DumpstateTelephonyOnly() {
+    DurationReporter duration_reporter("DUMPSTATE");
+
+    DumpIpTablesAsRoot();
+
+    if (!DropRootUser()) {
+        return;
+    }
+
+    do_dmesg();
+    DoLogcat();
+    DumpPacketStats();
+    DoKmsg();
+    DumpIpAddrAndRules();
+    dump_route_tables();
+
+    RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
+               CommandOptions::WithTimeout(10).Build());
+
+    RunCommand("SYSTEM PROPERTIES", {"getprop"});
+
+    printf("========================================================\n");
+    printf("== Android Framework Services\n");
+    printf("========================================================\n");
+
+    RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(), 10);
+    RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(), 10);
+
+    printf("========================================================\n");
+    printf("== Running Application Services\n");
+    printf("========================================================\n");
+
+    RunDumpsys("TELEPHONY SERVICES", {"activity", "service", "TelephonyDebugService"});
+
+    printf("========================================================\n");
+    printf("== dumpstate: done (id %d)\n", ds.id_);
+    printf("========================================================\n");
+}
+
 void Dumpstate::DumpstateBoard() {
     DurationReporter duration_reporter("dumpstate_board()");
     printf("========================================================\n");
@@ -1180,23 +1278,35 @@
         return;
     }
 
-    std::string path = kDumpstateBoardPath;
-    MYLOGI("Calling IDumpstateDevice implementation using path %s\n", path.c_str());
+    std::string path[NUM_OF_DUMPS];
+    android::base::unique_fd fd[NUM_OF_DUMPS];
+    int numFds = 0;
 
-    int fd =
-        TEMP_FAILURE_RETRY(open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
-                                S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
-    if (fd < 0) {
-        MYLOGE("Could not open file %s: %s\n", path.c_str(), strerror(errno));
-        return;
+    for (int i = 0; i < NUM_OF_DUMPS; i++) {
+        path[i] = kDumpstateBoardPath + kDumpstateBoardFiles[i];
+        MYLOGI("Calling IDumpstateDevice implementation using path %s\n", path[i].c_str());
+
+        fd[i] = android::base::unique_fd(
+            TEMP_FAILURE_RETRY(open(path[i].c_str(),
+            O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+            S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
+        if (fd[i] < 0) {
+            MYLOGE("Could not open file %s: %s\n", path[i].c_str(), strerror(errno));
+            return;
+        } else {
+            numFds++;
+        }
     }
 
-    native_handle_t* handle = native_handle_create(1, 0);
+    native_handle_t *handle = native_handle_create(numFds, 0);
     if (handle == nullptr) {
         MYLOGE("Could not create native_handle\n");
         return;
     }
-    handle->data[0] = fd;
+
+    for (int i = 0; i < numFds; i++) {
+        handle->data[i] = fd[i].release();
+    }
 
     // TODO: need a timeout mechanism so dumpstate does not hang on device implementation call.
     android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle);
@@ -1207,14 +1317,26 @@
         return;
     }
 
-    AddZipEntry("dumpstate-board.txt", path);
+    for (int i = 0; i < numFds; i++) {
+        struct stat s;
+        if (fstat(handle->data[i], &s) == -1) {
+            MYLOGE("Failed to fstat %s: %d\n", kDumpstateBoardFiles[i].c_str(), errno);
+        } else if (s.st_size > 0) {
+            AddZipEntry(kDumpstateBoardFiles[i], path[i]);
+        } else {
+            MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str());
+        }
+    }
+
     printf("*** See dumpstate-board.txt entry ***\n");
 
     native_handle_close(handle);
     native_handle_delete(handle);
 
-    if (remove(path.c_str()) != 0) {
-        MYLOGE("Could not remove(%s): %s\n", path.c_str(), strerror(errno));
+    for (int i = 0; i < numFds; i++) {
+        if (remove(path[i].c_str()) != 0) {
+            MYLOGE("Could not remove(%s): %s\n", path[i].c_str(), strerror(errno));
+        }
     }
 }
 
@@ -1676,15 +1798,8 @@
     ds.PrintHeader();
 
     if (telephony_only) {
-        DumpIpTables();
-        if (!DropRootUser()) {
-            return -1;
-        }
-        do_dmesg();
-        DoLogcat();
-        DoKmsg();
+        DumpstateTelephonyOnly();
         ds.DumpstateBoard();
-        DumpModemLogs();
     } else {
         // Dumps systrace right away, otherwise it will be filled with unnecessary events.
         // First try to dump anrd trace if the daemon is running. Otherwise, dump
@@ -1707,7 +1822,9 @@
         dump_traces_path = dump_traces();
 
         /* Run some operations that require root. */
-        get_tombstone_fds(tombstone_data);
+        tombstone_data.reset(GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping()));
+        anr_data.reset(GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping()));
+
         ds.AddDir(RECOVERY_DIR, true);
         ds.AddDir(RECOVERY_DATA_DIR, true);
         ds.AddDir(LOGPERSIST_DATA_DIR, false);
@@ -1716,7 +1833,7 @@
             ds.AddDir(PROFILE_DATA_DIR_REF, true);
         }
         add_mountinfo();
-        DumpIpTables();
+        DumpIpTablesAsRoot();
 
         // Capture any IPSec policies in play.  No keys are exposed here.
         RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"},
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index eefdcbd..93f4c22 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -38,6 +38,7 @@
 #include <time.h>
 #include <unistd.h>
 
+#include <memory>
 #include <set>
 #include <string>
 #include <vector>
@@ -46,6 +47,7 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <android-base/unique_fd.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
 #include <cutils/properties.h>
 #include <cutils/sockets.h>
@@ -96,8 +98,9 @@
         "android.hardware.bluetooth@1.0::IBluetoothHci",
         "android.hardware.camera.provider@2.4::ICameraProvider",
         "android.hardware.graphics.composer@2.1::IComposer",
-        "android.hardware.vr@1.0::IVr",
         "android.hardware.media.omx@1.0::IOmx",
+        "android.hardware.sensors@1.0::ISensors",
+        "android.hardware.vr@1.0::IVr",
         NULL,
 };
 
@@ -853,15 +856,143 @@
     return pids; // whether it was okay or not
 }
 
+const char* DumpTraces(const std::string& traces_path);
+const char* DumpTracesTombstoned(const std::string& traces_dir);
+
 /* dump Dalvik and native stack traces, return the trace file location (NULL if none) */
 const char *dump_traces() {
     DurationReporter duration_reporter("DUMP TRACES");
 
-    const char* result = nullptr;
+    const std::string traces_dir = android::base::GetProperty("dalvik.vm.stack-trace-dir", "");
+    if (!traces_dir.empty()) {
+        return DumpTracesTombstoned(traces_dir);
+    }
 
-    std::string traces_path = android::base::GetProperty("dalvik.vm.stack-trace-file", "");
-    if (traces_path.empty()) return nullptr;
+    const std::string traces_file = android::base::GetProperty("dalvik.vm.stack-trace-file", "");
+    if (!traces_file.empty()) {
+        return DumpTraces(traces_file);
+    }
 
+    return nullptr;
+}
+
+static bool IsZygote(int pid) {
+    static const std::string kZygotePrefix = "zygote";
+
+    std::string cmdline;
+    if (!android::base::ReadFileToString(android::base::StringPrintf("/proc/%d/cmdline", pid),
+                                         &cmdline)) {
+        return true;
+    }
+
+    return (cmdline.find(kZygotePrefix) == 0);
+}
+
+const char* DumpTracesTombstoned(const std::string& traces_dir) {
+    const std::string temp_file_pattern = traces_dir + "/dumptrace_XXXXXX";
+
+    const size_t buf_size = temp_file_pattern.length() + 1;
+    std::unique_ptr<char[]> file_name_buf(new char[buf_size]);
+    memcpy(file_name_buf.get(), temp_file_pattern.c_str(), buf_size);
+
+    // Create a new, empty file to receive all trace dumps.
+    //
+    // TODO: This can be simplified once we remove support for the old style
+    // dumps. We can have a file descriptor passed in to dump_traces instead
+    // of creating a file, closing it and then reopening it again.
+    android::base::unique_fd fd(mkostemp(file_name_buf.get(), O_APPEND | O_CLOEXEC));
+    if (fd < 0) {
+        MYLOGE("mkostemp on pattern %s: %s\n", file_name_buf.get(), strerror(errno));
+        return nullptr;
+    }
+
+    // Nobody should have access to this temporary file except dumpstate, but we
+    // temporarily grant 'read' to 'others' here because this file is created
+    // when tombstoned is still running as root, but dumped after dropping. This
+    // can go away once support for old style dumping has.
+    const int chmod_ret = fchmod(fd, 0666);
+    if (chmod_ret < 0) {
+        MYLOGE("fchmod on %s failed: %s\n", file_name_buf.get(), strerror(errno));
+        return nullptr;
+    }
+
+    std::unique_ptr<DIR, decltype(&closedir)> proc(opendir("/proc"), closedir);
+    if (proc.get() == nullptr) {
+        MYLOGE("opendir /proc failed: %s\n", strerror(errno));
+        return nullptr;
+    }
+
+    // Number of times process dumping has timed out. If we encounter too many
+    // failures, we'll give up.
+    int timeout_failures = 0;
+    bool dalvik_found = false;
+
+    const std::set<int> hal_pids = get_interesting_hal_pids();
+
+    struct dirent* d;
+    while ((d = readdir(proc.get()))) {
+        int pid = atoi(d->d_name);
+        if (pid <= 0) {
+            continue;
+        }
+
+        const std::string link_name = android::base::StringPrintf("/proc/%d/exe", pid);
+        std::string exe;
+        if (!android::base::Readlink(link_name, &exe)) {
+            continue;
+        }
+
+        bool is_java_process;
+        if (exe == "/system/bin/app_process32" || exe == "/system/bin/app_process64") {
+            // Don't bother dumping backtraces for the zygote.
+            if (IsZygote(pid)) {
+                continue;
+            }
+
+            dalvik_found = true;
+            is_java_process = true;
+        } else if (should_dump_native_traces(exe.c_str()) || hal_pids.find(pid) != hal_pids.end()) {
+            is_java_process = false;
+        } else {
+            // Probably a native process we don't care about, continue.
+            continue;
+        }
+
+        // If 3 backtrace dumps fail in a row, consider debuggerd dead.
+        if (timeout_failures == 3) {
+            dprintf(fd, "ERROR: Too many stack dump failures, exiting.\n");
+            break;
+        }
+
+        const uint64_t start = Nanotime();
+        const int ret = dump_backtrace_to_file_timeout(
+            pid, is_java_process ? kDebuggerdJavaBacktrace : kDebuggerdNativeBacktrace,
+            is_java_process ? 5 : 20, fd);
+
+        if (ret == -1) {
+            dprintf(fd, "dumping failed, likely due to a timeout\n");
+            timeout_failures++;
+            continue;
+        }
+
+        // We've successfully dumped stack traces, reset the failure count
+        // and write a summary of the elapsed time to the file and continue with the
+        // next process.
+        timeout_failures = 0;
+
+        dprintf(fd, "[dump %s stack %d: %.3fs elapsed]\n", is_java_process ? "dalvik" : "native",
+                pid, (float)(Nanotime() - start) / NANOS_PER_SEC);
+    }
+
+    if (!dalvik_found) {
+        MYLOGE("Warning: no Dalvik processes found to dump stacks\n");
+    }
+
+    return file_name_buf.release();
+}
+
+const char* DumpTraces(const std::string& traces_path) {
+    const char* result = NULL;
     /* move the old traces.txt (if any) out of the way temporarily */
     std::string anrtraces_path = traces_path + ".anr";
     if (rename(traces_path.c_str(), anrtraces_path.c_str()) && errno != ENOENT) {
@@ -974,7 +1105,8 @@
                 /* If 3 backtrace dumps fail in a row, consider debuggerd dead. */
                 if (timeout_failures == 3) {
                     dprintf(fd, "too many stack dump failures, skipping...\n");
-                } else if (dump_backtrace_to_file_timeout(pid, fd, 20) == -1) {
+                } else if (dump_backtrace_to_file_timeout(
+                        pid, kDebuggerdNativeBacktrace, 20, fd) == -1) {
                     dprintf(fd, "dumping failed, likely due to a timeout\n");
                     timeout_failures++;
                 } else {
diff --git a/cmds/dumpsys/tests/Android.bp b/cmds/dumpsys/tests/Android.bp
index 7698ed5..127e0f3 100644
--- a/cmds/dumpsys/tests/Android.bp
+++ b/cmds/dumpsys/tests/Android.bp
@@ -1,6 +1,7 @@
 // Build the unit tests for dumpsys
 cc_test {
     name: "dumpsys_test",
+    test_suites: ["device-tests"],
 
     srcs: ["dumpsys_test.cpp"],
 
diff --git a/cmds/dumpsys/tests/AndroidTest.xml b/cmds/dumpsys/tests/AndroidTest.xml
new file mode 100644
index 0000000..1a8c67f
--- /dev/null
+++ b/cmds/dumpsys/tests/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<configuration description="Config for dumpsys_test">
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="dumpsys_test->/data/local/tmp/dumpsys_test" />
+    </target_preparer>
+    <option name="test-suite-tag" value="apct" />
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="dumpsys_test" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 60c89a9..e3021d8 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -1786,6 +1786,16 @@
     return ok();
 }
 
+// Copy the contents of a system profile over the data profile.
+binder::Status InstalldNativeService::copySystemProfile(const std::string& systemProfile,
+        int32_t packageUid, const std::string& packageName, bool* _aidl_return) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+    *_aidl_return = copy_system_profile(systemProfile, packageUid, packageName);
+    return ok();
+}
+
 // TODO: Consider returning error codes.
 binder::Status InstalldNativeService::mergeProfiles(int32_t uid, const std::string& packageName,
         bool* _aidl_return) {
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 4011315..5756b82 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -91,6 +91,8 @@
     binder::Status mergeProfiles(int32_t uid, const std::string& packageName, bool* _aidl_return);
     binder::Status dumpProfiles(int32_t uid, const std::string& packageName,
             const std::string& codePaths, bool* _aidl_return);
+    binder::Status copySystemProfile(const std::string& systemProfile,
+            int32_t uid, const std::string& packageName, bool* _aidl_return);
     binder::Status clearAppProfiles(const std::string& packageName);
     binder::Status destroyAppProfiles(const std::string& packageName);
 
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index f09a397..c8e76b0 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -57,6 +57,8 @@
 
     boolean mergeProfiles(int uid, @utf8InCpp String packageName);
     boolean dumpProfiles(int uid, @utf8InCpp String packageName, @utf8InCpp String codePaths);
+    boolean copySystemProfile(@utf8InCpp String systemProfile, int uid,
+            @utf8InCpp String packageName);
     void clearAppProfiles(@utf8InCpp String packageName);
     void destroyAppProfiles(@utf8InCpp String packageName);
 
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 70cf35c..685fdd8 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -847,6 +847,70 @@
     return true;
 }
 
+bool copy_system_profile(const std::string& system_profile,
+        uid_t packageUid, const std::string& data_profile_location) {
+    unique_fd in_fd(open(system_profile.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC));
+    unique_fd out_fd(open_reference_profile(packageUid,
+                     data_profile_location,
+                     /*read_write*/ true,
+                     /*secondary*/ false));
+    if (in_fd.get() < 0) {
+        PLOG(WARNING) << "Could not open profile " << system_profile;
+        return false;
+    }
+    if (out_fd.get() < 0) {
+        PLOG(WARNING) << "Could not open profile " << data_profile_location;
+        return false;
+    }
+
+    // As a security measure we want to write the profile information with the reduced capabilities
+    // of the package user id. So we fork and drop capabilities in the child.
+    pid_t pid = fork();
+    if (pid == 0) {
+        /* child -- drop privileges before continuing */
+        drop_capabilities(packageUid);
+
+        if (flock(out_fd.get(), LOCK_EX | LOCK_NB) != 0) {
+            if (errno != EWOULDBLOCK) {
+                PLOG(WARNING) << "Error locking profile " << data_profile_location;
+            }
+            // This implies that the app owning this profile is running
+            // (and has acquired the lock).
+            //
+            // The app never acquires the lock for the reference profiles of primary apks.
+            // Only dex2oat from installd will do that. Since installd is single threaded
+            // we should not see this case. Nevertheless be prepared for it.
+            PLOG(WARNING) << "Failed to flock " << data_profile_location;
+            return false;
+        }
+
+        bool truncated = ftruncate(out_fd.get(), 0) == 0;
+        if (!truncated) {
+            PLOG(WARNING) << "Could not truncate " << data_profile_location;
+        }
+
+        // Copy over data.
+        static constexpr size_t kBufferSize = 4 * 1024;
+        char buffer[kBufferSize];
+        while (true) {
+            ssize_t bytes = read(in_fd.get(), buffer, kBufferSize);
+            if (bytes == 0) {
+                break;
+            }
+            write(out_fd.get(), buffer, bytes);
+        }
+        if (flock(out_fd.get(), LOCK_UN) != 0) {
+            PLOG(WARNING) << "Error unlocking profile " << data_profile_location;
+        }
+        // Use _exit since we don't want to run the global destructors in the child.
+        // b/62597429
+        _exit(0);
+    }
+    /* parent */
+    int return_code = wait_child(pid);
+    return return_code == 0;
+}
+
 static std::string replace_file_extension(const std::string& oat_path, const std::string& new_ext) {
   // A standard dalvik-cache entry. Replace ".dex" with `new_ext`.
   if (EndsWith(oat_path, ".dex")) {
@@ -926,14 +990,22 @@
   return oat_dir == nullptr || oat_dir[0] == '!';
 }
 
+// Best-effort check whether we can fit the the path into our buffers.
+// Note: the cache path will require an additional 5 bytes for ".swap", but we'll try to run
+// without a swap file, if necessary. Reference profiles file also add an extra ".prof"
+// extension to the cache path (5 bytes).
+// TODO(calin): move away from char* buffers and PKG_PATH_MAX.
+static bool validate_dex_path_size(const std::string& dex_path) {
+    if (dex_path.size() >= (PKG_PATH_MAX - 8)) {
+        LOG(ERROR) << "dex_path too long: " << dex_path;
+        return false;
+    }
+    return true;
+}
+
 static bool create_oat_out_path(const char* apk_path, const char* instruction_set,
             const char* oat_dir, bool is_secondary_dex, /*out*/ char* out_oat_path) {
-    // Early best-effort check whether we can fit the the path into our buffers.
-    // Note: the cache path will require an additional 5 bytes for ".swap", but we'll try to run
-    // without a swap file, if necessary. Reference profiles file also add an extra ".prof"
-    // extension to the cache path (5 bytes).
-    if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {
-        ALOGE("apk_path too long '%s'\n", apk_path);
+    if (!validate_dex_path_size(apk_path)) {
         return false;
     }
 
@@ -1286,33 +1358,29 @@
 // The analyzer will check if the dex_file needs to be (re)compiled to match the compiler_filter.
 // If this is for a profile guided compilation, profile_was_updated will tell whether or not
 // the profile has changed.
-static void exec_dexoptanalyzer(const std::string& dex_file, const char* instruction_set,
-        const char* compiler_filter, bool profile_was_updated) {
+static void exec_dexoptanalyzer(const std::string& dex_file, const std::string& instruction_set,
+        const std::string& compiler_filter, bool profile_was_updated) {
     static const char* DEXOPTANALYZER_BIN = "/system/bin/dexoptanalyzer";
     static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
 
-    if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
-        ALOGE("Instruction set %s longer than max length of %d",
-              instruction_set, MAX_INSTRUCTION_SET_LEN);
+    if (instruction_set.size() >= MAX_INSTRUCTION_SET_LEN) {
+        LOG(ERROR) << "Instruction set " << instruction_set
+                << " longer than max length of " << MAX_INSTRUCTION_SET_LEN;
         return;
     }
 
-    char dex_file_arg[strlen("--dex-file=") + PKG_PATH_MAX];
-    char isa_arg[strlen("--isa=") + MAX_INSTRUCTION_SET_LEN];
-    char compiler_filter_arg[strlen("--compiler-filter=") + kPropertyValueMax];
+    std::string dex_file_arg = "--dex-file=" + dex_file;
+    std::string isa_arg = "--isa=" + instruction_set;
+    std::string compiler_filter_arg = "--compiler-filter=" + compiler_filter;
     const char* assume_profile_changed = "--assume-profile-changed";
 
-    sprintf(dex_file_arg, "--dex-file=%s", dex_file.c_str());
-    sprintf(isa_arg, "--isa=%s", instruction_set);
-    sprintf(compiler_filter_arg, "--compiler-filter=%s", compiler_filter);
-
     // program name, dex file, isa, filter, the final NULL
     const char* argv[5 + (profile_was_updated ? 1 : 0)];
     int i = 0;
     argv[i++] = DEXOPTANALYZER_BIN;
-    argv[i++] = dex_file_arg;
-    argv[i++] = isa_arg;
-    argv[i++] = compiler_filter_arg;
+    argv[i++] = dex_file_arg.c_str();
+    argv[i++] = isa_arg.c_str();
+    argv[i++] = compiler_filter_arg.c_str();
     if (profile_was_updated) {
         argv[i++] = assume_profile_changed;
     }
@@ -1426,6 +1494,9 @@
         }
     }
     const std::string& dex_path = *dex_path_out;
+    if (!validate_dex_path_size(dex_path)) {
+        return false;
+    }
     if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid, uid, storage_flag)) {
         LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
         return false;
@@ -1496,6 +1567,10 @@
         LOG_FATAL("dexopt flags contains unknown fields\n");
     }
 
+    if (!validate_dex_path_size(dex_path)) {
+        return false;
+    }
+
     bool is_public = (dexopt_flags & DEXOPT_PUBLIC) != 0;
     bool debuggable = (dexopt_flags & DEXOPT_DEBUGGABLE) != 0;
     bool boot_complete = (dexopt_flags & DEXOPT_BOOTCOMPLETE) != 0;
@@ -1685,6 +1760,10 @@
         /*out*/bool* out_secondary_dex_exists) {
     // Set out to false to start with, just in case we have validation errors.
     *out_secondary_dex_exists = false;
+    if (!validate_dex_path_size(dex_path)) {
+        return false;
+    }
+
     if (isas.size() == 0) {
         LOG(ERROR) << "reconcile_secondary_dex_file called with empty isas vector";
         return false;
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 355adb1..d171ee5 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -30,7 +30,6 @@
 static constexpr int DEX2OAT_FOR_BOOT_IMAGE      = 2;
 static constexpr int DEX2OAT_FOR_FILTER          = 3;
 static constexpr int DEX2OAT_FOR_RELOCATION      = 4;
-static constexpr int PATCHOAT_FOR_RELOCATION     = 5;
 
 // Clear the reference profile for the primary apk of the given package.
 bool clear_primary_reference_profile(const std::string& pkgname);
@@ -51,6 +50,10 @@
 
 bool dump_profiles(int32_t uid, const std::string& pkgname, const char* code_paths);
 
+bool copy_system_profile(const std::string& system_profile,
+                         uid_t packageUid,
+                         const std::string& data_profile_location);
+
 bool delete_odex(const char* apk_path, const char* instruction_set, const char* output_path);
 
 bool reconcile_secondary_dex_file(const std::string& dex_path,
diff --git a/cmds/installd/installd_constants.h b/cmds/installd/installd_constants.h
index 6a81cfc..2597c79 100644
--- a/cmds/installd/installd_constants.h
+++ b/cmds/installd/installd_constants.h
@@ -31,7 +31,7 @@
 constexpr const char* DALVIK_CACHE_POSTFIX = "@classes.dex";
 
 constexpr size_t PKG_NAME_MAX = 128u;   /* largest allowed package name */
-constexpr size_t PKG_PATH_MAX = 256u;   /* max size of any path we use */
+constexpr size_t PKG_PATH_MAX = 1024u;  /* max size of any path we use */
 
 /****************************************************************************
  * IMPORTANT: These values are passed from Java code. Keep them in sync with
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index c792082..7c05417 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -168,18 +168,19 @@
 
 /**
  * Create the path name for user data for a certain userid.
+ * Keep same implementation as vold to minimize path walking overhead
  */
 std::string create_data_user_ce_path(const char* volume_uuid, userid_t userid) {
     std::string data(create_data_path(volume_uuid));
-    if (volume_uuid == nullptr) {
-        if (userid == 0) {
-            return StringPrintf("%s/data", data.c_str());
-        } else {
-            return StringPrintf("%s/user/%u", data.c_str(), userid);
+    if (volume_uuid == nullptr && userid == 0) {
+        std::string legacy = StringPrintf("%s/data", data.c_str());
+        struct stat sb;
+        if (lstat(legacy.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)) {
+            /* /data/data is dir, return /data/data for legacy system */
+            return legacy;
         }
-    } else {
-        return StringPrintf("%s/user/%u", data.c_str(), userid);
     }
+    return StringPrintf("%s/user/%u", data.c_str(), userid);
 }
 
 /**
diff --git a/cmds/lshal/Android.bp b/cmds/lshal/Android.bp
index 38647eb..67b5b46 100644
--- a/cmds/lshal/Android.bp
+++ b/cmds/lshal/Android.bp
@@ -22,7 +22,6 @@
         "libhidltransport",
         "libhidl-gen-utils",
         "libvintf",
-        "android.hidl.manager@1.0",
     ],
     srcs: [
         "DebugCommand.cpp",
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index 710b6e4..7c6cfd9 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -73,46 +73,92 @@
     }), pids->end());
 }
 
-bool ListCommand::getReferencedPids(
-        pid_t serverPid, std::map<uint64_t, Pids> *objects) const {
-
-    std::ifstream ifs("/d/binder/proc/" + std::to_string(serverPid));
+bool scanBinderContext(pid_t pid,
+        const std::string &contextName,
+        std::function<void(const std::string&)> eachLine) {
+    std::ifstream ifs("/d/binder/proc/" + std::to_string(pid));
     if (!ifs.is_open()) {
         return false;
     }
 
-    static const std::regex prefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+");
+    static const std::regex kContextLine("^context (\\w+)$");
 
+    bool isDesiredContext = false;
     std::string line;
     std::smatch match;
     while(getline(ifs, line)) {
-        if (!std::regex_search(line, match, prefix)) {
-            // the line doesn't start with the correct prefix
+        if (std::regex_search(line, match, kContextLine)) {
+            isDesiredContext = match.str(1) == contextName;
             continue;
         }
-        std::string ptrString = "0x" + match.str(2); // use number after c
-        uint64_t ptr;
-        if (!::android::base::ParseUint(ptrString.c_str(), &ptr)) {
-            // Should not reach here, but just be tolerant.
-            mErr << "Could not parse number " << ptrString << std::endl;
+
+        if (!isDesiredContext) {
             continue;
         }
-        const std::string proc = " proc ";
-        auto pos = line.rfind(proc);
-        if (pos != std::string::npos) {
-            for (const std::string &pidStr : split(line.substr(pos + proc.size()), ' ')) {
-                int32_t pid;
-                if (!::android::base::ParseInt(pidStr, &pid)) {
-                    mErr << "Could not parse number " << pidStr << std::endl;
-                    continue;
-                }
-                (*objects)[ptr].push_back(pid);
-            }
-        }
+
+        eachLine(line);
     }
     return true;
 }
 
+bool ListCommand::getPidInfo(
+        pid_t serverPid, PidInfo *pidInfo) const {
+    static const std::regex kReferencePrefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+");
+    static const std::regex kThreadPrefix("^\\s*thread \\d+:\\s+l\\s+(\\d)(\\d)");
+
+    std::smatch match;
+    return scanBinderContext(serverPid, "hwbinder", [&](const std::string& line) {
+        if (std::regex_search(line, match, kReferencePrefix)) {
+            const std::string &ptrString = "0x" + match.str(2); // use number after c
+            uint64_t ptr;
+            if (!::android::base::ParseUint(ptrString.c_str(), &ptr)) {
+                // Should not reach here, but just be tolerant.
+                mErr << "Could not parse number " << ptrString << std::endl;
+                return;
+            }
+            const std::string proc = " proc ";
+            auto pos = line.rfind(proc);
+            if (pos != std::string::npos) {
+                for (const std::string &pidStr : split(line.substr(pos + proc.size()), ' ')) {
+                    int32_t pid;
+                    if (!::android::base::ParseInt(pidStr, &pid)) {
+                        mErr << "Could not parse number " << pidStr << std::endl;
+                        return;
+                    }
+                    pidInfo->refPids[ptr].push_back(pid);
+                }
+            }
+
+            return;
+        }
+
+        if (std::regex_search(line, match, kThreadPrefix)) {
+            // "1" is waiting in binder driver
+            // "2" is poll. It's impossible to tell if these are in use.
+            //     and HIDL default code doesn't use it.
+            bool isInUse = match.str(1) != "1";
+            // "0" is a thread that has called into binder
+            // "1" is looper thread
+            // "2" is main looper thread
+            bool isHwbinderThread = match.str(2) != "0";
+
+            if (!isHwbinderThread) {
+                return;
+            }
+
+            if (isInUse) {
+                pidInfo->threadUsage++;
+            }
+
+            pidInfo->threadCount++;
+            return;
+        }
+
+        // not reference or thread line
+        return;
+    });
+}
+
 // Must process hwbinder services first, then passthrough services.
 void ListCommand::forEachTable(const std::function<void(Table &)> &f) {
     f(mServicesTable);
@@ -164,9 +210,11 @@
         const std::string &interfaceName,
         const std::string &transport,
         const std::string &arch,
+        const std::string &threadUsage,
         const std::string &server,
         const std::string &serverCmdline,
-        const std::string &address, const std::string &clients,
+        const std::string &address,
+        const std::string &clients,
         const std::string &clientCmdlines) const {
     if (mSelectedColumns & ENABLE_INTERFACE_NAME)
         mOut << std::setw(80) << interfaceName << "\t";
@@ -174,6 +222,9 @@
         mOut << std::setw(10) << transport << "\t";
     if (mSelectedColumns & ENABLE_ARCH)
         mOut << std::setw(5) << arch << "\t";
+    if (mSelectedColumns & ENABLE_THREADS) {
+        mOut << std::setw(8) << threadUsage << "\t";
+    }
     if (mSelectedColumns & ENABLE_SERVER_PID) {
         if (mEnableCmdlines) {
             mOut << std::setw(15) << serverCmdline << "\t";
@@ -193,7 +244,18 @@
     mOut << std::endl;
 }
 
+static inline bool findAndBumpVersion(vintf::ManifestHal* hal, const vintf::Version& version) {
+    for (vintf::Version& v : hal->versions) {
+        if (v.majorVer == version.majorVer) {
+            v.minorVer = std::max(v.minorVer, version.minorVer);
+            return true;
+        }
+    }
+    return false;
+}
+
 void ListCommand::dumpVintf() const {
+    using vintf::operator|=;
     mOut << "<!-- " << std::endl
          << "    This is a skeleton device manifest. Notes: " << std::endl
          << "    1. android.hidl.*, android.frameworks.*, android.system.* are not included." << std::endl
@@ -201,7 +263,9 @@
          << "       only hwbinder is shown." << std::endl
          << "    3. It is likely that HALs in passthrough transport does not have" << std::endl
          << "       <interface> declared; users will have to write them by hand." << std::endl
-         << "    4. sepolicy version is set to 0.0. It is recommended that the entry" << std::endl
+         << "    4. A HAL with lower minor version can be overridden by a HAL with" << std::endl
+         << "       higher minor version if they have the same name and major version." << std::endl
+         << "    5. sepolicy version is set to 0.0. It is recommended that the entry" << std::endl
          << "       is removed from the manifest file and written by assemble_vintf" << std::endl
          << "       at build time." << std::endl
          << "-->" << std::endl;
@@ -265,17 +329,19 @@
             for (vintf::ManifestHal *hal : manifest.getHals(fqName.package())) {
                 if (hal->transport() != transport) {
                     if (transport != vintf::Transport::PASSTHROUGH) {
-                        mErr << "Fatal: should not reach here. Generated result may be wrong."
+                        mErr << "Fatal: should not reach here. Generated result may be wrong for '"
+                             << hal->name << "'."
                              << std::endl;
                     }
                     done = true;
                     break;
                 }
-                if (hal->hasVersion(version)) {
+                if (findAndBumpVersion(hal, version)) {
                     if (&table != &mImplementationsTable) {
                         hal->interfaces[interfaceName].name = interfaceName;
                         hal->interfaces[interfaceName].instances.insert(instanceName);
                     }
+                    hal->transportArch.arch |= arch;
                     done = true;
                     break;
                 }
@@ -344,15 +410,20 @@
     mImplementationsTable.description =
             "All available passthrough implementations (all -impl.so files)";
     forEachTable([this] (const Table &table) {
-        mOut << table.description << std::endl;
+        if (!mNeat) {
+            mOut << table.description << std::endl;
+        }
         mOut << std::left;
-        printLine("Interface", "Transport", "Arch", "Server", "Server CMD",
-                  "PTR", "Clients", "Clients CMD");
+        if (!mNeat) {
+            printLine("Interface", "Transport", "Arch", "Thread Use", "Server",
+                      "Server CMD", "PTR", "Clients", "Clients CMD");
+        }
 
         for (const auto &entry : table) {
             printLine(entry.interfaceName,
                     entry.transport,
                     getArchString(entry.arch),
+                    entry.getThreadUsage(),
                     entry.serverPid == NO_PID ? "N/A" : std::to_string(entry.serverPid),
                     entry.serverCmdline,
                     entry.serverObjectAddress == NO_PTR ? "N/A" : toHexString(entry.serverObjectAddress),
@@ -369,7 +440,9 @@
                         NullableOStream<std::ostream>(nullptr));
             }
         }
-        mOut << std::endl;
+        if (!mNeat) {
+            mOut << std::endl;
+        }
     });
 
 }
@@ -409,7 +482,8 @@
     using namespace ::android::hardware;
     using namespace ::android::hidl::manager::V1_0;
     using namespace ::android::hidl::base::V1_0;
-    auto ret = timeoutIPC(manager, &IServiceManager::debugDump, [&] (const auto &infos) {
+    using std::literals::chrono_literals::operator""s;
+    auto ret = timeoutIPC(2s, manager, &IServiceManager::debugDump, [&] (const auto &infos) {
         std::map<std::string, TableEntry> entries;
         for (const auto &info : infos) {
             std::string interfaceName = std::string{info.interfaceName.c_str()} + "/" +
@@ -419,7 +493,7 @@
                 .transport = "passthrough",
                 .serverPid = NO_PID,
                 .serverObjectAddress = NO_PTR,
-                .clientPids = {},
+                .clientPids = info.clientPids,
                 .arch = ARCH_UNKNOWN
             }).first->second.arch |= fromBaseArchitecture(info.arch);
         }
@@ -486,7 +560,7 @@
     Status status = OK;
     // server pid, .ptr value of binder object, child pids
     std::map<std::string, DebugInfo> allDebugInfos;
-    std::map<pid_t, std::map<uint64_t, Pids>> allPids;
+    std::map<pid_t, PidInfo> allPids;
     for (const auto &fqInstanceName : fqInstanceNames) {
         const auto pair = splitFirst(fqInstanceName, '/');
         const auto &serviceName = pair.first;
@@ -510,7 +584,7 @@
         auto debugRet = timeoutIPC(service, &IBase::getDebugInfo, [&] (const auto &debugInfo) {
             allDebugInfos[fqInstanceName] = debugInfo;
             if (debugInfo.pid >= 0) {
-                allPids[static_cast<pid_t>(debugInfo.pid)].clear();
+                allPids[static_cast<pid_t>(debugInfo.pid)] = PidInfo();
             }
         });
         if (!debugRet.isOk()) {
@@ -520,9 +594,10 @@
             status |= DUMP_BINDERIZED_ERROR;
         }
     }
+
     for (auto &pair : allPids) {
         pid_t serverPid = pair.first;
-        if (!getReferencedPids(serverPid, &allPids[serverPid])) {
+        if (!getPidInfo(serverPid, &allPids[serverPid])) {
             mErr << "Warning: no information for PID " << serverPid
                       << ", are you root?" << std::endl;
             status |= DUMP_BINDERIZED_ERROR;
@@ -537,18 +612,23 @@
                 .serverPid = NO_PID,
                 .serverObjectAddress = NO_PTR,
                 .clientPids = {},
+                .threadUsage = 0,
+                .threadCount = 0,
                 .arch = ARCH_UNKNOWN
             });
             continue;
         }
         const DebugInfo &info = it->second;
+        bool writePidInfo = info.pid != NO_PID && info.ptr != NO_PTR;
+
         putEntry(HWSERVICEMANAGER_LIST, {
             .interfaceName = fqInstanceName,
             .transport = mode,
             .serverPid = info.pid,
             .serverObjectAddress = info.ptr,
-            .clientPids = info.pid == NO_PID || info.ptr == NO_PTR
-                    ? Pids{} : allPids[info.pid][info.ptr],
+            .clientPids = writePidInfo ? allPids[info.pid].refPids[info.ptr] : Pids{},
+            .threadUsage = writePidInfo ? allPids[info.pid].threadUsage : 0,
+            .threadCount = writePidInfo ? allPids[info.pid].threadCount : 0,
             .arch = fromBaseArchitecture(info.arch),
         });
     }
@@ -587,12 +667,14 @@
         {"pid",       no_argument,       0, 'p' },
         {"address",   no_argument,       0, 'a' },
         {"clients",   no_argument,       0, 'c' },
+        {"threads",   no_argument,       0, 'e' },
         {"cmdline",   no_argument,       0, 'm' },
         {"debug",     optional_argument, 0, 'd' },
 
         // long options without short alternatives
         {"sort",      required_argument, 0, 's' },
         {"init-vintf",optional_argument, 0, 'v' },
+        {"neat",      no_argument,       0, 'n' },
         { 0,          0,                 0,  0  }
     };
 
@@ -602,7 +684,7 @@
     for (;;) {
         // using getopt_long in case we want to add other options in the future
         c = getopt_long(arg.argc, arg.argv,
-                "hitrpacmd", longOptions, &optionIndex);
+                "hitrpacmde", longOptions, &optionIndex);
         if (c == -1) {
             break;
         }
@@ -654,6 +736,10 @@
             mSelectedColumns |= ENABLE_CLIENT_PIDS;
             break;
         }
+        case 'e': {
+            mSelectedColumns |= ENABLE_THREADS;
+            break;
+        }
         case 'm': {
             mEnableCmdlines = true;
             break;
@@ -672,6 +758,10 @@
             }
             break;
         }
+        case 'n': {
+            mNeat = true;
+            break;
+        }
         case 'h': // falls through
         default: // see unrecognized options
             mLshal.usage(command);
@@ -684,7 +774,7 @@
     }
 
     if (mSelectedColumns == 0) {
-        mSelectedColumns = ENABLE_INTERFACE_NAME | ENABLE_SERVER_PID | ENABLE_CLIENT_PIDS;
+        mSelectedColumns = ENABLE_INTERFACE_NAME | ENABLE_SERVER_PID | ENABLE_CLIENT_PIDS | ENABLE_THREADS;
     }
     return OK;
 }
diff --git a/cmds/lshal/ListCommand.h b/cmds/lshal/ListCommand.h
index 42c965f..a75db04 100644
--- a/cmds/lshal/ListCommand.h
+++ b/cmds/lshal/ListCommand.h
@@ -48,18 +48,26 @@
     Status fetchPassthrough(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
     Status fetchBinderized(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
     Status fetchAllLibraries(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
-    bool getReferencedPids(
-        pid_t serverPid, std::map<uint64_t, Pids> *objects) const;
+
+    struct PidInfo {
+        std::map<uint64_t, Pids> refPids; // pids that are referenced
+        uint32_t threadUsage; // number of threads in use
+        uint32_t threadCount; // number of threads total
+    };
+    bool getPidInfo(pid_t serverPid, PidInfo *info) const;
+
     void dumpTable();
     void dumpVintf() const;
     void printLine(
             const std::string &interfaceName,
             const std::string &transport,
             const std::string &arch,
+            const std::string &threadUsage,
             const std::string &server,
             const std::string &serverCmdline,
-            const std::string &address, const std::string &clients,
-            const std::string &clientCmdlines) const ;
+            const std::string &address,
+            const std::string &clients,
+            const std::string &clientCmdlines) const;
     // Return /proc/{pid}/cmdline if it exists, else empty string.
     const std::string &getCmdline(pid_t pid);
     // Call getCmdline on all pid in pids. If it returns empty string, the process might
@@ -85,7 +93,12 @@
     // If true, calls IBase::debug(...) on each service.
     bool mEmitDebugInfo = false;
 
+    // If true, output in VINTF format.
     bool mVintf = false;
+
+    // If true, explanatory text are not emitted.
+    bool mNeat = false;
+
     // If an entry does not exist, need to ask /proc/{pid}/cmdline to get it.
     // If an entry exist but is an empty string, process might have died.
     // If an entry exist and not empty, it contains the cached content of /proc/{pid}/cmdline.
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index 9db42f1..e2d5f6d 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -66,7 +66,7 @@
             "        List all hals with default ordering and columns (`lshal list -ipc`)\n"
             "    lshal list [-h|--help]\n"
             "        -h, --help: Print help message for list (`lshal help list`)\n"
-            "    lshal [list] [--interface|-i] [--transport|-t] [-r|--arch]\n"
+            "    lshal [list] [--interface|-i] [--transport|-t] [-r|--arch] [-e|--threads]\n"
             "            [--pid|-p] [--address|-a] [--clients|-c] [--cmdline|-m]\n"
             "            [--sort={interface|i|pid|p}] [--init-vintf[=<output file>]]\n"
             "            [--debug|-d[=<output file>]]\n"
@@ -74,6 +74,8 @@
             "        -n, --instance: print the instance name column\n"
             "        -t, --transport: print the transport mode column\n"
             "        -r, --arch: print if the HAL is in 64-bit or 32-bit\n"
+            "        -e, --threads: print currently used/available threads\n"
+            "                       (note, available threads created lazily)\n"
             "        -p, --pid: print the server PID, or server cmdline if -m is set\n"
             "        -a, --address: print the server object address column\n"
             "        -c, --clients: print the client PIDs, or client cmdlines if -m is set\n"
diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h
index 9ae8f78..e04c3ca 100644
--- a/cmds/lshal/TableEntry.h
+++ b/cmds/lshal/TableEntry.h
@@ -47,6 +47,8 @@
     std::string interfaceName;
     std::string transport;
     int32_t serverPid;
+    uint32_t threadUsage;
+    uint32_t threadCount;
     std::string serverCmdline;
     uint64_t serverObjectAddress;
     Pids clientPids;
@@ -59,6 +61,14 @@
     static bool sortByServerPid(const TableEntry &a, const TableEntry &b) {
         return a.serverPid < b.serverPid;
     };
+
+    std::string getThreadUsage() const {
+        if (threadCount == 0) {
+            return "N/A";
+        }
+
+        return std::to_string(threadUsage) + "/" + std::to_string(threadCount);
+    }
 };
 
 struct Table {
@@ -80,7 +90,8 @@
     ENABLE_SERVER_PID     = 1 << 2,
     ENABLE_SERVER_ADDR    = 1 << 3,
     ENABLE_CLIENT_PIDS    = 1 << 4,
-    ENABLE_ARCH           = 1 << 5
+    ENABLE_ARCH           = 1 << 5,
+    ENABLE_THREADS        = 1 << 6,
 };
 
 using TableEntrySelect = unsigned int;
diff --git a/cmds/lshal/Timeout.h b/cmds/lshal/Timeout.h
index ca477bf..c940404 100644
--- a/cmds/lshal/Timeout.h
+++ b/cmds/lshal/Timeout.h
@@ -77,14 +77,15 @@
     return success;
 }
 
-template<class Function, class I, class... Args>
+template<class R, class P, class Function, class I, class... Args>
 typename std::result_of<Function(I *, Args...)>::type
-timeoutIPC(const sp<I> &interfaceObject, Function &&func, Args &&... args) {
+timeoutIPC(std::chrono::duration<R, P> wait, const sp<I> &interfaceObject, Function &&func,
+           Args &&... args) {
     using ::android::hardware::Status;
     typename std::result_of<Function(I *, Args...)>::type ret{Status::ok()};
     auto boundFunc = std::bind(std::forward<Function>(func),
             interfaceObject.get(), std::forward<Args>(args)...);
-    bool success = timeout(IPC_CALL_WAIT, [&ret, &boundFunc] {
+    bool success = timeout(wait, [&ret, &boundFunc] {
         ret = std::move(boundFunc());
     });
     if (!success) {
@@ -93,5 +94,12 @@
     return ret;
 }
 
+template<class Function, class I, class... Args>
+typename std::result_of<Function(I *, Args...)>::type
+timeoutIPC(const sp<I> &interfaceObject, Function &&func, Args &&... args) {
+    return timeoutIPC(IPC_CALL_WAIT, interfaceObject, func, args...);
+}
+
+
 }  // namespace lshal
 }  // namespace android
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
index 39d92a7..d3d396f 100644
--- a/cmds/servicemanager/Android.bp
+++ b/cmds/servicemanager/Android.bp
@@ -46,7 +46,6 @@
     cflags: [
         "-DVENDORSERVICEMANAGER=1",
     ],
-    shared_libs: ["libcutils"],
-    static_libs: ["libselinux"],
+    shared_libs: ["libcutils", "libselinux_vendor"],
     init_rc: ["vndservicemanager.rc"],
 }
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index 45bb1d0..d5cfcaf 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -287,7 +287,11 @@
     }
 
     if (sehandle && selinux_status_updated() > 0) {
+#ifdef VENDORSERVICEMANAGER
+        struct selabel_handle *tmp_sehandle = selinux_android_vendor_service_context_handle();
+#else
         struct selabel_handle *tmp_sehandle = selinux_android_service_context_handle();
+#endif
         if (tmp_sehandle) {
             selabel_close(sehandle);
             sehandle = tmp_sehandle;
diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc
index aec211a..d336a43 100644
--- a/cmds/servicemanager/servicemanager.rc
+++ b/cmds/servicemanager/servicemanager.rc
@@ -12,3 +12,4 @@
     onrestart restart drm
     onrestart restart cameraserver
     writepid /dev/cpuset/system-background/tasks
+    shutdown critical
diff --git a/cmds/servicemanager/vndservicemanager.rc b/cmds/servicemanager/vndservicemanager.rc
index d5ddaaf..3fa4d7d 100644
--- a/cmds/servicemanager/vndservicemanager.rc
+++ b/cmds/servicemanager/vndservicemanager.rc
@@ -3,4 +3,4 @@
     user system
     group system readproc
     writepid /dev/cpuset/system-background/tasks
-
+    shutdown critical
diff --git a/cmds/surfacereplayer/Android.bp b/cmds/surfacereplayer/Android.bp
new file mode 100644
index 0000000..d4c037a
--- /dev/null
+++ b/cmds/surfacereplayer/Android.bp
@@ -0,0 +1,4 @@
+subdirs = [
+    "proto",
+    "replayer",
+]
\ No newline at end of file
diff --git a/cmds/surfacereplayer/proto/Android.bp b/cmds/surfacereplayer/proto/Android.bp
new file mode 100644
index 0000000..dda80bb
--- /dev/null
+++ b/cmds/surfacereplayer/proto/Android.bp
@@ -0,0 +1,10 @@
+cc_library_static {
+    name: "libtrace_proto",
+    srcs: [
+        "src/trace.proto",
+    ],
+    proto: {
+        type: "lite",
+        export_proto_headers: true,
+    },
+}
diff --git a/cmds/surfacereplayer/proto/Android.mk b/cmds/surfacereplayer/proto/Android.mk
deleted file mode 100644
index 3cf1148..0000000
--- a/cmds/surfacereplayer/proto/Android.mk
+++ /dev/null
@@ -1,28 +0,0 @@
-#
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-proto-files-under, src)
-
-LOCAL_PROTOC_OPTIMIZE_TYPE := lite
-
-LOCAL_MODULE := libtrace_proto
-LOCAL_MODULE_CLASS := STATIC_LIBRARIES
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/cmds/surfacereplayer/replayer/Android.bp b/cmds/surfacereplayer/replayer/Android.bp
new file mode 100644
index 0000000..5caceec
--- /dev/null
+++ b/cmds/surfacereplayer/replayer/Android.bp
@@ -0,0 +1,66 @@
+cc_library_shared {
+    name: "libsurfacereplayer",
+    clang: true,
+    srcs: [
+        "BufferQueueScheduler.cpp",
+        "Event.cpp",
+        "Replayer.cpp",
+    ],
+    cppflags: [
+        "-Werror",
+        "-Wno-unused-parameter",
+        "-Wno-format",
+	"-Wno-c++98-compat-pedantic",
+	"-Wno-float-conversion",
+	"-Wno-disabled-macro-expansion",
+	"-Wno-float-equal",
+	"-Wno-sign-conversion",
+	"-Wno-padded",
+	"-std=c++14",
+    ],
+    static_libs: [
+        "libtrace_proto",
+    ],
+    shared_libs: [
+        "libEGL",
+        "libGLESv2",
+        "libbinder",
+        "liblog",
+        "libcutils",
+        "libgui",
+        "libui",
+        "libutils",
+        "libprotobuf-cpp-lite",
+        "libbase",
+        "libnativewindow",
+    ],
+    export_include_dirs: [
+        ".",
+    ],
+}
+
+cc_binary {
+    name: "surfacereplayer",
+    clang: true,
+    srcs: [
+        "Main.cpp",
+    ],
+    shared_libs: [
+        "libprotobuf-cpp-lite",
+        "libsurfacereplayer",
+        "libutils",
+        "libgui",
+    ],
+    static_libs: [
+        "libtrace_proto",
+    ],
+    cppflags: [
+        "-Werror",
+        "-Wno-unused-parameter",
+	"-Wno-c++98-compat-pedantic",
+	"-Wno-float-conversion",
+	"-Wno-disabled-macro-expansion",
+	"-Wno-float-equal",
+	"-std=c++14",
+    ],
+}
diff --git a/cmds/surfacereplayer/replayer/Android.mk b/cmds/surfacereplayer/replayer/Android.mk
deleted file mode 100644
index 1dd926c..0000000
--- a/cmds/surfacereplayer/replayer/Android.mk
+++ /dev/null
@@ -1,75 +0,0 @@
-# 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.
-
-LOCAL_TARGET_DIR := $(TARGET_OUT_DATA)/local/tmp
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(call first-makefiles-under, /frameworks/native/cmds/surfacereplayer/proto)
-
-include $(CLEAR_VARS)
-
-LOCAL_CPPFLAGS := -Weverything -Werror
-LOCAL_CPPFLAGS := -Wno-unused-parameter
-LOCAL_CPPFLAGS := -Wno-format
-
-LOCAL_MODULE := libsurfacereplayer
-
-LOCAL_SRC_FILES := \
-    BufferQueueScheduler.cpp \
-    Event.cpp \
-    Replayer.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
-    libEGL \
-    libGLESv2 \
-    libbinder \
-    liblog \
-    libcutils \
-    libgui \
-    libui \
-    libutils \
-    libprotobuf-cpp-lite \
-    libbase \
-    libnativewindow \
-
-LOCAL_STATIC_LIBRARIES := \
-    libtrace_proto \
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/..
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := surfacereplayer
-
-LOCAL_SRC_FILES := \
-    Main.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
-    libprotobuf-cpp-lite \
-    libsurfacereplayer \
-    libutils \
-    libgui \
-
-LOCAL_STATIC_LIBRARIES := \
-    libtrace_proto \
-
-LOCAL_CPPFLAGS := -Weverything -Werror
-LOCAL_CPPFLAGS := -Wno-unused-parameter
-
-LOCAL_MODULE_PATH := $(LOCAL_TARGET_DIR)
-
-include $(BUILD_EXECUTABLE)
diff --git a/cmds/surfacereplayer/replayer/Main.cpp b/cmds/surfacereplayer/replayer/Main.cpp
index dd1dd7d..7090bdb 100644
--- a/cmds/surfacereplayer/replayer/Main.cpp
+++ b/cmds/surfacereplayer/replayer/Main.cpp
@@ -24,7 +24,7 @@
  * 5. Exit successfully or print error statement
  */
 
-#include <replayer/Replayer.h>
+#include <Replayer.h>
 
 #include <csignal>
 #include <iostream>
diff --git a/data/etc/android.hardware.radio.xml b/data/etc/android.hardware.radio.xml
new file mode 100644
index 0000000..f718c47
--- /dev/null
+++ b/data/etc/android.hardware.radio.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- This is the standard set of features for a broadcast radio. -->
+<permissions>
+    <feature name="android.hardware.radio" />
+</permissions>
diff --git a/data/etc/android.hardware.telephony.euicc.xml b/data/etc/android.hardware.telephony.euicc.xml
new file mode 100644
index 0000000..167ed6a
--- /dev/null
+++ b/data/etc/android.hardware.telephony.euicc.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Feature for devices with an eUICC. -->
+<permissions>
+    <feature name="android.hardware.telephony.euicc" />
+</permissions>
diff --git a/data/etc/android.hardware.wifi.passpoint.xml b/data/etc/android.hardware.wifi.passpoint.xml
new file mode 100644
index 0000000..4698bb3
--- /dev/null
+++ b/data/etc/android.hardware.wifi.passpoint.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- This is the standard feature indicating that the device includes WiFi Passpoint. -->
+<permissions>
+    <feature name="android.hardware.wifi.passpoint" />
+</permissions>
diff --git a/include/android/sensor.h b/include/android/sensor.h
index cdb3fff..97b4a2a 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -50,6 +50,7 @@
 
 #include <android/looper.h>
 
+#include <stdbool.h>
 #include <sys/types.h>
 #include <math.h>
 #include <stdint.h>
diff --git a/include/gui b/include/gui
new file mode 120000
index 0000000..3b796f3
--- /dev/null
+++ b/include/gui
@@ -0,0 +1 @@
+../libs/gui/include/gui
\ No newline at end of file
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index f31bcea..efa1ffb 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -65,6 +65,7 @@
             nsecs_t eventTime __attribute__((aligned(8)));
             int32_t deviceId;
             int32_t source;
+            int32_t displayId;
             int32_t action;
             int32_t flags;
             int32_t keyCode;
@@ -83,6 +84,7 @@
             nsecs_t eventTime __attribute__((aligned(8)));
             int32_t deviceId;
             int32_t source;
+            int32_t displayId;
             int32_t action;
             int32_t actionButton;
             int32_t flags;
@@ -232,6 +234,7 @@
             uint32_t seq,
             int32_t deviceId,
             int32_t source,
+            int32_t displayId,
             int32_t action,
             int32_t actionButton,
             int32_t flags,
@@ -303,7 +306,7 @@
      * Other errors probably indicate that the channel is broken.
      */
     status_t consume(InputEventFactoryInterface* factory, bool consumeBatches,
-            nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent);
+            nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId);
 
     /* Sends a finished signal to the publisher to inform it that the message
      * with the specified sequence number has finished being process and whether
@@ -424,9 +427,10 @@
     Vector<SeqChain> mSeqChains;
 
     status_t consumeBatch(InputEventFactoryInterface* factory,
-            nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent);
+            nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId);
     status_t consumeSamples(InputEventFactoryInterface* factory,
-            Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent);
+            Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent,
+            int32_t* displayId);
 
     void updateTouchState(InputMessage* msg);
     void rewriteMessage(const TouchState& state, InputMessage* msg);
diff --git a/include/media/hardware/HDCPAPI.h b/include/media/hardware/HDCPAPI.h
index 30cd5fd..7797bb2 100644
--- a/include/media/hardware/HDCPAPI.h
+++ b/include/media/hardware/HDCPAPI.h
@@ -15,11 +15,10 @@
  */
 
 #ifndef HDCP_API_H_
-
 #define HDCP_API_H_
 
 #include <utils/Errors.h>
-#include <system/window.h>
+#include <cutils/native_handle.h>
 
 namespace android {
 
diff --git a/include/media/hardware/HardwareAPI.h b/include/media/hardware/HardwareAPI.h
index cecf715..6c1ba3d 100644
--- a/include/media/hardware/HardwareAPI.h
+++ b/include/media/hardware/HardwareAPI.h
@@ -20,13 +20,15 @@
 
 #include <media/hardware/OMXPluginBase.h>
 #include <media/hardware/MetadataBufferType.h>
-#include <system/window.h>
+#include <cutils/native_handle.h>
 #include <utils/RefBase.h>
 
 #include "VideoAPI.h"
 
 #include <OMX_Component.h>
 
+struct ANativeWindowBuffer;
+
 namespace android {
 
 // This structure is used to enable Android native buffer use for either
diff --git a/include/private/gui b/include/private/gui
new file mode 120000
index 0000000..99de2dc
--- /dev/null
+++ b/include/private/gui
@@ -0,0 +1 @@
+../../libs/gui/include/private/gui
\ No newline at end of file
diff --git a/include/ui b/include/ui
new file mode 120000
index 0000000..2fb3147
--- /dev/null
+++ b/include/ui
@@ -0,0 +1 @@
+../libs/ui/include/ui
\ No newline at end of file
diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp
index 0d25176..a20154f 100644
--- a/libs/arect/Android.bp
+++ b/libs/arect/Android.bp
@@ -23,5 +23,6 @@
 cc_library_static {
     name: "libarect",
     host_supported: true,
+    vendor_available: true,
     export_include_dirs: ["include"],
 }
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 204fdb5..3a353c2 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -15,6 +15,7 @@
 cc_library_headers {
     name: "libbinder_headers",
     export_include_dirs: ["include"],
+    vendor_available: true,
 }
 
 cc_library {
@@ -74,13 +75,18 @@
         "libcutils",
         "libutils",
     ],
+
+    header_libs: [
+        "libbinder_headers",
+    ],
+
     export_shared_lib_headers: [
         "libbase",
         "libutils",
     ],
 
-    export_include_dirs: [
-        "include",
+    export_header_lib_headers: [
+        "libbinder_headers",
     ],
 
     clang: true,
diff --git a/libs/binder/include/binder/Parcelable.h b/libs/binder/include/binder/Parcelable.h
index d5b57ac..a9166e2 100644
--- a/libs/binder/include/binder/Parcelable.h
+++ b/libs/binder/include/binder/Parcelable.h
@@ -36,6 +36,9 @@
 public:
     virtual ~Parcelable() = default;
 
+    Parcelable() = default;
+    Parcelable(const Parcelable&) = default;
+
     // Write |this| parcelable to the given |parcel|.  Keep in mind that
     // implementations of writeToParcel must be manually kept in sync
     // with readFromParcel and the Java equivalent versions of these methods.
diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp
new file mode 100644
index 0000000..f2686d5
--- /dev/null
+++ b/libs/graphicsenv/Android.bp
@@ -0,0 +1,28 @@
+// Copyright (C) 2017 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.
+
+cc_library_shared {
+    name: "libgraphicsenv",
+
+    srcs: [
+        "GraphicsEnv.cpp",
+    ],
+
+    shared_libs: [
+        "libnativeloader",
+        "liblog",
+    ],
+
+    export_include_dirs: ["include"],
+}
diff --git a/libs/ui/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
similarity index 98%
rename from libs/ui/GraphicsEnv.cpp
rename to libs/graphicsenv/GraphicsEnv.cpp
index 8182c07..39b5829 100644
--- a/libs/ui/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -16,7 +16,7 @@
 
 //#define LOG_NDEBUG 1
 #define LOG_TAG "GraphicsEnv"
-#include <ui/GraphicsEnv.h>
+#include <graphicsenv/GraphicsEnv.h>
 
 #include <mutex>
 
diff --git a/include/ui/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
similarity index 100%
rename from include/ui/GraphicsEnv.h
rename to libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index a07726a..4558fe8 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -11,9 +11,15 @@
 // 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.
+cc_library_headers {
+    name: "libgui_headers",
+    vendor_available: true,
+    export_include_dirs: ["include"],
+}
 
 cc_library_shared {
     name: "libgui",
+    vendor_available: true,
 
     clang: true,
     cppflags: [
@@ -111,20 +117,30 @@
         "liblog",
         "libhidlbase",
         "libhidltransport",
-        "android.hidl.base@1.0",
         "android.hidl.token@1.0-utils",
         "android.hardware.graphics.bufferqueue@1.0",
         "android.hardware.configstore@1.0",
         "android.hardware.configstore-utils",
     ],
 
+    header_libs: [
+        "libnativebase_headers",
+        "libgui_headers",
+    ],
+
     export_shared_lib_headers: [
         "libbinder",
+        "libEGL",
+        "libnativewindow",
         "libui",
         "android.hidl.token@1.0-utils",
         "android.hardware.graphics.bufferqueue@1.0",
     ],
 
+    export_header_lib_headers: [
+        "libgui_headers",
+    ],
+
     export_include_dirs: [
         "include",
     ],
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 5e5de44..168d355 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -36,6 +36,8 @@
 #include <binder/PermissionCache.h>
 #include <private/android_filesystem_config.h>
 
+#include <system/window.h>
+
 namespace android {
 
 BufferQueueConsumer::BufferQueueConsumer(const sp<BufferQueueCore>& core) :
@@ -701,9 +703,9 @@
     return NO_ERROR;
 }
 
-status_t BufferQueueConsumer::setConsumerUsageBits(uint32_t usage) {
+status_t BufferQueueConsumer::setConsumerUsageBits(uint64_t usage) {
     ATRACE_CALL();
-    BQ_LOGV("setConsumerUsageBits: %#x", usage);
+    BQ_LOGV("setConsumerUsageBits: %#" PRIx64, usage);
     Mutex::Autolock lock(mCore->mMutex);
     mCore->mConsumerUsageBits = usage;
     return NO_ERROR;
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index cfb25e0..bb703da 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -38,6 +38,8 @@
 #include <gui/ISurfaceComposer.h>
 #include <private/gui/ComposerService.h>
 
+#include <system/window.h>
+
 namespace android {
 
 static String8 getUniqueName() {
@@ -110,54 +112,60 @@
 void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const {
     Mutex::Autolock lock(mMutex);
 
-    String8 fifo;
+    outResult->appendFormat("%s- BufferQueue ", prefix.string());
+    outResult->appendFormat("mMaxAcquiredBufferCount=%d mMaxDequeuedBufferCount=%d\n",
+                            mMaxAcquiredBufferCount, mMaxDequeuedBufferCount);
+    outResult->appendFormat("%s  mDequeueBufferCannotBlock=%d mAsyncMode=%d\n", prefix.string(),
+                            mDequeueBufferCannotBlock, mAsyncMode);
+    outResult->appendFormat("%s  default-size=[%dx%d] default-format=%d ", prefix.string(),
+                            mDefaultWidth, mDefaultHeight, mDefaultBufferFormat);
+    outResult->appendFormat("transform-hint=%02x frame-counter=%" PRIu64, mTransformHint,
+                            mFrameCounter);
+
+    outResult->appendFormat("\n%sFIFO(%zu):\n", prefix.string(), mQueue.size());
     Fifo::const_iterator current(mQueue.begin());
     while (current != mQueue.end()) {
-        fifo.appendFormat("%02d:%p crop=[%d,%d,%d,%d], "
-                "xform=0x%02x, time=%#" PRIx64 ", scale=%s\n",
-                current->mSlot, current->mGraphicBuffer.get(),
-                current->mCrop.left, current->mCrop.top, current->mCrop.right,
-                current->mCrop.bottom, current->mTransform, current->mTimestamp,
-                BufferItem::scalingModeName(current->mScalingMode));
+        double timestamp = current->mTimestamp / 1e9;
+        outResult->appendFormat("%s  %02d:%p ", prefix.string(), current->mSlot,
+                                current->mGraphicBuffer.get());
+        outResult->appendFormat("crop=[%d,%d,%d,%d] ", current->mCrop.left, current->mCrop.top,
+                                current->mCrop.right, current->mCrop.bottom);
+        outResult->appendFormat("xform=0x%02x time=%.4f scale=%s\n", current->mTransform, timestamp,
+                                BufferItem::scalingModeName(current->mScalingMode));
         ++current;
     }
 
-    outResult->appendFormat("%s-BufferQueue mMaxAcquiredBufferCount=%d, "
-            "mMaxDequeuedBufferCount=%d, mDequeueBufferCannotBlock=%d "
-            "mAsyncMode=%d, default-size=[%dx%d], default-format=%d, "
-            "transform-hint=%02x, FIFO(%zu)={%s}\n", prefix.string(),
-            mMaxAcquiredBufferCount, mMaxDequeuedBufferCount,
-            mDequeueBufferCannotBlock, mAsyncMode, mDefaultWidth,
-            mDefaultHeight, mDefaultBufferFormat, mTransformHint, mQueue.size(),
-            fifo.string());
-
+    outResult->appendFormat("%sSlots:\n", prefix.string());
     for (int s : mActiveBuffers) {
         const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
         // A dequeued buffer might be null if it's still being allocated
         if (buffer.get()) {
-            outResult->appendFormat("%s%s[%02d:%p] state=%-8s, %p "
-                    "[%4ux%4u:%4u,%3X]\n", prefix.string(),
-                    (mSlots[s].mBufferState.isAcquired()) ? ">" : " ", s,
-                    buffer.get(), mSlots[s].mBufferState.string(),
-                    buffer->handle, buffer->width, buffer->height,
-                    buffer->stride, buffer->format);
+            outResult->appendFormat("%s %s[%02d:%p] ", prefix.string(),
+                                    (mSlots[s].mBufferState.isAcquired()) ? ">" : " ", s,
+                                    buffer.get());
+            outResult->appendFormat("state=%-8s %p frame=%" PRIu64, mSlots[s].mBufferState.string(),
+                                    buffer->handle, mSlots[s].mFrameNumber);
+            outResult->appendFormat(" [%4ux%4u:%4u,%3X]\n", buffer->width, buffer->height,
+                                    buffer->stride, buffer->format);
         } else {
-            outResult->appendFormat("%s [%02d:%p] state=%-8s\n", prefix.string(), s,
-                    buffer.get(), mSlots[s].mBufferState.string());
+            outResult->appendFormat("%s  [%02d:%p] ", prefix.string(), s, buffer.get());
+            outResult->appendFormat("state=%-8s frame=%" PRIu64 "\n",
+                                    mSlots[s].mBufferState.string(), mSlots[s].mFrameNumber);
         }
     }
     for (int s : mFreeBuffers) {
         const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
-        outResult->appendFormat("%s [%02d:%p] state=%-8s, %p [%4ux%4u:%4u,%3X]\n",
-                prefix.string(), s, buffer.get(), mSlots[s].mBufferState.string(),
-                buffer->handle, buffer->width, buffer->height, buffer->stride,
-                buffer->format);
+        outResult->appendFormat("%s  [%02d:%p] ", prefix.string(), s, buffer.get());
+        outResult->appendFormat("state=%-8s %p frame=%" PRIu64, mSlots[s].mBufferState.string(),
+                                buffer->handle, mSlots[s].mFrameNumber);
+        outResult->appendFormat(" [%4ux%4u:%4u,%3X]\n", buffer->width, buffer->height,
+                                buffer->stride, buffer->format);
     }
 
     for (int s : mFreeSlots) {
         const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
-        outResult->appendFormat("%s [%02d:%p] state=%-8s\n", prefix.string(), s,
-                buffer.get(), mSlots[s].mBufferState.string());
+        outResult->appendFormat("%s  [%02d:%p] state=%-8s\n", prefix.string(), s, buffer.get(),
+                                mSlots[s].mBufferState.string());
     }
 }
 
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 8385864..3d94a02 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -39,6 +39,8 @@
 #include <utils/Log.h>
 #include <utils/Trace.h>
 
+#include <system/window.h>
+
 namespace android {
 
 static constexpr uint32_t BQ_LAYER_COUNT = 1;
@@ -347,7 +349,7 @@
 
 status_t BufferQueueProducer::dequeueBuffer(int *outSlot,
         sp<android::Fence> *outFence, uint32_t width, uint32_t height,
-        PixelFormat format, uint32_t usage,
+        PixelFormat format, uint64_t usage,
         FrameEventHistoryDelta* outTimestamps) {
     ATRACE_CALL();
     { // Autolock scope
@@ -365,8 +367,7 @@
         }
     } // Autolock scope
 
-    BQ_LOGV("dequeueBuffer: w=%u h=%u format=%#x, usage=%#x", width, height,
-            format, usage);
+    BQ_LOGV("dequeueBuffer: w=%u h=%u format=%#x, usage=%#" PRIx64, width, height, format, usage);
 
     if ((width && !height) || (!width && height)) {
         BQ_LOGE("dequeueBuffer: invalid size: w=%u h=%u", width, height);
@@ -416,11 +417,9 @@
             // buffer. If this buffer would require reallocation to meet the
             // requested attributes, we free it and attempt to get another one.
             if (!mCore->mAllowAllocation) {
-                if (buffer->needsReallocation(width, height, format,
-                        BQ_LAYER_COUNT, usage)) {
+                if (buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage)) {
                     if (mCore->mSharedBufferSlot == found) {
-                        BQ_LOGE("dequeueBuffer: cannot re-allocate a shared"
-                                "buffer");
+                        BQ_LOGE("dequeueBuffer: cannot re-allocate a sharedbuffer");
                         return BAD_VALUE;
                     }
                     mCore->mFreeSlots.insert(found);
@@ -433,8 +432,7 @@
 
         const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
         if (mCore->mSharedBufferSlot == found &&
-                buffer->needsReallocation(width, height, format,
-                        BQ_LAYER_COUNT, usage)) {
+                buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage)) {
             BQ_LOGE("dequeueBuffer: cannot re-allocate a shared"
                     "buffer");
 
@@ -468,8 +466,7 @@
         } else {
             // We add 1 because that will be the frame number when this buffer
             // is queued
-            mCore->mBufferAge =
-                    mCore->mFrameCounter + 1 - mSlots[found].mFrameNumber;
+            mCore->mBufferAge = mCore->mFrameCounter + 1 - mSlots[found].mFrameNumber;
         }
 
         BQ_LOGV("dequeueBuffer: setting buffer age to %" PRIu64,
@@ -1319,14 +1316,14 @@
 }
 
 void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height,
-        PixelFormat format, uint32_t usage) {
+        PixelFormat format, uint64_t usage) {
     ATRACE_CALL();
     while (true) {
         size_t newBufferCount = 0;
         uint32_t allocWidth = 0;
         uint32_t allocHeight = 0;
         PixelFormat allocFormat = PIXEL_FORMAT_UNKNOWN;
-        uint32_t allocUsage = 0;
+        uint64_t allocUsage = 0;
         { // Autolock scope
             Mutex::Autolock lock(mCore->mMutex);
             mCore->waitWhileAllocatingLocked();
@@ -1360,7 +1357,7 @@
 
             if (result != NO_ERROR) {
                 BQ_LOGE("allocateBuffers: failed to allocate buffer (%u x %u, format"
-                        " %u, usage %u)", width, height, format, usage);
+                        " %u, usage %#" PRIx64 ")", width, height, format, usage);
                 Mutex::Autolock lock(mCore->mMutex);
                 mCore->mIsAllocating = false;
                 mCore->mIsAllocatingCondition.broadcast();
@@ -1375,7 +1372,7 @@
             uint32_t checkHeight = height > 0 ? height : mCore->mDefaultHeight;
             PixelFormat checkFormat = format != 0 ?
                     format : mCore->mDefaultBufferFormat;
-            uint32_t checkUsage = usage | mCore->mConsumerUsageBits;
+            uint64_t checkUsage = usage | mCore->mConsumerUsageBits;
             if (checkWidth != allocWidth || checkHeight != allocHeight ||
                 checkFormat != allocFormat || checkUsage != allocUsage) {
                 // Something changed while we released the lock. Retry.
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index c654f08..34c9d78 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -21,6 +21,8 @@
 #define GL_GLEXT_PROTOTYPES
 #define EGL_EGLEXT_PROTOTYPES
 
+#include <inttypes.h>
+
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 #include <GLES2/gl2.h>
@@ -1219,7 +1221,7 @@
         mEglDisplay = EGL_NO_DISPLAY;
         mCropRect.makeInvalid();
         const sp<GraphicBuffer>& buffer = mGraphicBuffer;
-        ALOGE("Failed to create image. size=%ux%u st=%u usage=0x%x fmt=%d",
+        ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
             buffer->getWidth(), buffer->getHeight(), buffer->getStride(),
             buffer->getUsage(), buffer->getPixelFormat());
         return UNKNOWN_ERROR;
diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp
index a573bee..c705d39 100644
--- a/libs/gui/IGraphicBufferConsumer.cpp
+++ b/libs/gui/IGraphicBufferConsumer.cpp
@@ -132,7 +132,7 @@
         return callRemote<Signature>(Tag::SET_DEFAULT_BUFFER_DATA_SPACE, defaultDataSpace);
     }
 
-    status_t setConsumerUsageBits(uint32_t usage) override {
+    status_t setConsumerUsageBits(uint64_t usage) override {
         using Signature = decltype(&IGraphicBufferConsumer::setConsumerUsageBits);
         return callRemote<Signature>(Tag::SET_CONSUMER_USAGE_BITS, usage);
     }
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index bca645f..1b0fe06 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -73,7 +73,7 @@
     {
     }
 
-    virtual ~BpGraphicBufferProducer();
+    ~BpGraphicBufferProducer() override;
 
     virtual status_t requestBuffer(int bufferIdx, sp<GraphicBuffer>* buf) {
         Parcel data, reply;
@@ -125,7 +125,7 @@
     }
 
     virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, uint32_t width,
-            uint32_t height, PixelFormat format, uint32_t usage,
+            uint32_t height, PixelFormat format, uint64_t usage,
             FrameEventHistoryDelta* outTimestamps) {
         Parcel data, reply;
         bool getFrameTimestamps = (outTimestamps != nullptr);
@@ -134,7 +134,7 @@
         data.writeUint32(width);
         data.writeUint32(height);
         data.writeInt32(static_cast<int32_t>(format));
-        data.writeUint32(usage);
+        data.writeUint64(usage);
         data.writeBool(getFrameTimestamps);
 
         status_t result = remote()->transact(DEQUEUE_BUFFER, data, &reply);
@@ -333,13 +333,13 @@
     }
 
     virtual void allocateBuffers(uint32_t width, uint32_t height,
-            PixelFormat format, uint32_t usage) {
+            PixelFormat format, uint64_t usage) {
         Parcel data, reply;
         data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
         data.writeUint32(width);
         data.writeUint32(height);
         data.writeInt32(static_cast<int32_t>(format));
-        data.writeUint32(usage);
+        data.writeUint64(usage);
         status_t result = remote()->transact(ALLOCATE_BUFFERS, data, &reply);
         if (result != NO_ERROR) {
             ALOGE("allocateBuffers failed to transact: %d", result);
@@ -517,7 +517,7 @@
     }
 
     status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h,
-            PixelFormat format, uint32_t usage,
+            PixelFormat format, uint64_t usage,
             FrameEventHistoryDelta* outTimestamps) override {
         return mBase->dequeueBuffer(
                 slot, fence, w, h, format, usage, outTimestamps);
@@ -569,7 +569,7 @@
     }
 
     void allocateBuffers(uint32_t width, uint32_t height,
-            PixelFormat format, uint32_t usage) override {
+            PixelFormat format, uint64_t usage) override {
         return mBase->allocateBuffers(width, height, format, usage);
     }
 
@@ -654,7 +654,7 @@
             uint32_t width = data.readUint32();
             uint32_t height = data.readUint32();
             PixelFormat format = static_cast<PixelFormat>(data.readInt32());
-            uint32_t usage = data.readUint32();
+            uint64_t usage = data.readUint64();
             bool getTimestamps = data.readBool();
 
             int buf = 0;
@@ -777,7 +777,7 @@
             uint32_t width = data.readUint32();
             uint32_t height = data.readUint32();
             PixelFormat format = static_cast<PixelFormat>(data.readInt32());
-            uint32_t usage = data.readUint32();
+            uint64_t usage = data.readUint64();
             allocateBuffers(width, height, format, usage);
             return NO_ERROR;
         }
diff --git a/libs/gui/StreamSplitter.cpp b/libs/gui/StreamSplitter.cpp
index bafe947..52c9067 100644
--- a/libs/gui/StreamSplitter.cpp
+++ b/libs/gui/StreamSplitter.cpp
@@ -31,6 +31,8 @@
 
 #include <utils/Trace.h>
 
+#include <system/window.h>
+
 namespace android {
 
 status_t StreamSplitter::createSplitter(
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 7b2b5c3..409a3cb 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -20,6 +20,8 @@
 
 #include <gui/Surface.h>
 
+#include <inttypes.h>
+
 #include <android/native_window.h>
 
 #include <utils/Log.h>
@@ -471,7 +473,7 @@
     uint32_t reqWidth;
     uint32_t reqHeight;
     PixelFormat reqFormat;
-    uint32_t reqUsage;
+    uint64_t reqUsage;
     bool enableFrameTimestamps;
 
     {
@@ -511,8 +513,8 @@
 
     if (result < 0) {
         ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer"
-                "(%d, %d, %d, %d) failed: %d", reqWidth, reqHeight, reqFormat,
-                reqUsage, result);
+                "(%d, %d, %d, %#" PRIx64 ") failed: %d",
+                reqWidth, reqHeight, reqFormat, reqUsage, result);
         return result;
     }
 
@@ -962,6 +964,9 @@
     case NATIVE_WINDOW_GET_HDR_SUPPORT:
         res = dispatchGetHdrSupport(args);
         break;
+    case NATIVE_WINDOW_SET_USAGE64:
+        res = dispatchSetUsage64(args);
+        break;
     default:
         res = NAME_NOT_FOUND;
         break;
@@ -980,8 +985,13 @@
 }
 
 int Surface::dispatchSetUsage(va_list args) {
-    int usage = va_arg(args, int);
-    return setUsage(static_cast<uint32_t>(usage));
+    uint64_t usage = va_arg(args, uint32_t);
+    return setUsage(usage);
+}
+
+int Surface::dispatchSetUsage64(va_list args) {
+    uint64_t usage = va_arg(args, uint64_t);
+    return setUsage(usage);
 }
 
 int Surface::dispatchSetCrop(va_list args) {
@@ -1259,8 +1269,7 @@
     uint32_t priorGeneration = graphicBuffer->mGenerationNumber;
     graphicBuffer->mGenerationNumber = mGenerationNumber;
     int32_t attachedSlot = -1;
-    status_t result = mGraphicBufferProducer->attachBuffer(
-            &attachedSlot, graphicBuffer);
+    status_t result = mGraphicBufferProducer->attachBuffer(&attachedSlot, graphicBuffer);
     if (result != NO_ERROR) {
         ALOGE("attachBuffer: IGraphicBufferProducer call failed (%d)", result);
         graphicBuffer->mGenerationNumber = priorGeneration;
@@ -1274,7 +1283,7 @@
     return NO_ERROR;
 }
 
-int Surface::setUsage(uint32_t reqUsage)
+int Surface::setUsage(uint64_t reqUsage)
 {
     ALOGV("Surface::setUsage");
     Mutex::Autolock lock(mMutex);
@@ -1521,6 +1530,9 @@
         const Region& reg,
         int *dstFenceFd)
 {
+    if (dst->getId() == src->getId())
+        return OK;
+
     // src and dst with, height and format must be identical. no verification
     // is done here.
     status_t err;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 8c83843..7ae2672 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1080,5 +1080,9 @@
     return mBuffer.stride * mBuffer.height * bytesPerPixel(mBuffer.format);
 }
 
+android_dataspace ScreenshotClient::getDataSpace() const {
+    return mBuffer.dataSpace;
+}
+
 // ----------------------------------------------------------------------------
 }; // namespace android
diff --git a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
index fda5b94..7c0552e 100644
--- a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
+++ b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
@@ -125,7 +125,7 @@
     t->attr.stride = l.getStride();
     t->attr.format = static_cast<PixelFormat>(l.getPixelFormat());
     t->attr.layerCount = l.getLayerCount();
-    t->attr.usage = l.getUsage();
+    t->attr.usage = uint32_t(l.getUsage());     // FIXME: need 64-bits usage version
     t->attr.id = l.getId();
     t->attr.generationNumber = l.getGenerationNumber();
     t->nativeHandle = hidl_handle(l.handle);
@@ -988,14 +988,15 @@
     return toStatusT(mBase->setAsyncMode(async));
 }
 
+// FIXME: usage bits truncated -- needs a 64-bits usage version
 status_t H2BGraphicBufferProducer::dequeueBuffer(
         int* slot, sp<Fence>* fence,
         uint32_t w, uint32_t h, ::android::PixelFormat format,
-        uint32_t usage, FrameEventHistoryDelta* outTimestamps) {
+        uint64_t usage, FrameEventHistoryDelta* outTimestamps) {
     *fence = new Fence();
     status_t fnStatus;
     status_t transStatus = toStatusT(mBase->dequeueBuffer(
-            w, h, static_cast<PixelFormat>(format), usage,
+            w, h, static_cast<PixelFormat>(format), uint32_t(usage),
             outTimestamps != nullptr,
             [&fnStatus, slot, fence, outTimestamps] (
                     Status status,
@@ -1144,10 +1145,11 @@
     return toStatusT(mBase->setSidebandStream(stream == nullptr ? nullptr : stream->handle()));
 }
 
+// FIXME: usage bits truncated -- needs a 64-bits usage version
 void H2BGraphicBufferProducer::allocateBuffers(uint32_t width, uint32_t height,
-        ::android::PixelFormat format, uint32_t usage) {
+        ::android::PixelFormat format, uint64_t usage) {
     mBase->allocateBuffers(
-            width, height, static_cast<PixelFormat>(format), usage);
+            width, height, static_cast<PixelFormat>(format), uint32_t(usage));
 }
 
 status_t H2BGraphicBufferProducer::allowAllocation(bool allow) {
diff --git a/include/gui/BufferItem.h b/libs/gui/include/gui/BufferItem.h
similarity index 100%
rename from include/gui/BufferItem.h
rename to libs/gui/include/gui/BufferItem.h
diff --git a/include/gui/BufferItemConsumer.h b/libs/gui/include/gui/BufferItemConsumer.h
similarity index 98%
rename from include/gui/BufferItemConsumer.h
rename to libs/gui/include/gui/BufferItemConsumer.h
index db7e944..217fe6a 100644
--- a/include/gui/BufferItemConsumer.h
+++ b/libs/gui/include/gui/BufferItemConsumer.h
@@ -55,7 +55,7 @@
             uint32_t consumerUsage, int bufferCount = DEFAULT_MAX_BUFFERS,
             bool controlledByApp = false);
 
-    virtual ~BufferItemConsumer();
+    ~BufferItemConsumer() override;
 
     // set the name of the BufferItemConsumer that will be used to identify it in
     // log messages.
diff --git a/include/gui/BufferQueue.h b/libs/gui/include/gui/BufferQueue.h
similarity index 98%
rename from include/gui/BufferQueue.h
rename to libs/gui/include/gui/BufferQueue.h
index bd62d85..ba5cbf7 100644
--- a/include/gui/BufferQueue.h
+++ b/libs/gui/include/gui/BufferQueue.h
@@ -57,7 +57,7 @@
     class ProxyConsumerListener : public BnConsumerListener {
     public:
         explicit ProxyConsumerListener(const wp<ConsumerListener>& consumerListener);
-        virtual ~ProxyConsumerListener();
+        ~ProxyConsumerListener() override;
         void onDisconnect() override;
         void onFrameAvailable(const BufferItem& item) override;
         void onFrameReplaced(const BufferItem& item) override;
diff --git a/include/gui/BufferQueueConsumer.h b/libs/gui/include/gui/BufferQueueConsumer.h
similarity index 97%
rename from include/gui/BufferQueueConsumer.h
rename to libs/gui/include/gui/BufferQueueConsumer.h
index b383056..d108120 100644
--- a/include/gui/BufferQueueConsumer.h
+++ b/libs/gui/include/gui/BufferQueueConsumer.h
@@ -32,7 +32,7 @@
 
 public:
     BufferQueueConsumer(const sp<BufferQueueCore>& core);
-    virtual ~BufferQueueConsumer();
+    ~BufferQueueConsumer() override;
 
     // acquireBuffer attempts to acquire ownership of the next pending buffer in
     // the BufferQueue. If no buffer is pending then it returns
@@ -121,13 +121,12 @@
     // GraphicBuffers of a defaultDataSpace if no data space is specified
     // in queueBuffer.
     // The initial default is HAL_DATASPACE_UNKNOWN
-    virtual status_t setDefaultBufferDataSpace(
-            android_dataspace defaultDataSpace);
+    virtual status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace);
 
     // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer.
     // These are merged with the bits passed to dequeueBuffer.  The values are
     // enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0.
-    virtual status_t setConsumerUsageBits(uint32_t usage);
+    virtual status_t setConsumerUsageBits(uint64_t usage) override;
 
     // setConsumerIsProtected will turn on an internal bit that indicates whether
     // the consumer can handle protected gralloc buffers (i.e. with
diff --git a/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h
similarity index 99%
rename from include/gui/BufferQueueCore.h
rename to libs/gui/include/gui/BufferQueueCore.h
index dd8b992..537c957 100644
--- a/include/gui/BufferQueueCore.h
+++ b/libs/gui/include/gui/BufferQueueCore.h
@@ -170,7 +170,7 @@
 
     // mConsumerUsageBits contains flags that the consumer wants for
     // GraphicBuffers.
-    uint32_t mConsumerUsageBits;
+    uint64_t mConsumerUsageBits;
 
     // mConsumerIsProtected indicates the consumer is ready to handle protected
     // buffer.
diff --git a/include/gui/BufferQueueDefs.h b/libs/gui/include/gui/BufferQueueDefs.h
similarity index 100%
rename from include/gui/BufferQueueDefs.h
rename to libs/gui/include/gui/BufferQueueDefs.h
diff --git a/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h
similarity index 97%
rename from include/gui/BufferQueueProducer.h
rename to libs/gui/include/gui/BufferQueueProducer.h
index 5541468..0f8917a 100644
--- a/include/gui/BufferQueueProducer.h
+++ b/libs/gui/include/gui/BufferQueueProducer.h
@@ -30,7 +30,7 @@
     friend class BufferQueue; // Needed to access binderDied
 
     BufferQueueProducer(const sp<BufferQueueCore>& core, bool consumerIsSurfaceFlinger = false);
-    virtual ~BufferQueueProducer();
+    ~BufferQueueProducer() override;
 
     // requestBuffer returns the GraphicBuffer for slot N.
     //
@@ -80,9 +80,9 @@
     //
     // In both cases, the producer will need to call requestBuffer to get a
     // GraphicBuffer handle for the returned slot.
-    status_t dequeueBuffer(int *outSlot, sp<Fence>* outFence,
+    virtual status_t dequeueBuffer(int *outSlot, sp<Fence>* outFence,
             uint32_t width, uint32_t height, PixelFormat format,
-            uint32_t usage, FrameEventHistoryDelta* outTimestamps) override;
+            uint64_t usage, FrameEventHistoryDelta* outTimestamps) override;
 
     // See IGraphicBufferProducer::detachBuffer
     virtual status_t detachBuffer(int slot);
@@ -152,7 +152,7 @@
 
     // See IGraphicBufferProducer::allocateBuffers
     virtual void allocateBuffers(uint32_t width, uint32_t height,
-            PixelFormat format, uint32_t usage);
+            PixelFormat format, uint64_t usage) override;
 
     // See IGraphicBufferProducer::allowAllocation
     virtual status_t allowAllocation(bool allow);
diff --git a/include/gui/BufferSlot.h b/libs/gui/include/gui/BufferSlot.h
similarity index 100%
rename from include/gui/BufferSlot.h
rename to libs/gui/include/gui/BufferSlot.h
diff --git a/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h
similarity index 99%
rename from include/gui/ConsumerBase.h
rename to libs/gui/include/gui/ConsumerBase.h
index 891290b..e9fc8fd 100644
--- a/include/gui/ConsumerBase.h
+++ b/libs/gui/include/gui/ConsumerBase.h
@@ -47,7 +47,7 @@
         virtual void onFrameReplaced(const BufferItem& /* item */) {}
     };
 
-    virtual ~ConsumerBase();
+    ~ConsumerBase() override;
 
     // abandon frees all the buffers and puts the ConsumerBase into the
     // 'abandoned' state.  Once put in this state the ConsumerBase can never
diff --git a/include/gui/CpuConsumer.h b/libs/gui/include/gui/CpuConsumer.h
similarity index 100%
rename from include/gui/CpuConsumer.h
rename to libs/gui/include/gui/CpuConsumer.h
diff --git a/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
similarity index 100%
rename from include/gui/DisplayEventReceiver.h
rename to libs/gui/include/gui/DisplayEventReceiver.h
diff --git a/include/gui/FrameTimestamps.h b/libs/gui/include/gui/FrameTimestamps.h
similarity index 100%
rename from include/gui/FrameTimestamps.h
rename to libs/gui/include/gui/FrameTimestamps.h
diff --git a/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h
similarity index 100%
rename from include/gui/GLConsumer.h
rename to libs/gui/include/gui/GLConsumer.h
diff --git a/include/gui/GuiConfig.h b/libs/gui/include/gui/GuiConfig.h
similarity index 100%
rename from include/gui/GuiConfig.h
rename to libs/gui/include/gui/GuiConfig.h
diff --git a/include/gui/IConsumerListener.h b/libs/gui/include/gui/IConsumerListener.h
similarity index 100%
rename from include/gui/IConsumerListener.h
rename to libs/gui/include/gui/IConsumerListener.h
diff --git a/include/gui/IDisplayEventConnection.h b/libs/gui/include/gui/IDisplayEventConnection.h
similarity index 100%
rename from include/gui/IDisplayEventConnection.h
rename to libs/gui/include/gui/IDisplayEventConnection.h
diff --git a/include/gui/IGraphicBufferConsumer.h b/libs/gui/include/gui/IGraphicBufferConsumer.h
similarity index 99%
rename from include/gui/IGraphicBufferConsumer.h
rename to libs/gui/include/gui/IGraphicBufferConsumer.h
index 3d069df..9fb7580 100644
--- a/include/gui/IGraphicBufferConsumer.h
+++ b/libs/gui/include/gui/IGraphicBufferConsumer.h
@@ -241,7 +241,7 @@
     // e.g. GRALLOC_USAGE_HW_RENDER; the default is 0.
     //
     // Return of a value other than NO_ERROR means an unknown error has occurred.
-    virtual status_t setConsumerUsageBits(uint32_t usage) = 0;
+    virtual status_t setConsumerUsageBits(uint64_t usage) = 0;
 
     // setConsumerIsProtected will turn on an internal bit that indicates whether
     // the consumer can handle protected gralloc buffers (i.e. with
diff --git a/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h
similarity index 99%
rename from include/gui/IGraphicBufferProducer.h
rename to libs/gui/include/gui/IGraphicBufferProducer.h
index 9250806..6d16e74 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -195,7 +195,7 @@
     // All other negative values are an unknown error returned downstream
     // from the graphics allocator (typically errno).
     virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w,
-            uint32_t h, PixelFormat format, uint32_t usage,
+            uint32_t h, PixelFormat format, uint64_t usage,
             FrameEventHistoryDelta* outTimestamps) = 0;
 
     // detachBuffer attempts to remove all ownership of the buffer in the given
@@ -517,7 +517,7 @@
     // dequeueBuffer. If there are already the maximum number of buffers
     // allocated, this function has no effect.
     virtual void allocateBuffers(uint32_t width, uint32_t height,
-            PixelFormat format, uint32_t usage) = 0;
+            PixelFormat format, uint64_t usage) = 0;
 
     // Sets whether dequeueBuffer is allowed to allocate new buffers.
     //
diff --git a/include/gui/IProducerListener.h b/libs/gui/include/gui/IProducerListener.h
similarity index 100%
rename from include/gui/IProducerListener.h
rename to libs/gui/include/gui/IProducerListener.h
diff --git a/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
similarity index 100%
rename from include/gui/ISurfaceComposer.h
rename to libs/gui/include/gui/ISurfaceComposer.h
diff --git a/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h
similarity index 100%
rename from include/gui/ISurfaceComposerClient.h
rename to libs/gui/include/gui/ISurfaceComposerClient.h
diff --git a/include/gui/OccupancyTracker.h b/libs/gui/include/gui/OccupancyTracker.h
similarity index 100%
rename from include/gui/OccupancyTracker.h
rename to libs/gui/include/gui/OccupancyTracker.h
diff --git a/include/gui/StreamSplitter.h b/libs/gui/include/gui/StreamSplitter.h
similarity index 100%
rename from include/gui/StreamSplitter.h
rename to libs/gui/include/gui/StreamSplitter.h
diff --git a/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
similarity index 98%
rename from include/gui/Surface.h
rename to libs/gui/include/gui/Surface.h
index e8dc83e..0f7e12a 100644
--- a/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -27,7 +27,7 @@
 #include <utils/Mutex.h>
 #include <utils/RefBase.h>
 
-struct ANativeWindow_Buffer;
+#include <system/window.h>
 
 namespace android {
 
@@ -207,8 +207,8 @@
     int dispatchSetBuffersStickyTransform(va_list args);
     int dispatchSetBuffersTimestamp(va_list args);
     int dispatchSetCrop(va_list args);
-    int dispatchSetPostTransformCrop(va_list args);
     int dispatchSetUsage(va_list args);
+    int dispatchSetUsage64(va_list args);
     int dispatchLock(va_list args);
     int dispatchUnlockAndPost(va_list args);
     int dispatchSetSidebandStream(va_list args);
@@ -242,7 +242,7 @@
     virtual int setBuffersTimestamp(int64_t timestamp);
     virtual int setBuffersDataSpace(android_dataspace dataSpace);
     virtual int setCrop(Rect const* rect);
-    virtual int setUsage(uint32_t reqUsage);
+    virtual int setUsage(uint64_t reqUsage);
     virtual void setSurfaceDamage(android_native_rect_t* rects, size_t numRects);
 
 public:
@@ -321,7 +321,7 @@
 
     // mReqUsage is the set of buffer usage flags that will be requested
     // at the next deuque operation. It is initialized to 0.
-    uint32_t mReqUsage;
+    uint64_t mReqUsage;
 
     // mTimestamp is the timestamp that will be used for the next buffer queue
     // operation. It defaults to NATIVE_WINDOW_TIMESTAMP_AUTO, which means that
diff --git a/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
similarity index 99%
rename from include/gui/SurfaceComposerClient.h
rename to libs/gui/include/gui/SurfaceComposerClient.h
index ec310cf..145c059 100644
--- a/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -271,6 +271,7 @@
     uint32_t getStride() const;
     // size of allocated memory in bytes
     size_t getSize() const;
+    android_dataspace getDataSpace() const;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
similarity index 100%
rename from include/gui/SurfaceControl.h
rename to libs/gui/include/gui/SurfaceControl.h
diff --git a/include/gui/bufferqueue/1.0/B2HProducerListener.h b/libs/gui/include/gui/bufferqueue/1.0/B2HProducerListener.h
similarity index 100%
rename from include/gui/bufferqueue/1.0/B2HProducerListener.h
rename to libs/gui/include/gui/bufferqueue/1.0/B2HProducerListener.h
diff --git a/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
similarity index 96%
rename from include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
rename to libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
index 93c452a..c3a9d44 100644
--- a/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
+++ b/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
@@ -65,7 +65,7 @@
     status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) override;
     status_t setAsyncMode(bool async) override;
     status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w,
-            uint32_t h, ::android::PixelFormat format, uint32_t usage,
+            uint32_t h, ::android::PixelFormat format, uint64_t usage,
             FrameEventHistoryDelta* outTimestamps) override;
     status_t detachBuffer(int slot) override;
     status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence)
@@ -83,7 +83,7 @@
             override;
     status_t setSidebandStream(const sp<NativeHandle>& stream) override;
     void allocateBuffers(uint32_t width, uint32_t height,
-            ::android::PixelFormat format, uint32_t usage) override;
+            ::android::PixelFormat format, uint64_t usage) override;
     status_t allowAllocation(bool allow) override;
     status_t setGenerationNumber(uint32_t generationNumber) override;
     String8 getConsumerName() const override;
diff --git a/include/gui/view/Surface.h b/libs/gui/include/gui/view/Surface.h
similarity index 100%
rename from include/gui/view/Surface.h
rename to libs/gui/include/gui/view/Surface.h
diff --git a/include/private/gui/ComposerService.h b/libs/gui/include/private/gui/ComposerService.h
similarity index 100%
rename from include/private/gui/ComposerService.h
rename to libs/gui/include/private/gui/ComposerService.h
diff --git a/include/private/gui/LayerState.h b/libs/gui/include/private/gui/LayerState.h
similarity index 100%
rename from include/private/gui/LayerState.h
rename to libs/gui/include/private/gui/LayerState.h
diff --git a/include/private/gui/SyncFeatures.h b/libs/gui/include/private/gui/SyncFeatures.h
similarity index 100%
rename from include/private/gui/SyncFeatures.h
rename to libs/gui/include/private/gui/SyncFeatures.h
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 7efdb14..fa87f29 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -4,6 +4,7 @@
 // to integrate with auto-test framework.
 cc_test {
     name: "libgui_test",
+    test_suites: ["device-tests"],
 
     clang: true,
 
diff --git a/libs/gui/tests/AndroidTest.xml b/libs/gui/tests/AndroidTest.xml
new file mode 100644
index 0000000..c02e020
--- /dev/null
+++ b/libs/gui/tests/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<configuration description="Config for libgui_test">
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="libgui_test->/data/local/tmp/libgui_test" />
+    </target_preparer>
+    <option name="test-suite-tag" value="apct" />
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="libgui_test" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 60c1277..4220aaf 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -32,6 +32,8 @@
 #include <utils/String8.h>
 #include <utils/threads.h>
 
+#include <system/window.h>
+
 #include <gtest/gtest.h>
 
 #include <thread>
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index aa071f6..bcfc91c 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -29,6 +29,8 @@
 #include <gui/BufferQueue.h>
 #include <gui/IProducerListener.h>
 
+#include <system/window.h>
+
 #include <vector>
 
 #define ASSERT_OK(x) ASSERT_EQ(OK, (x))
diff --git a/libs/gui/tests/Malicious.cpp b/libs/gui/tests/Malicious.cpp
index 7ecf08c..6bc3ccf 100644
--- a/libs/gui/tests/Malicious.cpp
+++ b/libs/gui/tests/Malicious.cpp
@@ -38,7 +38,7 @@
     }
     status_t setAsyncMode(bool async) override { return mProducer->setAsyncMode(async); }
     status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h, PixelFormat format,
-                           uint32_t usage, FrameEventHistoryDelta* outTimestamps) override {
+                           uint64_t usage, FrameEventHistoryDelta* outTimestamps) override {
         return mProducer->dequeueBuffer(slot, fence, w, h, format, usage, outTimestamps);
     }
     status_t detachBuffer(int slot) override { return mProducer->detachBuffer(slot); }
@@ -67,7 +67,7 @@
         return mProducer->setSidebandStream(stream);
     }
     void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format,
-                         uint32_t usage) override {
+                         uint64_t usage) override {
         mProducer->allocateBuffers(width, height, format, usage);
     }
     status_t allowAllocation(bool allow) override { return mProducer->allowAllocation(allow); }
@@ -105,7 +105,7 @@
 
     // Override dequeueBuffer, optionally corrupting the returned slot number
     status_t dequeueBuffer(int* buf, sp<Fence>* fence, uint32_t width, uint32_t height,
-                           PixelFormat format, uint32_t usage,
+                           PixelFormat format, uint64_t usage,
                            FrameEventHistoryDelta* outTimestamps) override {
         EXPECT_EQ(BUFFER_NEEDS_REALLOCATION,
                   mProducer->dequeueBuffer(buf, fence, width, height, format, usage,
diff --git a/libs/gui/tests/StreamSplitter_test.cpp b/libs/gui/tests/StreamSplitter_test.cpp
index 80e30da..e2f4948 100644
--- a/libs/gui/tests/StreamSplitter_test.cpp
+++ b/libs/gui/tests/StreamSplitter_test.cpp
@@ -24,6 +24,8 @@
 #include <gui/StreamSplitter.h>
 #include <private/gui/ComposerService.h>
 
+#include <system/window.h>
+
 #include <gtest/gtest.h>
 
 namespace android {
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index af1c0af..d5c5927 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -285,6 +285,7 @@
         uint32_t seq,
         int32_t deviceId,
         int32_t source,
+        int32_t displayId,
         int32_t action,
         int32_t actionButton,
         int32_t flags,
@@ -327,6 +328,7 @@
     msg.body.motion.seq = seq;
     msg.body.motion.deviceId = deviceId;
     msg.body.motion.source = source;
+    msg.body.motion.displayId = displayId;
     msg.body.motion.action = action;
     msg.body.motion.actionButton = actionButton;
     msg.body.motion.flags = flags;
@@ -396,7 +398,8 @@
 }
 
 status_t InputConsumer::consume(InputEventFactoryInterface* factory,
-        bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
+        bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent,
+        int32_t* displayId) {
 #if DEBUG_TRANSPORT_ACTIONS
     ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%lld",
             mChannel->getName().string(), consumeBatches ? "true" : "false", frameTime);
@@ -404,6 +407,7 @@
 
     *outSeq = 0;
     *outEvent = NULL;
+    *displayId = -1;  // Invalid display.
 
     // Fetch the next input message.
     // Loop until an event can be returned or no additional events are received.
@@ -418,7 +422,7 @@
             if (result) {
                 // Consume the next batched event unless batches are being held for later.
                 if (consumeBatches || result != WOULD_BLOCK) {
-                    result = consumeBatch(factory, frameTime, outSeq, outEvent);
+                    result = consumeBatch(factory, frameTime, outSeq, outEvent, displayId);
                     if (*outEvent) {
 #if DEBUG_TRANSPORT_ACTIONS
                         ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u",
@@ -462,7 +466,7 @@
                     // the previous batch right now and defer the new message until later.
                     mMsgDeferred = true;
                     status_t result = consumeSamples(factory,
-                            batch, batch.samples.size(), outSeq, outEvent);
+                            batch, batch.samples.size(), outSeq, outEvent, displayId);
                     mBatches.removeAt(batchIndex);
                     if (result) {
                         return result;
@@ -496,6 +500,7 @@
             initializeMotionEvent(motionEvent, &mMsg);
             *outSeq = mMsg.body.motion.seq;
             *outEvent = motionEvent;
+            *displayId = mMsg.body.motion.displayId;
 #if DEBUG_TRANSPORT_ACTIONS
             ALOGD("channel '%s' consumer ~ consumed motion event, seq=%u",
                     mChannel->getName().string(), *outSeq);
@@ -513,14 +518,14 @@
 }
 
 status_t InputConsumer::consumeBatch(InputEventFactoryInterface* factory,
-        nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
+        nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId) {
     status_t result;
     for (size_t i = mBatches.size(); i > 0; ) {
         i--;
         Batch& batch = mBatches.editItemAt(i);
         if (frameTime < 0) {
             result = consumeSamples(factory, batch, batch.samples.size(),
-                    outSeq, outEvent);
+                    outSeq, outEvent, displayId);
             mBatches.removeAt(i);
             return result;
         }
@@ -534,7 +539,7 @@
             continue;
         }
 
-        result = consumeSamples(factory, batch, split + 1, outSeq, outEvent);
+        result = consumeSamples(factory, batch, split + 1, outSeq, outEvent, displayId);
         const InputMessage* next;
         if (batch.samples.isEmpty()) {
             mBatches.removeAt(i);
@@ -552,7 +557,7 @@
 }
 
 status_t InputConsumer::consumeSamples(InputEventFactoryInterface* factory,
-        Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent) {
+        Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId) {
     MotionEvent* motionEvent = factory->createMotionEvent();
     if (! motionEvent) return NO_MEMORY;
 
@@ -567,6 +572,7 @@
             mSeqChains.push(seqChain);
             addSample(motionEvent, &msg);
         } else {
+            *displayId = msg.body.motion.displayId;
             initializeMotionEvent(motionEvent, &msg);
         }
         chain = msg.body.motion.seq;
@@ -842,15 +848,14 @@
         }
         if (status) {
             // An error occurred so at least one signal was not sent, reconstruct the chain.
-            do {
+            for (;;) {
                 SeqChain seqChain;
                 seqChain.seq = chainIndex != 0 ? chainSeqs[chainIndex - 1] : seq;
                 seqChain.chain = chainSeqs[chainIndex];
                 mSeqChains.push(seqChain);
-                if (chainIndex != 0) {
-                    chainIndex--;
-                }
-            } while (chainIndex > 0);
+                if (!chainIndex) break;
+                chainIndex--;
+            }
             return status;
         }
     }
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 8e69c9c..a136738 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -89,7 +89,8 @@
 
     uint32_t consumeSeq;
     InputEvent* event;
-    status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
+    status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event,
+            0);
     ASSERT_EQ(OK, status)
             << "consumer consume should return OK";
 
@@ -132,6 +133,7 @@
     const uint32_t seq = 15;
     const int32_t deviceId = 1;
     const int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
+    const int32_t displayId = 0;
     const int32_t action = AMOTION_EVENT_ACTION_MOVE;
     const int32_t actionButton = 0;
     const int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
@@ -164,7 +166,7 @@
         pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i);
     }
 
-    status = mPublisher->publishMotionEvent(seq, deviceId, source, action, actionButton,
+    status = mPublisher->publishMotionEvent(seq, deviceId, source, displayId, action, actionButton,
             flags, edgeFlags, metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision,
             downTime, eventTime, pointerCount,
             pointerProperties, pointerCoords);
@@ -173,7 +175,8 @@
 
     uint32_t consumeSeq;
     InputEvent* event;
-    status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
+    status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event,
+            0);
     ASSERT_EQ(OK, status)
             << "consumer consume should return OK";
 
@@ -256,7 +259,7 @@
     PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
 
-    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(BAD_VALUE, status)
             << "publisher publishMotionEvent should return BAD_VALUE";
@@ -272,7 +275,7 @@
         pointerCoords[i].clear();
     }
 
-    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(BAD_VALUE, status)
             << "publisher publishMotionEvent should return BAD_VALUE";
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index 81b9953..d19f3b8 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -38,31 +38,33 @@
   CHECK_OFFSET(InputMessage::Body::Key, eventTime, 8);
   CHECK_OFFSET(InputMessage::Body::Key, deviceId, 16);
   CHECK_OFFSET(InputMessage::Body::Key, source, 20);
-  CHECK_OFFSET(InputMessage::Body::Key, action, 24);
-  CHECK_OFFSET(InputMessage::Body::Key, flags, 28);
-  CHECK_OFFSET(InputMessage::Body::Key, keyCode, 32);
-  CHECK_OFFSET(InputMessage::Body::Key, scanCode, 36);
-  CHECK_OFFSET(InputMessage::Body::Key, metaState, 40);
-  CHECK_OFFSET(InputMessage::Body::Key, repeatCount, 44);
-  CHECK_OFFSET(InputMessage::Body::Key, downTime, 48);
+  CHECK_OFFSET(InputMessage::Body::Key, displayId, 24);
+  CHECK_OFFSET(InputMessage::Body::Key, action, 28);
+  CHECK_OFFSET(InputMessage::Body::Key, flags, 32);
+  CHECK_OFFSET(InputMessage::Body::Key, keyCode, 36);
+  CHECK_OFFSET(InputMessage::Body::Key, scanCode, 40);
+  CHECK_OFFSET(InputMessage::Body::Key, metaState, 44);
+  CHECK_OFFSET(InputMessage::Body::Key, repeatCount, 48);
+  CHECK_OFFSET(InputMessage::Body::Key, downTime, 56);
 
   CHECK_OFFSET(InputMessage::Body::Motion, seq, 0);
   CHECK_OFFSET(InputMessage::Body::Motion, eventTime, 8);
   CHECK_OFFSET(InputMessage::Body::Motion, deviceId, 16);
   CHECK_OFFSET(InputMessage::Body::Motion, source, 20);
-  CHECK_OFFSET(InputMessage::Body::Motion, action, 24);
-  CHECK_OFFSET(InputMessage::Body::Motion, actionButton, 28);
-  CHECK_OFFSET(InputMessage::Body::Motion, flags, 32);
-  CHECK_OFFSET(InputMessage::Body::Motion, metaState, 36);
-  CHECK_OFFSET(InputMessage::Body::Motion, buttonState, 40);
-  CHECK_OFFSET(InputMessage::Body::Motion, edgeFlags, 44);
-  CHECK_OFFSET(InputMessage::Body::Motion, downTime, 48);
-  CHECK_OFFSET(InputMessage::Body::Motion, xOffset, 56);
-  CHECK_OFFSET(InputMessage::Body::Motion, yOffset, 60);
-  CHECK_OFFSET(InputMessage::Body::Motion, xPrecision, 64);
-  CHECK_OFFSET(InputMessage::Body::Motion, yPrecision, 68);
-  CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 72);
-  CHECK_OFFSET(InputMessage::Body::Motion, pointers, 80);
+  CHECK_OFFSET(InputMessage::Body::Motion, displayId, 24);
+  CHECK_OFFSET(InputMessage::Body::Motion, action, 28);
+  CHECK_OFFSET(InputMessage::Body::Motion, actionButton, 32);
+  CHECK_OFFSET(InputMessage::Body::Motion, flags, 36);
+  CHECK_OFFSET(InputMessage::Body::Motion, metaState, 40);
+  CHECK_OFFSET(InputMessage::Body::Motion, buttonState, 44);
+  CHECK_OFFSET(InputMessage::Body::Motion, edgeFlags, 48);
+  CHECK_OFFSET(InputMessage::Body::Motion, downTime, 56);
+  CHECK_OFFSET(InputMessage::Body::Motion, xOffset, 64);
+  CHECK_OFFSET(InputMessage::Body::Motion, yOffset, 68);
+  CHECK_OFFSET(InputMessage::Body::Motion, xPrecision, 72);
+  CHECK_OFFSET(InputMessage::Body::Motion, yPrecision, 76);
+  CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 80);
+  CHECK_OFFSET(InputMessage::Body::Motion, pointers, 88);
 }
 
 } // namespace android
diff --git a/libs/math/Android.bp b/libs/math/Android.bp
index 3ef8b4a..693bace 100644
--- a/libs/math/Android.bp
+++ b/libs/math/Android.bp
@@ -15,6 +15,7 @@
 cc_library_static {
     name: "libmath",
     host_supported: true,
+    vendor_available: true,
     export_include_dirs: ["include"],
 }
 
diff --git a/libs/math/include/math/TMatHelpers.h b/libs/math/include/math/TMatHelpers.h
index 5cb725d..1423ade 100644
--- a/libs/math/include/math/TMatHelpers.h
+++ b/libs/math/include/math/TMatHelpers.h
@@ -342,9 +342,9 @@
 template <typename MATRIX>
 String8 asString(const MATRIX& m) {
     String8 s;
-    for (size_t c = 0; c < MATRIX::col_size(); c++) {
+    for (size_t c = 0; c < MATRIX::COL_SIZE; c++) {
         s.append("|  ");
-        for (size_t r = 0; r < MATRIX::row_size(); r++) {
+        for (size_t r = 0; r < MATRIX::ROW_SIZE; r++) {
             s.appendFormat("%7.2f  ", m[r][c]);
         }
         s.append("|\n");
diff --git a/libs/math/include/math/half.h b/libs/math/include/math/half.h
index 615b840..7682973 100644
--- a/libs/math/include/math/half.h
+++ b/libs/math/include/math/half.h
@@ -56,8 +56,8 @@
  */
 class half {
     struct fp16 {
-        uint16_t bits = 0;
-        fp16() noexcept = default;
+        uint16_t bits;
+        explicit constexpr fp16() noexcept : bits(0) { }
         explicit constexpr fp16(uint16_t b) noexcept : bits(b) { }
         void setS(unsigned int s) noexcept { bits = uint16_t((bits & 0x7FFF) | (s<<15)); }
         void setE(unsigned int s) noexcept { bits = uint16_t((bits & 0xE3FF) | (s<<10)); }
@@ -68,11 +68,11 @@
     };
     struct fp32 {
         union {
-            uint32_t bits = 0;
+            uint32_t bits;
             float fp;
         };
-        fp32() noexcept = default;
-        explicit constexpr fp32(float f) : fp(f) { }
+        explicit constexpr fp32() noexcept : bits(0) { }
+        explicit constexpr fp32(float f) noexcept : fp(f) { }
         void setS(unsigned int s) noexcept { bits = uint32_t((bits & 0x7FFFFFFF) | (s<<31)); }
         void setE(unsigned int s) noexcept { bits = uint32_t((bits & 0x807FFFFF) | (s<<23)); }
         void setM(unsigned int s) noexcept { bits = uint32_t((bits & 0xFF800000) | (s<< 0)); }
diff --git a/libs/math/tests/mat_test.cpp b/libs/math/tests/mat_test.cpp
index c365366..3217a1a 100644
--- a/libs/math/tests/mat_test.cpp
+++ b/libs/math/tests/mat_test.cpp
@@ -487,7 +487,7 @@
         for (size_t i = 0; i < v1.size(); ++i) {                \
             EXPECT_FLOAT_EQ(v1[i], v2[i]);                      \
         }                                                       \
-    } else if (std::is_same<TypeParam,float>::value) {          \
+    } else if (std::is_same<TypeParam,double>::value) {         \
         for (size_t i = 0; i < v1.size(); ++i) {                \
             EXPECT_DOUBLE_EQ(v1[i], v2[i]);                     \
         }                                                       \
@@ -506,7 +506,7 @@
     const decltype(T2) t2 = T2;                                 \
     if (std::is_same<TypeParam,float>::value) {                 \
         ASSERT_FLOAT_EQ(t1, t2);                                \
-    } else if (std::is_same<TypeParam,float>::value) {         \
+    } else if (std::is_same<TypeParam,double>::value) {         \
         ASSERT_DOUBLE_EQ(t1, t2);                               \
     } else {                                                    \
         ASSERT_EQ(t1, t2);                                      \
diff --git a/libs/nativebase/Android.bp b/libs/nativebase/Android.bp
new file mode 100644
index 0000000..7375a2b
--- /dev/null
+++ b/libs/nativebase/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2017 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.
+
+cc_library_headers {
+    name: "libnativebase_headers",
+    vendor_available: true,
+    host_supported: true,
+    export_include_dirs: ["include"],
+
+    target: {
+        linux_bionic: {
+            enabled: true,
+        },
+        windows: {
+            enabled: true,
+        },
+    }
+}
diff --git a/libs/nativebase/MODULE_LICENSE_APACHE2 b/libs/nativebase/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libs/nativebase/MODULE_LICENSE_APACHE2
diff --git a/libs/nativebase/NOTICE b/libs/nativebase/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/libs/nativebase/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, 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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/libs/nativebase/include/nativebase/nativebase.h b/libs/nativebase/include/nativebase/nativebase.h
new file mode 100644
index 0000000..7ecdfbd
--- /dev/null
+++ b/libs/nativebase/include/nativebase/nativebase.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/cdefs.h>
+#include <system/graphics-base.h>
+#include <cutils/native_handle.h>
+
+__BEGIN_DECLS
+
+#ifdef __cplusplus
+#define ANDROID_NATIVE_UNSIGNED_CAST(x) static_cast<unsigned int>(x)
+#else
+#define ANDROID_NATIVE_UNSIGNED_CAST(x) ((unsigned int)(x))
+#endif
+
+#define ANDROID_NATIVE_MAKE_CONSTANT(a,b,c,d)  \
+    ((ANDROID_NATIVE_UNSIGNED_CAST(a) << 24) | \
+     (ANDROID_NATIVE_UNSIGNED_CAST(b) << 16) | \
+     (ANDROID_NATIVE_UNSIGNED_CAST(c) <<  8) | \
+     (ANDROID_NATIVE_UNSIGNED_CAST(d)))
+
+#define ANDROID_NATIVE_BUFFER_MAGIC     ANDROID_NATIVE_MAKE_CONSTANT('_','b','f','r')
+
+
+typedef struct android_native_base_t
+{
+    /* a magic value defined by the actual EGL native type */
+    int magic;
+
+    /* the sizeof() of the actual EGL native type */
+    int version;
+
+    void* reserved[4];
+
+    /* reference-counting interface */
+    void (*incRef)(struct android_native_base_t* base);
+    void (*decRef)(struct android_native_base_t* base);
+} android_native_base_t;
+
+typedef struct android_native_rect_t
+{
+    int32_t left;
+    int32_t top;
+    int32_t right;
+    int32_t bottom;
+} android_native_rect_t;
+
+typedef struct ANativeWindowBuffer
+{
+#ifdef __cplusplus
+    ANativeWindowBuffer() {
+        common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
+        common.version = sizeof(ANativeWindowBuffer);
+        memset(common.reserved, 0, sizeof(common.reserved));
+    }
+
+    // Implement the methods that sp<ANativeWindowBuffer> expects so that it
+    // can be used to automatically refcount ANativeWindowBuffer's.
+    void incStrong(const void* /*id*/) const {
+        common.incRef(const_cast<android_native_base_t*>(&common));
+    }
+    void decStrong(const void* /*id*/) const {
+        common.decRef(const_cast<android_native_base_t*>(&common));
+    }
+#endif
+
+    struct android_native_base_t common;
+
+    int width;
+    int height;
+    int stride;
+    int format;
+    int usage_deprecated;
+    uintptr_t layerCount;
+
+    void* reserved[1];
+
+    const native_handle_t* handle;
+    uint64_t usage;
+
+    // we needed extra space for storing the 64-bits usage flags
+    // the number of slots to use from reserved_proc depends on the
+    // architecture.
+    void* reserved_proc[8 - (sizeof(uint64_t) / sizeof(void*))];
+} ANativeWindowBuffer_t;
+
+typedef struct ANativeWindowBuffer ANativeWindowBuffer;
+
+// Old typedef for backwards compatibility.
+typedef ANativeWindowBuffer_t android_native_buffer_t;
+
+__END_DECLS
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index f64bab1..c6994c3 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -16,8 +16,6 @@
 
 #define LOG_TAG "ANativeWindow"
 
-#include <android/native_window.h>
-
 #include <grallocusage/GrallocUsageConversion.h>
 // from nativewindow/includes/system/window.h
 // (not to be confused with the compatibility-only window.h from system/core/includes)
@@ -192,8 +190,7 @@
 }
 
 int ANativeWindow_setUsage(ANativeWindow* window, uint64_t usage) {
-    usage = AHardwareBuffer_convertToGrallocUsageBits(usage);
-    return native_window_set_usage(window, (uint32_t)usage); // FIXME: we need a 64-bits version
+    return native_window_set_usage(window, usage);
 }
 
 int ANativeWindow_setBufferCount(ANativeWindow* window, size_t bufferCount) {
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index d759acb..e61fbd6 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -57,10 +57,25 @@
         "libgrallocusage",
     ],
 
+    header_libs: [
+        "libnativebase_headers",
+    ],
+
     // headers we include in our public headers
     export_static_lib_headers: [
         "libarect",
     ],
+
+    export_header_lib_headers: [
+        "libnativebase_headers",
+    ],
+}
+
+llndk_library {
+    name: "libnativewindow",
+    symbol_file: "libnativewindow.map.txt",
+    unversioned: true,
+    export_include_dirs: ["include"],
 }
 
 subdirs = ["tests"]
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 45110c4..3df97a1 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -60,25 +60,6 @@
 
 // ---------------------------------------------------------------------------
 
-typedef const native_handle_t* buffer_handle_t;
-
-// ---------------------------------------------------------------------------
-
-typedef struct android_native_rect_t
-{
-    int32_t left;
-    int32_t top;
-    int32_t right;
-    int32_t bottom;
-} android_native_rect_t;
-
-// ---------------------------------------------------------------------------
-
-// Old typedef for backwards compatibility.
-typedef ANativeWindowBuffer_t android_native_buffer_t;
-
-// ---------------------------------------------------------------------------
-
 /* attributes queriable with query() */
 enum {
     NATIVE_WINDOW_WIDTH     = 0,
@@ -212,36 +193,37 @@
  */
 enum {
 // clang-format off
-    NATIVE_WINDOW_SET_USAGE                 =  0,
-    NATIVE_WINDOW_CONNECT                   =  1,   /* deprecated */
-    NATIVE_WINDOW_DISCONNECT                =  2,   /* deprecated */
-    NATIVE_WINDOW_SET_CROP                  =  3,   /* private */
-    NATIVE_WINDOW_SET_BUFFER_COUNT          =  4,
-    NATIVE_WINDOW_SET_BUFFERS_GEOMETRY      =  5,   /* deprecated */
-    NATIVE_WINDOW_SET_BUFFERS_TRANSFORM     =  6,
-    NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP     =  7,
-    NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS    =  8,
-    NATIVE_WINDOW_SET_BUFFERS_FORMAT        =  9,
-    NATIVE_WINDOW_SET_SCALING_MODE          = 10,   /* private */
-    NATIVE_WINDOW_LOCK                      = 11,   /* private */
-    NATIVE_WINDOW_UNLOCK_AND_POST           = 12,   /* private */
-    NATIVE_WINDOW_API_CONNECT               = 13,   /* private */
-    NATIVE_WINDOW_API_DISCONNECT            = 14,   /* private */
-    NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */
-    NATIVE_WINDOW_SET_POST_TRANSFORM_CROP   = 16,   /* private */
-    NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17,/* private */
-    NATIVE_WINDOW_SET_SIDEBAND_STREAM       = 18,
-    NATIVE_WINDOW_SET_BUFFERS_DATASPACE     = 19,
-    NATIVE_WINDOW_SET_SURFACE_DAMAGE        = 20,   /* private */
-    NATIVE_WINDOW_SET_SHARED_BUFFER_MODE    = 21,
-    NATIVE_WINDOW_SET_AUTO_REFRESH          = 22,
-    NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION= 23,
-    NATIVE_WINDOW_GET_NEXT_FRAME_ID         = 24,
-    NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS   = 25,
-    NATIVE_WINDOW_GET_COMPOSITOR_TIMING     = 26,
-    NATIVE_WINDOW_GET_FRAME_TIMESTAMPS      = 27,
-    NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT    = 28,
-    NATIVE_WINDOW_GET_HDR_SUPPORT           = 29,
+    NATIVE_WINDOW_SET_USAGE                     =  0,   /* deprecated */
+    NATIVE_WINDOW_CONNECT                       =  1,   /* deprecated */
+    NATIVE_WINDOW_DISCONNECT                    =  2,   /* deprecated */
+    NATIVE_WINDOW_SET_CROP                      =  3,   /* private */
+    NATIVE_WINDOW_SET_BUFFER_COUNT              =  4,
+    NATIVE_WINDOW_SET_BUFFERS_GEOMETRY          =  5,   /* deprecated */
+    NATIVE_WINDOW_SET_BUFFERS_TRANSFORM         =  6,
+    NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP         =  7,
+    NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS        =  8,
+    NATIVE_WINDOW_SET_BUFFERS_FORMAT            =  9,
+    NATIVE_WINDOW_SET_SCALING_MODE              = 10,   /* private */
+    NATIVE_WINDOW_LOCK                          = 11,   /* private */
+    NATIVE_WINDOW_UNLOCK_AND_POST               = 12,   /* private */
+    NATIVE_WINDOW_API_CONNECT                   = 13,   /* private */
+    NATIVE_WINDOW_API_DISCONNECT                = 14,   /* private */
+    NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS   = 15,   /* private */
+    NATIVE_WINDOW_SET_POST_TRANSFORM_CROP       = 16,   /* deprecated, unimplemented */
+    NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM  = 17,   /* private */
+    NATIVE_WINDOW_SET_SIDEBAND_STREAM           = 18,
+    NATIVE_WINDOW_SET_BUFFERS_DATASPACE         = 19,
+    NATIVE_WINDOW_SET_SURFACE_DAMAGE            = 20,   /* private */
+    NATIVE_WINDOW_SET_SHARED_BUFFER_MODE        = 21,
+    NATIVE_WINDOW_SET_AUTO_REFRESH              = 22,
+    NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION    = 23,
+    NATIVE_WINDOW_GET_NEXT_FRAME_ID             = 24,
+    NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS       = 25,
+    NATIVE_WINDOW_GET_COMPOSITOR_TIMING         = 26,
+    NATIVE_WINDOW_GET_FRAME_TIMESTAMPS          = 27,
+    NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT        = 28,
+    NATIVE_WINDOW_GET_HDR_SUPPORT               = 29,
+    NATIVE_WINDOW_SET_USAGE64                   = 30,
 // clang-format on
 };
 
@@ -549,24 +531,21 @@
  /* Backwards compatibility: use ANativeWindow (struct ANativeWindow in C).
   * android_native_window_t is deprecated.
   */
-typedef struct ANativeWindow ANativeWindow;
 typedef struct ANativeWindow android_native_window_t __deprecated;
 
 /*
- *  native_window_set_usage(..., usage)
+ *  native_window_set_usage64(..., usage)
  *  Sets the intended usage flags for the next buffers
  *  acquired with (*lockBuffer)() and on.
- *  By default (if this function is never called), a usage of
- *      GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE
- *  is assumed.
+ *
+ *  Valid usage flags are defined in android/hardware_buffer.h
+ *  All AHARDWAREBUFFER_USAGE_* flags can be specified as needed.
+ *
  *  Calling this function will usually cause following buffers to be
  *  reallocated.
  */
-
-static inline int native_window_set_usage(
-        struct ANativeWindow* window, int usage)
-{
-    return window->perform(window, NATIVE_WINDOW_SET_USAGE, usage);
+static inline int native_window_set_usage(struct ANativeWindow* window, uint64_t usage) {
+    return window->perform(window, NATIVE_WINDOW_SET_USAGE64, usage);
 }
 
 /* deprecated. Always returns 0. Don't call. */
@@ -609,45 +588,6 @@
 }
 
 /*
- * native_window_set_post_transform_crop(..., crop)
- * Sets which region of the next queued buffers needs to be considered.
- * Depending on the scaling mode, a buffer's crop region is scaled and/or
- * cropped to match the surface's size.  This function sets the crop in
- * post-transformed pixel coordinates.
- *
- * The specified crop region applies to all buffers queued after it is called.
- *
- * If 'crop' is NULL, subsequently queued buffers won't be cropped.
- *
- * An error is returned if for instance the crop region is invalid, out of the
- * buffer's bound or if the window is invalid.
- */
-static inline int native_window_set_post_transform_crop(
-        struct ANativeWindow* window,
-        android_native_rect_t const * crop)
-{
-    return window->perform(window, NATIVE_WINDOW_SET_POST_TRANSFORM_CROP, crop);
-}
-
-/*
- * native_window_set_active_rect(..., active_rect)
- *
- * This function is deprecated and will be removed soon.  For now it simply
- * sets the post-transform crop for compatibility while multi-project commits
- * get checked.
- */
-static inline int native_window_set_active_rect(
-        struct ANativeWindow* window,
-        android_native_rect_t const * active_rect) __deprecated;
-
-static inline int native_window_set_active_rect(
-        struct ANativeWindow* window,
-        android_native_rect_t const * active_rect)
-{
-    return native_window_set_post_transform_crop(window, active_rect);
-}
-
-/*
  * native_window_set_buffer_count(..., count)
  * Sets the number of buffers associated with this native window.
  */
diff --git a/libs/nativewindow/include/vndk/window.h b/libs/nativewindow/include/vndk/window.h
index 95618c4..a7b340a 100644
--- a/libs/nativewindow/include/vndk/window.h
+++ b/libs/nativewindow/include/vndk/window.h
@@ -17,88 +17,14 @@
 #ifndef ANDROID_VNDK_NATIVEWINDOW_ANATIVEWINDOW_H
 #define ANDROID_VNDK_NATIVEWINDOW_ANATIVEWINDOW_H
 
-#include <stdint.h>
-#include <stdbool.h>
-#include <sys/cdefs.h>
-#include <system/graphics-base.h>
-#include <cutils/native_handle.h>
+#include <nativebase/nativebase.h>
 
 // vndk is a superset of the NDK
 #include <android/native_window.h>
 
+
 __BEGIN_DECLS
 
-/*****************************************************************************/
-
-#ifdef __cplusplus
-#define ANDROID_NATIVE_UNSIGNED_CAST(x) static_cast<unsigned int>(x)
-#else
-#define ANDROID_NATIVE_UNSIGNED_CAST(x) ((unsigned int)(x))
-#endif
-
-#define ANDROID_NATIVE_MAKE_CONSTANT(a,b,c,d)  \
-    ((ANDROID_NATIVE_UNSIGNED_CAST(a) << 24) | \
-     (ANDROID_NATIVE_UNSIGNED_CAST(b) << 16) | \
-     (ANDROID_NATIVE_UNSIGNED_CAST(c) <<  8) | \
-     (ANDROID_NATIVE_UNSIGNED_CAST(d)))
-
-#define ANDROID_NATIVE_BUFFER_MAGIC     ANDROID_NATIVE_MAKE_CONSTANT('_','b','f','r')
-
-
-/*****************************************************************************/
-
-typedef struct android_native_base_t
-{
-    /* a magic value defined by the actual EGL native type */
-    int magic;
-
-    /* the sizeof() of the actual EGL native type */
-    int version;
-
-    void* reserved[4];
-
-    /* reference-counting interface */
-    void (*incRef)(struct android_native_base_t* base);
-    void (*decRef)(struct android_native_base_t* base);
-} android_native_base_t;
-
-typedef struct ANativeWindowBuffer
-{
-#ifdef __cplusplus
-    ANativeWindowBuffer() {
-        common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
-        common.version = sizeof(ANativeWindowBuffer);
-        memset(common.reserved, 0, sizeof(common.reserved));
-    }
-
-    // Implement the methods that sp<ANativeWindowBuffer> expects so that it
-    // can be used to automatically refcount ANativeWindowBuffer's.
-    void incStrong(const void* /*id*/) const {
-        common.incRef(const_cast<android_native_base_t*>(&common));
-    }
-    void decStrong(const void* /*id*/) const {
-        common.decRef(const_cast<android_native_base_t*>(&common));
-    }
-#endif
-
-    struct android_native_base_t common;
-
-    int width;
-    int height;
-    int stride;
-    int format;
-    int usage;
-    uintptr_t layerCount;
-
-    void* reserved[1];
-
-    const native_handle_t* handle;
-
-    void* reserved_proc[8];
-} ANativeWindowBuffer_t;
-
-typedef struct ANativeWindowBuffer ANativeWindowBuffer;
-
 /*
  * Convert this ANativeWindowBuffer into a AHardwareBuffer
  */
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index b1d1a72..58045be 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -4,22 +4,40 @@
     AHardwareBuffer_allocate;
     AHardwareBuffer_describe;
     AHardwareBuffer_fromHardwareBuffer;
+    AHardwareBuffer_getNativeHandle; # vndk
     AHardwareBuffer_lock;
     AHardwareBuffer_recvHandleFromUnixSocket;
     AHardwareBuffer_release;
     AHardwareBuffer_sendHandleToUnixSocket;
     AHardwareBuffer_toHardwareBuffer;
     AHardwareBuffer_unlock;
+    ANativeWindowBuffer_getHardwareBuffer; # vndk
+    ANativeWindow_OemStorageGet; # vndk
+    ANativeWindow_OemStorageSet; # vndk
     ANativeWindow_acquire;
+    ANativeWindow_cancelBuffer; # vndk
+    ANativeWindow_dequeueBuffer; # vndk
     ANativeWindow_fromSurface;
     ANativeWindow_fromSurfaceTexture;
     ANativeWindow_getFormat;
     ANativeWindow_getHeight;
     ANativeWindow_getWidth;
     ANativeWindow_lock;
+    ANativeWindow_query; # vndk
+    ANativeWindow_queryf; # vndk
+    ANativeWindow_queueBuffer; # vndk
     ANativeWindow_release;
+    ANativeWindow_setAutoRefresh; # vndk
+    ANativeWindow_setBufferCount; # vndk
+    ANativeWindow_setBufferDataSpace; # vndk
+    ANativeWindow_setBuffersDimensions; # vndk
+    ANativeWindow_setBuffersFormat; # vndk
     ANativeWindow_setBuffersGeometry;
+    ANativeWindow_setBuffersTimestamp; # vndk
     ANativeWindow_setBuffersTransform;
+    ANativeWindow_setSharedBufferMode; # vndk
+    ANativeWindow_setSwapInterval; # vndk
+    ANativeWindow_setUsage; # vndk
     ANativeWindow_unlockAndPost;
   local:
     *;
diff --git a/libs/sensor/ISensorEventConnection.cpp b/libs/sensor/ISensorEventConnection.cpp
index 8a3a623..1cd8e01 100644
--- a/libs/sensor/ISensorEventConnection.cpp
+++ b/libs/sensor/ISensorEventConnection.cpp
@@ -36,7 +36,8 @@
     ENABLE_DISABLE,
     SET_EVENT_RATE,
     FLUSH_SENSOR,
-    CONFIGURE_CHANNEL
+    CONFIGURE_CHANNEL,
+    DESTROY,
 };
 
 class BpSensorEventConnection : public BpInterface<ISensorEventConnection>
@@ -96,11 +97,22 @@
         remote()->transact(CONFIGURE_CHANNEL, data, &reply);
         return reply.readInt32();
     }
+
+    virtual void onLastStrongRef(const void* id) {
+        destroy();
+        BpInterface<ISensorEventConnection>::onLastStrongRef(id);
+    }
+
+protected:
+    virtual void destroy() {
+        Parcel data, reply;
+        remote()->transact(DESTROY, data, &reply);
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
 // translation unit (see clang warning -Wweak-vtables)
-BpSensorEventConnection::~BpSensorEventConnection() {}
+BpSensorEventConnection::~BpSensorEventConnection() { }
 
 IMPLEMENT_META_INTERFACE(SensorEventConnection, "android.gui.SensorEventConnection");
 
@@ -150,6 +162,10 @@
             reply->writeInt32(result);
             return NO_ERROR;
         }
+        case DESTROY: {
+            destroy();
+            return NO_ERROR;
+        }
 
     }
     return BBinder::onTransact(code, data, reply, flags);
diff --git a/libs/sensor/ISensorServer.cpp b/libs/sensor/ISensorServer.cpp
index 74186df..f20668d 100644
--- a/libs/sensor/ISensorServer.cpp
+++ b/libs/sensor/ISensorServer.cpp
@@ -119,10 +119,12 @@
         return interface_cast<ISensorEventConnection>(reply.readStrongBinder());
     }
 
-    virtual int setOperationParameter(
-            int32_t type, const Vector<float> &floats, const Vector<int32_t> &ints) {
+    virtual int setOperationParameter(int32_t handle, int32_t type,
+                                      const Vector<float> &floats,
+                                      const Vector<int32_t> &ints) {
         Parcel data, reply;
         data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor());
+        data.writeInt32(handle);
         data.writeInt32(type);
         data.writeUint32(static_cast<uint32_t>(floats.size()));
         for (auto i : floats) {
@@ -203,10 +205,12 @@
         }
         case SET_OPERATION_PARAMETER: {
             CHECK_INTERFACE(ISensorServer, data, reply);
+            int32_t handle;
             int32_t type;
             Vector<float> floats;
             Vector<int32_t> ints;
 
+            handle = data.readInt32();
             type = data.readInt32();
             floats.resize(data.readUint32());
             for (auto &i : floats) {
@@ -217,7 +221,7 @@
                 i = data.readInt32();
             }
 
-            int32_t ret = setOperationParameter(type, floats, ints);
+            int32_t ret = setOperationParameter(handle, type, floats, ints);
             reply->writeInt32(ret);
             return NO_ERROR;
         }
diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp
index c2d477e..a0e368c 100644
--- a/libs/sensor/Sensor.cpp
+++ b/libs/sensor/Sensor.cpp
@@ -30,7 +30,7 @@
         mName(name), mHandle(0), mType(0),
         mMinValue(0), mMaxValue(0), mResolution(0),
         mPower(0), mMinDelay(0), mVersion(0), mFifoReservedEventCount(0),
-        mFifoMaxEventCount(0), mRequiredAppOp(0),
+        mFifoMaxEventCount(0), mRequiredAppOp(-1),
         mMaxDelay(0), mFlags(0) {
 }
 
@@ -38,7 +38,8 @@
         Sensor(*hwSensor, uuid_t(), halVersion) {
 }
 
-Sensor::Sensor(struct sensor_t const& hwSensor, const uuid_t& uuid, int halVersion) {
+Sensor::Sensor(struct sensor_t const& hwSensor, const uuid_t& uuid, int halVersion) :
+        Sensor("") {
     mName = hwSensor.name;
     mVendor = hwSensor.vendor;
     mVersion = hwSensor.version;
@@ -412,6 +413,10 @@
     return (mFlags & SENSOR_FLAG_DYNAMIC_SENSOR) != 0;
 }
 
+bool Sensor::isDataInjectionSupported() const {
+    return (mFlags & SENSOR_FLAG_DATA_INJECTION) != 0;
+}
+
 bool Sensor::hasAdditionalInfo() const {
     return (mFlags & SENSOR_FLAG_ADDITIONAL_INFO) != 0;
 }
diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp
index 3fbc5eb..6fe72a1 100644
--- a/libs/sensor/SensorManager.cpp
+++ b/libs/sensor/SensorManager.cpp
@@ -305,12 +305,13 @@
 }
 
 int SensorManager::setOperationParameter(
-        int type, const Vector<float> &floats, const Vector<int32_t> &ints) {
+        int handle, int type,
+        const Vector<float> &floats, const Vector<int32_t> &ints) {
     Mutex::Autolock _l(mLock);
     if (assertStateLocked() != NO_ERROR) {
         return NO_INIT;
     }
-    return mSensorServer->setOperationParameter(type, floats, ints);
+    return mSensorServer->setOperationParameter(handle, type, floats, ints);
 }
 
 // ----------------------------------------------------------------------------
diff --git a/libs/sensor/include/sensor/ISensorEventConnection.h b/libs/sensor/include/sensor/ISensorEventConnection.h
index 07cc7e8..b62e18c 100644
--- a/libs/sensor/include/sensor/ISensorEventConnection.h
+++ b/libs/sensor/include/sensor/ISensorEventConnection.h
@@ -42,6 +42,8 @@
     virtual status_t setEventRate(int handle, nsecs_t ns) = 0;
     virtual status_t flush() = 0;
     virtual int32_t configureChannel(int32_t handle, int32_t rateLevel) = 0;
+protected:
+    virtual void destroy() = 0; // synchronously release resource hold by remote object
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libs/sensor/include/sensor/ISensorServer.h b/libs/sensor/include/sensor/ISensorServer.h
index 8d50062..edf3e0f 100644
--- a/libs/sensor/include/sensor/ISensorServer.h
+++ b/libs/sensor/include/sensor/ISensorServer.h
@@ -52,7 +52,7 @@
             uint32_t size, int32_t type, int32_t format, const native_handle_t *resource) = 0;
 
     virtual int setOperationParameter(
-            int32_t type, const Vector<float> &floats, const Vector<int32_t> &ints) = 0;
+            int32_t handle, int32_t type, const Vector<float> &floats, const Vector<int32_t> &ints) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libs/sensor/include/sensor/Sensor.h b/libs/sensor/include/sensor/Sensor.h
index 043e635..6926f7f 100644
--- a/libs/sensor/include/sensor/Sensor.h
+++ b/libs/sensor/include/sensor/Sensor.h
@@ -90,6 +90,7 @@
     uint32_t getFlags() const;
     bool isWakeUpSensor() const;
     bool isDynamicSensor() const;
+    bool isDataInjectionSupported() const;
     bool hasAdditionalInfo() const;
     int32_t getHighestDirectReportRateLevel() const;
     bool isDirectChannelTypeSupported(int32_t sharedMemType) const;
diff --git a/libs/sensor/include/sensor/SensorManager.h b/libs/sensor/include/sensor/SensorManager.h
index 5fc85d3..23f7a91 100644
--- a/libs/sensor/include/sensor/SensorManager.h
+++ b/libs/sensor/include/sensor/SensorManager.h
@@ -64,7 +64,7 @@
     int createDirectChannel(size_t size, int channelType, const native_handle_t *channelData);
     void destroyDirectChannel(int channelNativeHandle);
     int configureDirectChannel(int channelNativeHandle, int sensorHandle, int rateLevel);
-    int setOperationParameter(int type, const Vector<float> &floats, const Vector<int32_t> &ints);
+    int setOperationParameter(int handle, int type, const Vector<float> &floats, const Vector<int32_t> &ints);
 
 private:
     // DeathRecipient interface
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 5edd664..6630d90 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -54,7 +54,6 @@
         "GraphicBuffer.cpp",
         "GraphicBufferAllocator.cpp",
         "GraphicBufferMapper.cpp",
-        "GraphicsEnv.cpp",
         "HdrCapabilities.cpp",
         "PixelFormat.cpp",
         "Rect.cpp",
@@ -70,9 +69,8 @@
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.configstore@1.0",
-	"android.hardware.configstore-utils",
+        "android.hardware.configstore-utils",
         "libbase",
-        "libnativeloader",
         "libcutils",
         "libhardware",
         "libhidlbase",
@@ -89,10 +87,22 @@
         "libmath",
     ],
 
+    header_libs: [
+        "libnativebase_headers",
+        "libhardware_headers",
+    ],
+
+    export_include_dirs: ["include"],
+
     export_static_lib_headers: [
         "libarect",
         "libmath",
     ],
+
+    export_header_lib_headers: [
+        "libnativebase_headers",
+        "libhardware_headers",
+    ],
 }
 
 subdirs = ["tests"]
diff --git a/libs/ui/DebugUtils.cpp b/libs/ui/DebugUtils.cpp
index 882bd7c..d5676cc 100644
--- a/libs/ui/DebugUtils.cpp
+++ b/libs/ui/DebugUtils.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <ui/DebugUtils.h>
+#include <ui/PixelFormat.h>
 
 #include <android-base/stringprintf.h>
 #include <string>
@@ -58,24 +59,20 @@
         case 0:
             switch (dataspace & 0xffff) {
                 case HAL_DATASPACE_JFIF:
-                    return std::string("(deprecated) JFIF (BT601_625, SMPTE_170M Full range)");
+                    return std::string("(deprecated) JFIF (BT601_625)");
 
                 case HAL_DATASPACE_BT601_625:
-                    return std::string("(deprecated) BT601_625 (BT601_625, SMPTE_170M Limited "
-                                       "range)");
+                    return std::string("(deprecated) BT601_625");
 
                 case HAL_DATASPACE_BT601_525:
-                    return std::string("(deprecated) BT601_525 (BT601_525, SMPTE_170M Limited "
-                                       "range)");
+                    return std::string("(deprecated) BT601_525");
 
                 case HAL_DATASPACE_SRGB_LINEAR:
-                    return std::string("(deprecated) SRGB Linear Full range");
-
                 case HAL_DATASPACE_SRGB:
                     return std::string("(deprecated) sRGB");
 
                 case HAL_DATASPACE_V0_BT709:
-                    return std::string("(deprecated) BT709 (BT709, SMPTE_170M Limited range)");
+                    return std::string("(deprecated) BT709");
 
                 case HAL_DATASPACE_ARBITRARY:
                     return std::string("ARBITRARY");
@@ -92,6 +89,29 @@
 }
 
 std::string decodeTransfer(android_dataspace dataspace) {
+    const uint32_t dataspaceSelect = (dataspace & HAL_DATASPACE_STANDARD_MASK);
+    if (dataspaceSelect == 0) {
+        switch (dataspace & 0xffff) {
+            case HAL_DATASPACE_JFIF:
+            case HAL_DATASPACE_BT601_625:
+            case HAL_DATASPACE_BT601_525:
+            case HAL_DATASPACE_V0_BT709:
+                return std::string("SMPTE_170M");
+
+            case HAL_DATASPACE_SRGB_LINEAR:
+            case HAL_DATASPACE_ARBITRARY:
+                return std::string("Linear");
+
+            case HAL_DATASPACE_SRGB:
+                return std::string("sRGB");
+
+            case HAL_DATASPACE_UNKNOWN:
+            // Fallthrough
+            default:
+                return std::string("");
+        }
+    }
+
     const uint32_t dataspaceTransfer = (dataspace & HAL_DATASPACE_TRANSFER_MASK);
     switch (dataspaceTransfer) {
         case HAL_DATASPACE_TRANSFER_UNSPECIFIED:
@@ -126,6 +146,27 @@
 }
 
 std::string decodeRange(android_dataspace dataspace) {
+    const uint32_t dataspaceSelect = (dataspace & HAL_DATASPACE_STANDARD_MASK);
+    if (dataspaceSelect == 0) {
+        switch (dataspace & 0xffff) {
+            case HAL_DATASPACE_JFIF:
+            case HAL_DATASPACE_SRGB_LINEAR:
+            case HAL_DATASPACE_SRGB:
+                return std::string("Full range");
+
+            case HAL_DATASPACE_BT601_625:
+            case HAL_DATASPACE_BT601_525:
+            case HAL_DATASPACE_V0_BT709:
+                return std::string("Limited range)");
+
+            case HAL_DATASPACE_ARBITRARY:
+            case HAL_DATASPACE_UNKNOWN:
+            // Fallthrough
+            default:
+                return std::string("unspecified range");
+        }
+    }
+
     const uint32_t dataspaceRange = (dataspace & HAL_DATASPACE_RANGE_MASK);
     switch (dataspaceRange) {
         case HAL_DATASPACE_RANGE_UNSPECIFIED:
@@ -145,6 +186,9 @@
 }
 
 std::string dataspaceDetails(android_dataspace dataspace) {
+    if (dataspace == 0) {
+        return "Default (0)";
+    }
     return android::base::StringPrintf("%s %s %s", decodeStandard(dataspace).c_str(),
                                        decodeTransfer(dataspace).c_str(),
                                        decodeRange(dataspace).c_str());
@@ -185,3 +229,36 @@
 
     return android::base::StringPrintf("Unknown color mode %d", colorMode);
 }
+
+// Converts a PixelFormat to a human-readable string.  Max 11 chars.
+// (Could use a table of prefab String8 objects.)
+std::string decodePixelFormat(android::PixelFormat format) {
+    switch (format) {
+        case android::PIXEL_FORMAT_UNKNOWN:
+            return std::string("Unknown/None");
+        case android::PIXEL_FORMAT_CUSTOM:
+            return std::string("Custom");
+        case android::PIXEL_FORMAT_TRANSLUCENT:
+            return std::string("Translucent");
+        case android::PIXEL_FORMAT_TRANSPARENT:
+            return std::string("Transparent");
+        case android::PIXEL_FORMAT_OPAQUE:
+            return std::string("Opaque");
+        case android::PIXEL_FORMAT_RGBA_8888:
+            return std::string("RGBA_8888");
+        case android::PIXEL_FORMAT_RGBX_8888:
+            return std::string("RGBx_8888");
+        case android::PIXEL_FORMAT_RGBA_FP16:
+            return std::string("RGBA_FP16");
+        case android::PIXEL_FORMAT_RGBA_1010102:
+            return std::string("RGBA_1010102");
+        case android::PIXEL_FORMAT_RGB_888:
+            return std::string("RGB_888");
+        case android::PIXEL_FORMAT_RGB_565:
+            return std::string("RGB_565");
+        case android::PIXEL_FORMAT_BGRA_8888:
+            return std::string("BGRA_8888");
+        default:
+            return android::base::StringPrintf("Unknown %#08x", format);
+    }
+}
diff --git a/libs/ui/Gralloc2.cpp b/libs/ui/Gralloc2.cpp
index 87dbaf4..0eb08e5 100644
--- a/libs/ui/Gralloc2.cpp
+++ b/libs/ui/Gralloc2.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "Gralloc2"
 
+#include <hidl/ServiceManagement.h>
 #include <hwbinder/IPCThreadState.h>
 #include <ui/Gralloc2.h>
 
@@ -31,6 +32,10 @@
 
 static constexpr Error kTransactionError = Error::NO_RESOURCES;
 
+void Mapper::preload() {
+    android::hardware::preloadPassthroughService<hardware::graphics::mapper::V2_0::IMapper>();
+}
+
 Mapper::Mapper()
 {
     mMapper = IMapper::getService();
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index ee85c9b..c880500 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -51,6 +51,7 @@
     height =
     stride =
     format =
+    usage_deprecated = 0;
     usage  = 0;
     layerCount = 0;
     handle = NULL;
@@ -59,14 +60,12 @@
 // deprecated
 GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
         PixelFormat inFormat, uint32_t inUsage, std::string requestorName)
-    : GraphicBuffer(inWidth, inHeight, inFormat, 1, static_cast<uint64_t>(inUsage),
-            requestorName)
+    : GraphicBuffer(inWidth, inHeight, inFormat, 1, static_cast<uint64_t>(inUsage), requestorName)
 {
 }
 
 GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
-        PixelFormat inFormat, uint32_t inLayerCount, uint64_t usage,
-        std::string requestorName)
+        PixelFormat inFormat, uint32_t inLayerCount, uint64_t usage, std::string requestorName)
     : GraphicBuffer()
 {
     mInitCheck = initWithSize(inWidth, inHeight, inFormat, inLayerCount,
@@ -139,7 +138,7 @@
             static_cast<int>(inHeight) == height &&
             inFormat == format &&
             inLayerCount == layerCount &&
-            static_cast<int>(inUsage) == usage)
+            inUsage == usage)
         return NO_ERROR;
 
     if (handle) {
@@ -147,8 +146,7 @@
         allocator.free(handle);
         handle = 0;
     }
-    return initWithSize(inWidth, inHeight, inFormat, inLayerCount,
-            inUsage, "[Reallocation]");
+    return initWithSize(inWidth, inHeight, inFormat, inLayerCount, inUsage, "[Reallocation]");
 }
 
 bool GraphicBuffer::needsReallocation(uint32_t inWidth, uint32_t inHeight,
@@ -158,7 +156,7 @@
     if (static_cast<int>(inHeight) != height) return true;
     if (inFormat != format) return true;
     if (inLayerCount != layerCount) return true;
-    if ((static_cast<uint32_t>(usage) & inUsage) != inUsage) return true;
+    if ((usage & inUsage) != inUsage) return true;
     return false;
 }
 
@@ -176,7 +174,8 @@
         height = static_cast<int>(inHeight);
         format = inFormat;
         layerCount = inLayerCount;
-        usage = static_cast<int>(inUsage);
+        usage = inUsage;
+        usage_deprecated = int(usage);
         stride = static_cast<int>(outStride);
     }
     return err;
@@ -191,7 +190,8 @@
     ANativeWindowBuffer::height = static_cast<int>(height);
     ANativeWindowBuffer::stride = static_cast<int>(stride);
     ANativeWindowBuffer::format = format;
-    ANativeWindowBuffer::usage  = static_cast<int>(usage);
+    ANativeWindowBuffer::usage  = usage;
+    ANativeWindowBuffer::usage_deprecated = int(usage);
 
     ANativeWindowBuffer::layerCount = layerCount;
 
@@ -312,8 +312,7 @@
                 width, height);
         return BAD_VALUE;
     }
-    status_t res = getBufferMapper().lockAsyncYCbCr(handle, inUsage, rect,
-            ycbcr, fenceFd);
+    status_t res = getBufferMapper().lockAsyncYCbCr(handle, inUsage, rect, ycbcr, fenceFd);
     return res;
 }
 
@@ -324,7 +323,7 @@
 }
 
 size_t GraphicBuffer::getFlattenedSize() const {
-    return static_cast<size_t>(12 + (handle ? handle->numInts : 0)) * sizeof(int);
+    return static_cast<size_t>(13 + (handle ? handle->numInts : 0)) * sizeof(int);
 }
 
 size_t GraphicBuffer::getFdCount() const {
@@ -339,25 +338,25 @@
     if (count < fdCountNeeded) return NO_MEMORY;
 
     int32_t* buf = static_cast<int32_t*>(buffer);
-    buf[0] = 'GBFR';
+    buf[0] = 'GB01';
     buf[1] = width;
     buf[2] = height;
     buf[3] = stride;
     buf[4] = format;
     buf[5] = static_cast<int32_t>(layerCount);
-    buf[6] = usage;
+    buf[6] = int(usage); // low 32-bits
     buf[7] = static_cast<int32_t>(mId >> 32);
     buf[8] = static_cast<int32_t>(mId & 0xFFFFFFFFull);
     buf[9] = static_cast<int32_t>(mGenerationNumber);
     buf[10] = 0;
     buf[11] = 0;
+    buf[12] = int(usage >> 32); // high 32-bits
 
     if (handle) {
         buf[10] = handle->numFds;
         buf[11] = handle->numInts;
-        memcpy(fds, handle->data,
-                static_cast<size_t>(handle->numFds) * sizeof(int));
-        memcpy(&buf[12], handle->data + handle->numFds,
+        memcpy(fds, handle->data, static_cast<size_t>(handle->numFds) * sizeof(int));
+        memcpy(buf + 13, handle->data + handle->numFds,
                 static_cast<size_t>(handle->numInts) * sizeof(int));
     }
 
@@ -373,10 +372,21 @@
 
 status_t GraphicBuffer::unflatten(
         void const*& buffer, size_t& size, int const*& fds, size_t& count) {
-    if (size < 12 * sizeof(int)) return NO_MEMORY;
 
     int const* buf = static_cast<int const*>(buffer);
-    if (buf[0] != 'GBFR') return BAD_TYPE;
+
+    // NOTE: it turns out that some media code generates a flattened GraphicBuffer manually!!!!!
+    // see H2BGraphicBufferProducer.cpp
+    uint32_t flattenWordCount = 0;
+    if (buf[0] == 'GB01') {
+        // new version with 64-bits usage bits
+        flattenWordCount = 13;
+    } else if (buf[0] == 'GBFR') {
+        // old version, when usage bits were 32-bits
+        flattenWordCount = 12;
+    } else {
+        return BAD_TYPE;
+    }
 
     const size_t numFds  = static_cast<size_t>(buf[10]);
     const size_t numInts = static_cast<size_t>(buf[11]);
@@ -386,15 +396,16 @@
     // chosen to be high enough to not cause issues and low enough to prevent
     // overflow problems.
     const size_t maxNumber = 4096;
-    if (numFds >= maxNumber || numInts >= (maxNumber - 12)) {
-        width = height = stride = format = layerCount = usage = 0;
+    if (numFds >= maxNumber || numInts >= (maxNumber - flattenWordCount)) {
+        width = height = stride = format = usage_deprecated = 0;
+        layerCount = 0;
+        usage = 0;
         handle = NULL;
-        ALOGE("unflatten: numFds or numInts is too large: %zd, %zd",
-                numFds, numInts);
+        ALOGE("unflatten: numFds or numInts is too large: %zd, %zd", numFds, numInts);
         return BAD_VALUE;
     }
 
-    const size_t sizeNeeded = (12 + numInts) * sizeof(int);
+    const size_t sizeNeeded = (flattenWordCount + numInts) * sizeof(int);
     if (size < sizeNeeded) return NO_MEMORY;
 
     size_t fdCountNeeded = numFds;
@@ -411,20 +422,29 @@
         stride = buf[3];
         format = buf[4];
         layerCount = static_cast<uintptr_t>(buf[5]);
-        usage  = buf[6];
+        usage_deprecated = buf[6];
+        if (flattenWordCount == 13) {
+            usage = (uint64_t(buf[12]) << 32) | uint32_t(buf[6]);
+        } else {
+            usage = uint64_t(usage_deprecated);
+        }
         native_handle* h = native_handle_create(
                 static_cast<int>(numFds), static_cast<int>(numInts));
         if (!h) {
-            width = height = stride = format = layerCount = usage = 0;
+            width = height = stride = format = usage_deprecated = 0;
+            layerCount = 0;
+            usage = 0;
             handle = NULL;
             ALOGE("unflatten: native_handle_create failed");
             return NO_MEMORY;
         }
         memcpy(h->data, fds, numFds * sizeof(int));
-        memcpy(h->data + numFds, &buf[12], numInts * sizeof(int));
+        memcpy(h->data + numFds, buf + flattenWordCount, numInts * sizeof(int));
         handle = h;
     } else {
-        width = height = stride = format = layerCount = usage = 0;
+        width = height = stride = format = usage_deprecated = 0;
+        layerCount = 0;
+        usage = 0;
         handle = NULL;
     }
 
@@ -439,10 +459,11 @@
         buffer_handle_t importedHandle;
         status_t err = mBufferMapper.importBuffer(handle, &importedHandle);
         if (err != NO_ERROR) {
-            width = height = stride = format = layerCount = usage = 0;
+            width = height = stride = format = usage_deprecated = 0;
+            layerCount = 0;
+            usage = 0;
             handle = NULL;
-            ALOGE("unflatten: registerBuffer failed: %s (%d)",
-                    strerror(-err), err);
+            ALOGE("unflatten: registerBuffer failed: %s (%d)", strerror(-err), err);
             return err;
         }
 
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index b9fa640..d52c508 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -42,6 +42,10 @@
 
 ANDROID_SINGLETON_STATIC_INSTANCE( GraphicBufferMapper )
 
+void GraphicBufferMapper::preloadHal() {
+    Gralloc2::Mapper::preload();
+}
+
 GraphicBufferMapper::GraphicBufferMapper()
   : mMapper(std::make_unique<const Gralloc2::Mapper>())
 {
diff --git a/include/ui/ANativeObjectBase.h b/libs/ui/include/ui/ANativeObjectBase.h
similarity index 71%
rename from include/ui/ANativeObjectBase.h
rename to libs/ui/include/ui/ANativeObjectBase.h
index 640e34b..e9d5d8d 100644
--- a/include/ui/ANativeObjectBase.h
+++ b/libs/ui/include/ui/ANativeObjectBase.h
@@ -19,26 +19,8 @@
 
 #include <sys/types.h>
 
-#include <system/window.h>
+#include <nativebase/nativebase.h>
 
-// ---------------------------------------------------------------------------
-
-/* FIXME: this is legacy for pixmaps */
-typedef struct egl_native_pixmap_t
-{
-    int32_t     version;    /* must be 32 */
-    int32_t     width;
-    int32_t     height;
-    int32_t     stride;
-    uint8_t*    data;
-    uint8_t     format;
-    uint8_t     rfu[3];
-    union {
-        uint32_t    compressedFormat;
-        int32_t     vstride;
-    };
-    int32_t     reserved;
-} egl_native_pixmap_t;
 
 /*****************************************************************************/
 
@@ -52,7 +34,8 @@
  * This helper class turns a ANativeXXX object type into a C++
  * reference-counted object; with proper type conversions.
  */
-template <typename NATIVE_TYPE, typename TYPE, typename REF>
+template <typename NATIVE_TYPE, typename TYPE, typename REF,
+        typename NATIVE_BASE = android_native_base_t>
 class ANativeObjectBase : public NATIVE_TYPE, public REF
 {
 public:
@@ -65,7 +48,7 @@
     }
 
 protected:
-    typedef ANativeObjectBase<NATIVE_TYPE, TYPE, REF> BASE;
+    typedef ANativeObjectBase<NATIVE_TYPE, TYPE, REF, NATIVE_BASE> BASE;
     ANativeObjectBase() : NATIVE_TYPE(), REF() {
         NATIVE_TYPE::common.incRef = incRef;
         NATIVE_TYPE::common.decRef = decRef;
@@ -76,17 +59,17 @@
     static inline TYPE const* getSelf(NATIVE_TYPE const* self) {
         return static_cast<TYPE const *>(self);
     }
-    static inline TYPE* getSelf(android_native_base_t* base) {
+    static inline TYPE* getSelf(NATIVE_BASE* base) {
         return getSelf(reinterpret_cast<NATIVE_TYPE*>(base));
     }
-    static inline TYPE const * getSelf(android_native_base_t const* base) {
+    static inline TYPE const * getSelf(NATIVE_BASE const* base) {
         return getSelf(reinterpret_cast<NATIVE_TYPE const*>(base));
     }
-    static void incRef(android_native_base_t* base) {
+    static void incRef(NATIVE_BASE* base) {
         ANativeObjectBase* self = getSelf(base);
         self->incStrong(self);
     }
-    static void decRef(android_native_base_t* base) {
+    static void decRef(NATIVE_BASE* base) {
         ANativeObjectBase* self = getSelf(base);
         self->decStrong(self);
     }
diff --git a/include/ui/BufferQueueDefs.h b/libs/ui/include/ui/BufferQueueDefs.h
similarity index 100%
rename from include/ui/BufferQueueDefs.h
rename to libs/ui/include/ui/BufferQueueDefs.h
diff --git a/include/ui/ColorSpace.h b/libs/ui/include/ui/ColorSpace.h
similarity index 100%
rename from include/ui/ColorSpace.h
rename to libs/ui/include/ui/ColorSpace.h
diff --git a/include/ui/DebugUtils.h b/libs/ui/include/ui/DebugUtils.h
similarity index 91%
rename from include/ui/DebugUtils.h
rename to libs/ui/include/ui/DebugUtils.h
index 8483808..30f4a59 100644
--- a/include/ui/DebugUtils.h
+++ b/libs/ui/include/ui/DebugUtils.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <system/graphics.h>
+#include <ui/PixelFormat.h>
 
 #include <string>
 
@@ -25,3 +26,4 @@
 std::string decodeRange(android_dataspace dataspace);
 std::string dataspaceDetails(android_dataspace dataspace);
 std::string decodeColorMode(android_color_mode colormode);
+std::string decodePixelFormat(android::PixelFormat format);
diff --git a/include/ui/DisplayInfo.h b/libs/ui/include/ui/DisplayInfo.h
similarity index 100%
rename from include/ui/DisplayInfo.h
rename to libs/ui/include/ui/DisplayInfo.h
diff --git a/include/ui/DisplayStatInfo.h b/libs/ui/include/ui/DisplayStatInfo.h
similarity index 100%
rename from include/ui/DisplayStatInfo.h
rename to libs/ui/include/ui/DisplayStatInfo.h
diff --git a/include/ui/Fence.h b/libs/ui/include/ui/Fence.h
similarity index 100%
rename from include/ui/Fence.h
rename to libs/ui/include/ui/Fence.h
diff --git a/include/ui/FenceTime.h b/libs/ui/include/ui/FenceTime.h
similarity index 100%
rename from include/ui/FenceTime.h
rename to libs/ui/include/ui/FenceTime.h
diff --git a/include/ui/FloatRect.h b/libs/ui/include/ui/FloatRect.h
similarity index 100%
rename from include/ui/FloatRect.h
rename to libs/ui/include/ui/FloatRect.h
diff --git a/include/ui/FrameStats.h b/libs/ui/include/ui/FrameStats.h
similarity index 100%
rename from include/ui/FrameStats.h
rename to libs/ui/include/ui/FrameStats.h
diff --git a/include/ui/Gralloc2.h b/libs/ui/include/ui/Gralloc2.h
similarity index 98%
rename from include/ui/Gralloc2.h
rename to libs/ui/include/ui/Gralloc2.h
index f826b92..8aee160 100644
--- a/include/ui/Gralloc2.h
+++ b/libs/ui/include/ui/Gralloc2.h
@@ -21,7 +21,6 @@
 
 #include <android/hardware/graphics/allocator/2.0/IAllocator.h>
 #include <android/hardware/graphics/mapper/2.0/IMapper.h>
-#include <system/window.h>
 #include <utils/StrongPointer.h>
 
 namespace android {
@@ -39,6 +38,8 @@
 // A wrapper to IMapper
 class Mapper {
 public:
+    static void preload();
+
     Mapper();
 
     Error createDescriptor(
diff --git a/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
similarity index 97%
rename from include/ui/GraphicBuffer.h
rename to libs/ui/include/ui/GraphicBuffer.h
index 4b82cff..95c2d22 100644
--- a/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -28,9 +28,9 @@
 #include <utils/Flattenable.h>
 #include <utils/RefBase.h>
 
-#include <hardware/gralloc.h>
+#include <nativebase/nativebase.h>
 
-struct ANativeWindowBuffer;
+#include <hardware/gralloc.h>
 
 namespace android {
 
@@ -41,7 +41,7 @@
 // ===========================================================================
 
 class GraphicBuffer
-    : public ANativeObjectBase< ANativeWindowBuffer, GraphicBuffer, RefBase >,
+    : public ANativeObjectBase<ANativeWindowBuffer, GraphicBuffer, RefBase>,
       public Flattenable<GraphicBuffer>
 {
     friend class Flattenable<GraphicBuffer>;
@@ -141,7 +141,7 @@
     uint32_t getWidth() const           { return static_cast<uint32_t>(width); }
     uint32_t getHeight() const          { return static_cast<uint32_t>(height); }
     uint32_t getStride() const          { return static_cast<uint32_t>(stride); }
-    uint32_t getUsage() const           { return static_cast<uint32_t>(usage); }
+    uint64_t getUsage() const           { return usage; }
     PixelFormat getPixelFormat() const  { return format; }
     uint32_t getLayerCount() const      { return static_cast<uint32_t>(layerCount); }
     Rect getBounds() const              { return Rect(width, height); }
diff --git a/include/ui/GraphicBufferAllocator.h b/libs/ui/include/ui/GraphicBufferAllocator.h
similarity index 98%
rename from include/ui/GraphicBufferAllocator.h
rename to libs/ui/include/ui/GraphicBufferAllocator.h
index fe99de1..14a865e 100644
--- a/include/ui/GraphicBufferAllocator.h
+++ b/libs/ui/include/ui/GraphicBufferAllocator.h
@@ -25,8 +25,6 @@
 
 #include <cutils/native_handle.h>
 
-#include <system/window.h>
-
 #include <ui/PixelFormat.h>
 
 #include <utils/Errors.h>
diff --git a/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h
similarity index 98%
rename from include/ui/GraphicBufferMapper.h
rename to libs/ui/include/ui/GraphicBufferMapper.h
index e0702e9..06961b1 100644
--- a/include/ui/GraphicBufferMapper.h
+++ b/libs/ui/include/ui/GraphicBufferMapper.h
@@ -43,6 +43,7 @@
 class GraphicBufferMapper : public Singleton<GraphicBufferMapper>
 {
 public:
+    static void preloadHal();
     static inline GraphicBufferMapper& get() { return getInstance(); }
 
     // The imported outHandle must be freed with freeBuffer when no longer
diff --git a/include/ui/HdrCapabilities.h b/libs/ui/include/ui/HdrCapabilities.h
similarity index 100%
rename from include/ui/HdrCapabilities.h
rename to libs/ui/include/ui/HdrCapabilities.h
diff --git a/include/ui/PixelFormat.h b/libs/ui/include/ui/PixelFormat.h
similarity index 100%
rename from include/ui/PixelFormat.h
rename to libs/ui/include/ui/PixelFormat.h
diff --git a/include/ui/Point.h b/libs/ui/include/ui/Point.h
similarity index 100%
rename from include/ui/Point.h
rename to libs/ui/include/ui/Point.h
diff --git a/include/ui/Rect.h b/libs/ui/include/ui/Rect.h
similarity index 100%
rename from include/ui/Rect.h
rename to libs/ui/include/ui/Rect.h
diff --git a/include/ui/Region.h b/libs/ui/include/ui/Region.h
similarity index 100%
rename from include/ui/Region.h
rename to libs/ui/include/ui/Region.h
diff --git a/include/ui/UiConfig.h b/libs/ui/include/ui/UiConfig.h
similarity index 100%
rename from include/ui/UiConfig.h
rename to libs/ui/include/ui/UiConfig.h
diff --git a/libs/vr/libbroadcastring/include/libbroadcastring/broadcast_ring.h b/libs/vr/libbroadcastring/include/libbroadcastring/broadcast_ring.h
index 69cb648..f2e5034 100644
--- a/libs/vr/libbroadcastring/include/libbroadcastring/broadcast_ring.h
+++ b/libs/vr/libbroadcastring/include/libbroadcastring/broadcast_ring.h
@@ -174,8 +174,6 @@
   //
   // There must be at least |MemorySize(record_count)| bytes of space already
   // allocated at |mmap|. The ring does not take ownership.
-  //
-  // Use this function for dynamically sized rings.
   static BroadcastRing Create(void* mmap, size_t mmap_size,
                               uint32_t record_count) {
     BroadcastRing ring(mmap);
@@ -188,12 +186,11 @@
   //
   // There must be at least |MemorySize()| bytes of space already allocated at
   // |mmap|. The ring does not take ownership.
-  //
-  // Use this function for statically sized rings.
   static BroadcastRing Create(void* mmap, size_t mmap_size) {
-    static_assert(Traits::kUseStaticRecordCount,
-                  "Wrong Create() function called for dynamic record count");
-    return Create(mmap, mmap_size, Traits::kStaticRecordCount);
+    return Create(mmap, mmap_size,
+                  Traits::kUseStaticRecordCount
+                      ? Traits::kStaticRecordCount
+                      : BroadcastRing::GetRecordCount(mmap_size));
   }
 
   // Imports an existing ring at |mmap|.
@@ -233,6 +230,30 @@
     return MemorySize(Traits::kStaticRecordCount);
   }
 
+  static uint32_t NextPowerOf2(uint32_t n) {
+    if (n == 0)
+      return 0;
+    n -= 1;
+    n |= n >> 16;
+    n |= n >> 8;
+    n |= n >> 4;
+    n |= n >> 2;
+    n |= n >> 1;
+    return n + 1;
+  }
+
+  // Gets the biggest power of 2 record count that can fit into this mmap.
+  //
+  // The header size has been taken into account.
+  static uint32_t GetRecordCount(size_t mmap_size) {
+    if (mmap_size <= sizeof(Header)) {
+      return 0;
+    }
+    uint32_t count =
+        static_cast<uint32_t>((mmap_size - sizeof(Header)) / sizeof(Record));
+    return IsPowerOfTwo(count) ? count : (NextPowerOf2(count) / 2);
+  }
+
   // Writes a record to the ring.
   //
   // The oldest record is overwritten unless the ring is not already full.
@@ -348,6 +369,9 @@
     return Get(sequence, record);
   }
 
+  // Returns true if this instance has been created or imported.
+  bool is_valid() const { return !!data_.mmap; }
+
   uint32_t record_count() const { return record_count_internal(); }
   uint32_t record_size() const { return record_size_internal(); }
   static constexpr uint32_t mmap_alignment() { return alignof(Mmap); }
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index 452bad0..da0ea24 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -34,6 +34,11 @@
     "liblog",
     "libui",
     "libutils",
+    "libnativewindow"
+]
+
+HeaderLibraries = [
+    "libnativebase_headers",
 ]
 
 cc_library {
@@ -45,7 +50,11 @@
     export_include_dirs: localIncludeFiles,
     static_libs: staticLibraries,
     shared_libs: sharedLibraries,
+    header_libs: HeaderLibraries,
     name: "libbufferhub",
+    export_header_lib_headers: [
+        "libnativebase_headers",
+    ],
 }
 
 cc_test {
diff --git a/libs/vr/libbufferhub/bufferhub_tests.cpp b/libs/vr/libbufferhub/bufferhub_tests.cpp
index fa61c4a..1daa5d6 100644
--- a/libs/vr/libbufferhub/bufferhub_tests.cpp
+++ b/libs/vr/libbufferhub/bufferhub_tests.cpp
@@ -62,6 +62,57 @@
   EXPECT_GE(0, RETRY_EINTR(p->Poll(0)));
 }
 
+TEST_F(LibBufferHubTest, TestStateTransitions) {
+  std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+      kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+  ASSERT_TRUE(p.get() != nullptr);
+  std::unique_ptr<BufferConsumer> c =
+      BufferConsumer::Import(p->CreateConsumer());
+  ASSERT_TRUE(c.get() != nullptr);
+
+  uint64_t context;
+  LocalHandle fence;
+
+  // The producer buffer starts in gained state.
+
+  // Acquire, release, and gain in gained state should fail.
+  EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+  EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
+  EXPECT_EQ(-EALREADY, p->Gain(&fence));
+
+  // Post in gained state should succeed.
+  EXPECT_EQ(0, p->Post(LocalHandle(), kContext));
+
+  // Post, release, and gain in posted state should fail.
+  EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext));
+  EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
+  EXPECT_EQ(-EBUSY, p->Gain(&fence));
+
+  // Acquire in posted state should succeed.
+  EXPECT_LE(0, c->Acquire(&fence, &context));
+
+  // Acquire, post, and gain in acquired state should fail.
+  EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+  EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext));
+  EXPECT_EQ(-EBUSY, p->Gain(&fence));
+
+  // Release in acquired state should succeed.
+  EXPECT_EQ(0, c->Release(LocalHandle()));
+
+  // Release, acquire, and post in released state should fail.
+  EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
+  EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+  EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext));
+
+  // Gain in released state should succeed.
+  EXPECT_EQ(0, p->Gain(&fence));
+
+  // Acquire, release, and gain in gained state should fail.
+  EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
+  EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
+  EXPECT_EQ(-EALREADY, p->Gain(&fence));
+}
+
 TEST_F(LibBufferHubTest, TestWithCustomMetadata) {
   struct Metadata {
     int64_t field1;
diff --git a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
index ffdc9e2..ca0e0e0 100644
--- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
+++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
@@ -129,19 +129,102 @@
 using LocalFence = FenceHandle<pdx::LocalHandle>;
 using BorrowedFence = FenceHandle<pdx::BorrowedHandle>;
 
-struct QueueInfo {
+struct ProducerQueueConfig {
+  // Whether the buffer queue is operating in Async mode.
+  // From GVR's perspective of view, this means a buffer can be acquired
+  // asynchronously by the compositor.
+  // From Android Surface's perspective of view, this is equivalent to
+  // IGraphicBufferProducer's async mode. When in async mode, a producer
+  // will never block even if consumer is running slow.
+  bool is_async;
+
+  // Default buffer width that is set during ProducerQueue's creation.
+  uint32_t default_width;
+
+  // Default buffer height that is set during ProducerQueue's creation.
+  uint32_t default_height;
+
+  // Default buffer format that is set during ProducerQueue's creation.
+  uint32_t default_format;
+
+  // Size of the meta data associated with all the buffers allocated from the
+  // queue.
   size_t meta_size_bytes;
+
+ private:
+  PDX_SERIALIZABLE_MEMBERS(ProducerQueueConfig, is_async, default_width,
+                           default_height, default_format, meta_size_bytes);
+};
+
+class ProducerQueueConfigBuilder {
+ public:
+  // Build a ProducerQueueConfig object.
+  ProducerQueueConfig Build() {
+    return {is_async_, default_width_, default_height_, default_format_,
+            meta_size_bytes_};
+  }
+
+  ProducerQueueConfigBuilder& SetIsAsync(bool is_async) {
+    is_async_ = is_async;
+    return *this;
+  }
+
+  ProducerQueueConfigBuilder& SetDefaultWidth(uint32_t width) {
+    default_width_ = width;
+    return *this;
+  }
+
+  ProducerQueueConfigBuilder& SetDefaultHeight(uint32_t height) {
+    default_height_ = height;
+    return *this;
+  }
+
+  ProducerQueueConfigBuilder& SetDefaultFormat(uint32_t format) {
+    default_format_ = format;
+    return *this;
+  }
+
+  template <typename Meta>
+  ProducerQueueConfigBuilder& SetMetadata() {
+    meta_size_bytes_ = sizeof(Meta);
+    return *this;
+  }
+
+  ProducerQueueConfigBuilder& SetMetadataSize(size_t meta_size_bytes) {
+    meta_size_bytes_ = meta_size_bytes;
+    return *this;
+  }
+
+ private:
+  bool is_async_{false};
+  uint32_t default_width_{1};
+  uint32_t default_height_{1};
+  uint32_t default_format_{1};  // PIXEL_FORMAT_RGBA_8888
+  size_t meta_size_bytes_{0};
+};
+
+// Explicit specializations of ProducerQueueConfigBuilder::Build for void
+// metadata type.
+template <>
+inline ProducerQueueConfigBuilder&
+ProducerQueueConfigBuilder::SetMetadata<void>() {
+  meta_size_bytes_ = 0;
+  return *this;
+}
+
+struct QueueInfo {
+  ProducerQueueConfig producer_config;
   int id;
 
  private:
-  PDX_SERIALIZABLE_MEMBERS(QueueInfo, meta_size_bytes, id);
+  PDX_SERIALIZABLE_MEMBERS(QueueInfo, producer_config, id);
 };
 
 struct UsagePolicy {
-  uint64_t usage_set_mask;
-  uint64_t usage_clear_mask;
-  uint64_t usage_deny_set_mask;
-  uint64_t usage_deny_clear_mask;
+  uint64_t usage_set_mask{0};
+  uint64_t usage_clear_mask{0};
+  uint64_t usage_deny_set_mask{0};
+  uint64_t usage_deny_clear_mask{0};
 
  private:
   PDX_SERIALIZABLE_MEMBERS(UsagePolicy, usage_set_mask, usage_clear_mask,
@@ -181,7 +264,7 @@
     kOpCreateConsumerQueue,
     kOpGetQueueInfo,
     kOpProducerQueueAllocateBuffers,
-    kOpProducerQueueDetachBuffer,
+    kOpProducerQueueRemoveBuffer,
     kOpConsumerQueueImportBuffers,
   };
 
@@ -219,7 +302,7 @@
 
   // Buffer Queue Methods.
   PDX_REMOTE_METHOD(CreateProducerQueue, kOpCreateProducerQueue,
-                    QueueInfo(size_t meta_size_bytes,
+                    QueueInfo(const ProducerQueueConfig& producer_config,
                               const UsagePolicy& usage_policy));
   PDX_REMOTE_METHOD(CreateConsumerQueue, kOpCreateConsumerQueue,
                     LocalChannelHandle(Void));
@@ -229,7 +312,7 @@
                     std::vector<std::pair<LocalChannelHandle, size_t>>(
                         uint32_t width, uint32_t height, uint32_t layer_count,
                         uint32_t format, uint64_t usage, size_t buffer_count));
-  PDX_REMOTE_METHOD(ProducerQueueDetachBuffer, kOpProducerQueueDetachBuffer,
+  PDX_REMOTE_METHOD(ProducerQueueRemoveBuffer, kOpProducerQueueRemoveBuffer,
                     void(size_t slot));
   PDX_REMOTE_METHOD(ConsumerQueueImportBuffers, kOpConsumerQueueImportBuffers,
                     std::vector<std::pair<LocalChannelHandle, size_t>>(Void));
diff --git a/libs/vr/libbufferhub/include/private/dvr/native_buffer.h b/libs/vr/libbufferhub/include/private/dvr/native_buffer.h
index b4ef2f5..140ffc5 100644
--- a/libs/vr/libbufferhub/include/private/dvr/native_buffer.h
+++ b/libs/vr/libbufferhub/include/private/dvr/native_buffer.h
@@ -4,9 +4,9 @@
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 #include <log/log.h>
-#include <system/window.h>
 #include <ui/ANativeObjectBase.h>
 #include <utils/RefBase.h>
+#include <nativebase/nativebase.h>
 
 #include <private/dvr/buffer_hub_client.h>
 
@@ -52,8 +52,6 @@
   void operator=(NativeBuffer&) = delete;
 };
 
-// NativeBufferProducer is an implementation of ANativeWindowBuffer backed by a
-// BufferProducer.
 class NativeBufferProducer : public android::ANativeObjectBase<
                                  ANativeWindowBuffer, NativeBufferProducer,
                                  android::LightRefBase<NativeBufferProducer>> {
@@ -71,20 +69,25 @@
     ANativeWindowBuffer::stride = buffer_->stride();
     ANativeWindowBuffer::format = buffer_->format();
     ANativeWindowBuffer::usage = buffer_->usage();
-    handle = buffer_->native_handle();
+    ANativeWindowBuffer::handle = buffer_->native_handle();
+    if (display_) {
+      image_khr_ =
+          eglCreateImageKHR(display_, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+                            static_cast<ANativeWindowBuffer*>(this), nullptr);
+    } else {
+      image_khr_ = EGL_NO_IMAGE_KHR;
+    }
   }
 
   explicit NativeBufferProducer(const std::shared_ptr<BufferProducer>& buffer)
       : NativeBufferProducer(buffer, nullptr, 0) {}
 
   virtual ~NativeBufferProducer() {
-    for (EGLImageKHR egl_image : egl_images_) {
-      if (egl_image != EGL_NO_IMAGE_KHR)
-        eglDestroyImageKHR(display_, egl_image);
-    }
+    if (image_khr_ != EGL_NO_IMAGE_KHR)
+      eglDestroyImageKHR(display_, image_khr_);
   }
 
-  EGLImageKHR image_khr(int index) const { return egl_images_[index]; }
+  EGLImageKHR image_khr() const { return image_khr_; }
   std::shared_ptr<BufferProducer> buffer() const { return buffer_; }
   int release_fence() const { return release_fence_.Get(); }
   uint32_t surface_buffer_index() const { return surface_buffer_index_; }
@@ -112,7 +115,7 @@
 
   std::shared_ptr<BufferProducer> buffer_;
   pdx::LocalHandle release_fence_;
-  std::vector<EGLImageKHR> egl_images_;
+  EGLImageKHR image_khr_;
   uint32_t surface_buffer_index_;
   EGLDisplay display_;
 
diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp
index a587f95..0b3b2f0 100644
--- a/libs/vr/libbufferhubqueue/Android.bp
+++ b/libs/vr/libbufferhubqueue/Android.bp
@@ -21,10 +21,6 @@
     "include",
 ]
 
-headerLibraries = [
-    "libdvr_headers",
-]
-
 staticLibraries = [
     "libbufferhub",
     "libdvrcommon",
@@ -42,6 +38,11 @@
     "libgui",
 ]
 
+headerLibraries = [
+    "libdvr_headers",
+    "libnativebase_headers",
+]
+
 cc_library {
     name: "libbufferhubqueue",
     cflags: [
@@ -51,9 +52,9 @@
     srcs: sourceFiles,
     export_include_dirs: includeFiles,
     export_static_lib_headers: staticLibraries,
-    header_libs: headerLibraries,
     static_libs: staticLibraries,
     shared_libs: sharedLibraries,
+    header_libs: headerLibraries,
 }
 
 subdirs = ["tests"]
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index 012a4e7..bfb9a55 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -10,7 +10,6 @@
 #include <pdx/default_transport/client_channel.h>
 #include <pdx/default_transport/client_channel_factory.h>
 #include <pdx/file_handle.h>
-#include <private/dvr/bufferhub_rpc.h>
 
 #define RETRY_EINTR(fnc_call)                 \
   ([&]() -> decltype(fnc_call) {              \
@@ -23,34 +22,61 @@
 
 using android::pdx::ErrorStatus;
 using android::pdx::LocalChannelHandle;
+using android::pdx::LocalHandle;
 using android::pdx::Status;
 
 namespace android {
 namespace dvr {
 
+namespace {
+
+// Polls an fd for the given events.
+Status<int> PollEvents(int fd, short events) {
+  const int kTimeoutMs = 0;
+  pollfd pfd{fd, events, 0};
+  const int count = RETRY_EINTR(poll(&pfd, 1, kTimeoutMs));
+  if (count < 0) {
+    return ErrorStatus(errno);
+  } else if (count == 0) {
+    return ErrorStatus(ETIMEDOUT);
+  } else {
+    return {pfd.revents};
+  }
+}
+
+// Polls a buffer for the given events, taking care to do the proper
+// translation.
+Status<int> PollEvents(const std::shared_ptr<BufferHubBuffer>& buffer,
+                       short events) {
+  auto poll_status = PollEvents(buffer->event_fd(), events);
+  if (!poll_status)
+    return poll_status;
+
+  return buffer->GetEventMask(poll_status.get());
+}
+
+std::pair<int32_t, int32_t> Unstuff(uint64_t value) {
+  return {static_cast<int32_t>(value >> 32),
+          static_cast<int32_t>(value & ((1ull << 32) - 1))};
+}
+
+uint64_t Stuff(int32_t a, int32_t b) {
+  const uint32_t ua = static_cast<uint32_t>(a);
+  const uint32_t ub = static_cast<uint32_t>(b);
+  return (static_cast<uint64_t>(ua) << 32) | static_cast<uint64_t>(ub);
+}
+
+}  // anonymous namespace
+
 BufferHubQueue::BufferHubQueue(LocalChannelHandle channel_handle)
     : Client{pdx::default_transport::ClientChannel::Create(
-          std::move(channel_handle))},
-      meta_size_(0),
-      buffers_(BufferHubQueue::kMaxQueueCapacity),
-      epollhup_pending_(BufferHubQueue::kMaxQueueCapacity, false),
-      available_buffers_(BufferHubQueue::kMaxQueueCapacity),
-      fences_(BufferHubQueue::kMaxQueueCapacity),
-      capacity_(0),
-      id_(-1) {
+          std::move(channel_handle))} {
   Initialize();
 }
 
 BufferHubQueue::BufferHubQueue(const std::string& endpoint_path)
-    : Client{pdx::default_transport::ClientChannelFactory::Create(
-          endpoint_path)},
-      meta_size_(0),
-      buffers_(BufferHubQueue::kMaxQueueCapacity),
-      epollhup_pending_(BufferHubQueue::kMaxQueueCapacity, false),
-      available_buffers_(BufferHubQueue::kMaxQueueCapacity),
-      fences_(BufferHubQueue::kMaxQueueCapacity),
-      capacity_(0),
-      id_(-1) {
+    : Client{
+          pdx::default_transport::ClientChannelFactory::Create(endpoint_path)} {
   Initialize();
 }
 
@@ -62,9 +88,9 @@
     return;
   }
 
-  epoll_event event = {.events = EPOLLIN | EPOLLET,
-                       .data = {.u64 = static_cast<uint64_t>(
-                                    BufferHubQueue::kEpollQueueEventIndex)}};
+  epoll_event event = {
+      .events = EPOLLIN | EPOLLET,
+      .data = {.u64 = Stuff(-1, BufferHubQueue::kEpollQueueEventIndex)}};
   ret = epoll_fd_.Control(EPOLL_CTL_ADD, event_fd(), &event);
   if (ret < 0) {
     ALOGE("BufferHubQueue::Initialize: Failed to add event fd to epoll set: %s",
@@ -79,15 +105,18 @@
           status.GetErrorMessage().c_str());
     return ErrorStatus(status.error());
   } else {
-    SetupQueue(status.get().meta_size_bytes, status.get().id);
+    SetupQueue(status.get());
     return {};
   }
 }
 
-void BufferHubQueue::SetupQueue(size_t meta_size_bytes, int id) {
-  meta_size_ = meta_size_bytes;
-  id_ = id;
-  meta_buffer_tmp_.reset(meta_size_ > 0 ? new uint8_t[meta_size_] : nullptr);
+void BufferHubQueue::SetupQueue(const QueueInfo& queue_info) {
+  is_async_ = queue_info.producer_config.is_async;
+  default_width_ = queue_info.producer_config.default_width;
+  default_height_ = queue_info.producer_config.default_height;
+  default_format_ = queue_info.producer_config.default_format;
+  meta_size_ = queue_info.producer_config.meta_size_bytes;
+  id_ = queue_info.id;
 }
 
 std::unique_ptr<ConsumerQueue> BufferHubQueue::CreateConsumerQueue() {
@@ -152,19 +181,24 @@
     // one for each buffer, in the queue and one extra event for the queue
     // client itself.
     for (int i = 0; i < num_events; i++) {
-      int64_t index = static_cast<int64_t>(events[i].data.u64);
+      int32_t event_fd;
+      int32_t index;
+      std::tie(event_fd, index) = Unstuff(events[i].data.u64);
 
       ALOGD_IF(TRACE,
-               "BufferHubQueue::WaitForBuffers: event %d: index=%" PRId64, i,
-               index);
+               "BufferHubQueue::WaitForBuffers: event %d: event_fd=%d index=%d",
+               i, event_fd, index);
 
       if (is_buffer_event_index(index)) {
-        HandleBufferEvent(static_cast<size_t>(index), events[i].events);
+        HandleBufferEvent(static_cast<size_t>(index), event_fd,
+                          events[i].events);
       } else if (is_queue_event_index(index)) {
         HandleQueueEvent(events[i].events);
       } else {
-        ALOGW("BufferHubQueue::WaitForBuffers: Unknown event index: %" PRId64,
-              index);
+        ALOGW(
+            "BufferHubQueue::WaitForBuffers: Unknown event type event_fd=%d "
+            "index=%d",
+            event_fd, index);
       }
     }
   } while (count() == 0 && capacity() > 0 && !hung_up());
@@ -172,52 +206,72 @@
   return count() != 0;
 }
 
-void BufferHubQueue::HandleBufferEvent(size_t slot, int poll_events) {
-  auto buffer = buffers_[slot];
-  if (!buffer) {
+Status<void> BufferHubQueue::HandleBufferEvent(size_t slot, int event_fd,
+                                               int poll_events) {
+  if (!buffers_[slot]) {
     ALOGW("BufferHubQueue::HandleBufferEvent: Invalid buffer slot: %zu", slot);
-    return;
+    return ErrorStatus(ENOENT);
   }
 
-  auto status = buffer->GetEventMask(poll_events);
+  auto status = buffers_[slot]->GetEventMask(poll_events);
   if (!status) {
     ALOGW("BufferHubQueue::HandleBufferEvent: Failed to get event mask: %s",
           status.GetErrorMessage().c_str());
-    return;
+    return status.error_status();
   }
 
   const int events = status.get();
   if (events & EPOLLIN) {
-    const int ret = OnBufferReady(buffer, &fences_[slot]);
-    if (ret == 0 || ret == -EALREADY || ret == -EBUSY) {
+    auto entry_status = OnBufferReady(buffers_[slot], slot);
+    if (entry_status.ok() || entry_status.error() == EALREADY) {
       // Only enqueue the buffer if it moves to or is already in the state
-      // requested in OnBufferReady(). If the buffer is busy this means that the
-      // buffer moved from released to posted when a new consumer was created
-      // before the ProducerQueue had a chance to regain it. This is a valid
-      // transition that we have to handle because edge triggered poll events
-      // latch the ready state even if it is later de-asserted -- don't enqueue
-      // or print an error log in this case.
-      if (ret != -EBUSY)
-        Enqueue(buffer, slot);
+      // requested in OnBufferReady().
+      return Enqueue(entry_status.take());
+    } else if (entry_status.error() == EBUSY) {
+      // If the buffer is busy this means that the buffer moved from released to
+      // posted when a new consumer was created before the ProducerQueue had a
+      // chance to regain it. This is a valid transition that we have to handle
+      // because edge triggered poll events latch the ready state even if it is
+      // later de-asserted -- don't enqueue or print an error log in this case.
     } else {
       ALOGE(
           "BufferHubQueue::HandleBufferEvent: Failed to set buffer ready, "
           "queue_id=%d buffer_id=%d: %s",
-          id(), buffer->id(), strerror(-ret));
+          id(), buffers_[slot]->id(), entry_status.GetErrorMessage().c_str());
     }
   } else if (events & EPOLLHUP) {
-    // This might be caused by producer replacing an existing buffer slot, or
-    // when BufferHubQueue is shutting down. For the first case, currently the
-    // epoll FD is cleaned up when the replacement consumer client is imported,
-    // we shouldn't detach again if |epollhub_pending_[slot]| is set.
+    // Check to see if the current buffer in the slot hung up. This is a bit of
+    // paranoia to deal with the epoll set getting out of sync with the buffer
+    // slots.
+    auto poll_status = PollEvents(buffers_[slot], POLLIN);
+    if (!poll_status && poll_status.error() != ETIMEDOUT) {
+      ALOGE("BufferHubQueue::HandleBufferEvent: Failed to poll buffer: %s",
+            poll_status.GetErrorMessage().c_str());
+      return poll_status.error_status();
+    }
+
+    const bool hangup_pending = status.ok() && (poll_status.get() & EPOLLHUP);
+
     ALOGW(
-        "BufferHubQueue::HandleBufferEvent: Received EPOLLHUP at slot: %zu, "
-        "buffer event fd: %d, EPOLLHUP pending: %d",
-        slot, buffer->event_fd(), int{epollhup_pending_[slot]});
-    if (epollhup_pending_[slot]) {
-      epollhup_pending_[slot] = false;
+        "BufferHubQueue::HandleBufferEvent: Received EPOLLHUP event: slot=%zu "
+        "event_fd=%d buffer_id=%d hangup_pending=%d poll_status=%x",
+        slot, buffers_[slot]->event_fd(), buffers_[slot]->id(), hangup_pending,
+        poll_status.get());
+
+    if (hangup_pending) {
+      return RemoveBuffer(slot);
     } else {
-      DetachBuffer(slot);
+      // Clean up the bookkeeping for the event fd. This is a bit of paranoia to
+      // deal with the epoll set getting out of sync with the buffer slots.
+      // Hitting this path should be very unusual.
+      const int ret = epoll_fd_.Control(EPOLL_CTL_DEL, event_fd, nullptr);
+      if (ret < 0) {
+        ALOGE(
+            "BufferHubQueue::HandleBufferEvent: Failed to remove fd=%d from "
+            "epoll set: %s",
+            event_fd, strerror(-ret));
+        return ErrorStatus(-ret);
+      }
     }
   } else {
     ALOGW(
@@ -225,14 +279,16 @@
         "events=%d",
         slot, events);
   }
+
+  return {};
 }
 
-void BufferHubQueue::HandleQueueEvent(int poll_event) {
+Status<void> BufferHubQueue::HandleQueueEvent(int poll_event) {
   auto status = GetEventMask(poll_event);
   if (!status) {
     ALOGW("BufferHubQueue::HandleQueueEvent: Failed to get event mask: %s",
           status.GetErrorMessage().c_str());
-    return;
+    return status.error_status();
   }
 
   const int events = status.get();
@@ -250,115 +306,116 @@
   } else {
     ALOGW("BufferHubQueue::HandleQueueEvent: Unknown epoll events=%x", events);
   }
+
+  return {};
 }
 
-int BufferHubQueue::AddBuffer(const std::shared_ptr<BufferHubBuffer>& buf,
-                              size_t slot) {
+Status<void> BufferHubQueue::AddBuffer(
+    const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) {
+  ALOGD_IF(TRACE, "BufferHubQueue::AddBuffer: buffer_id=%d slot=%zu",
+           buffer->id(), slot);
+
   if (is_full()) {
-    // TODO(jwcai) Move the check into Producer's AllocateBuffer and consumer's
-    // import buffer.
     ALOGE("BufferHubQueue::AddBuffer queue is at maximum capacity: %zu",
           capacity_);
-    return -E2BIG;
+    return ErrorStatus(E2BIG);
   }
 
-  if (buffers_[slot] != nullptr) {
-    // Replace the buffer if the slot is preoccupied. This could happen when the
-    // producer side replaced the slot with a newly allocated buffer. Detach the
+  if (buffers_[slot]) {
+    // Replace the buffer if the slot is occupied. This could happen when the
+    // producer side replaced the slot with a newly allocated buffer. Remove the
     // buffer before setting up with the new one.
-    DetachBuffer(slot);
-    epollhup_pending_[slot] = true;
+    auto remove_status = RemoveBuffer(slot);
+    if (!remove_status)
+      return remove_status.error_status();
   }
 
-  epoll_event event = {.events = EPOLLIN | EPOLLET, .data = {.u64 = slot}};
-  const int ret = epoll_fd_.Control(EPOLL_CTL_ADD, buf->event_fd(), &event);
+  epoll_event event = {.events = EPOLLIN | EPOLLET,
+                       .data = {.u64 = Stuff(buffer->event_fd(), slot)}};
+  const int ret = epoll_fd_.Control(EPOLL_CTL_ADD, buffer->event_fd(), &event);
   if (ret < 0) {
     ALOGE("BufferHubQueue::AddBuffer: Failed to add buffer to epoll set: %s",
           strerror(-ret));
-    return ret;
+    return ErrorStatus(-ret);
   }
 
-  buffers_[slot] = buf;
+  buffers_[slot] = buffer;
   capacity_++;
-  return 0;
+  return {};
 }
 
-int BufferHubQueue::DetachBuffer(size_t slot) {
-  auto& buf = buffers_[slot];
-  if (buf == nullptr) {
-    ALOGE("BufferHubQueue::DetachBuffer: Invalid slot: %zu", slot);
-    return -EINVAL;
+Status<void> BufferHubQueue::RemoveBuffer(size_t slot) {
+  ALOGD_IF(TRACE, "BufferHubQueue::RemoveBuffer: slot=%zu", slot);
+
+  if (buffers_[slot]) {
+    const int ret =
+        epoll_fd_.Control(EPOLL_CTL_DEL, buffers_[slot]->event_fd(), nullptr);
+    if (ret < 0) {
+      ALOGE(
+          "BufferHubQueue::RemoveBuffer: Failed to remove buffer from epoll "
+          "set: "
+          "%s",
+          strerror(-ret));
+      return ErrorStatus(-ret);
+    }
+
+    // Trigger OnBufferRemoved callback if registered.
+    if (on_buffer_removed_)
+      on_buffer_removed_(buffers_[slot]);
+
+    buffers_[slot] = nullptr;
+    capacity_--;
   }
 
-  const int ret = epoll_fd_.Control(EPOLL_CTL_DEL, buf->event_fd(), nullptr);
-  if (ret < 0) {
-    ALOGE(
-        "BufferHubQueue::DetachBuffer: Failed to detach buffer from epoll set: "
-        "%s",
-        strerror(-ret));
-    return ret;
-  }
-
-  buffers_[slot] = nullptr;
-  capacity_--;
-  return 0;
+  return {};
 }
 
-void BufferHubQueue::Enqueue(const std::shared_ptr<BufferHubBuffer>& buf,
-                             size_t slot) {
-  if (count() == capacity_) {
+Status<void> BufferHubQueue::Enqueue(Entry entry) {
+  if (!is_full()) {
+    available_buffers_.Append(std::move(entry));
+
+    // Trigger OnBufferAvailable callback if registered.
+    if (on_buffer_available_)
+      on_buffer_available_();
+
+    return {};
+  } else {
     ALOGE("BufferHubQueue::Enqueue: Buffer queue is full!");
-    return;
+    return ErrorStatus(E2BIG);
   }
-
-  // Set slot buffer back to vector.
-  // TODO(jwcai) Here have to dynamically allocate BufferInfo::metadata due to
-  // the limitation of the RingBuffer we are using. Would be better to refactor
-  // that.
-  BufferInfo buffer_info(slot, meta_size_);
-  buffer_info.buffer = buf;
-  // Swap metadata loaded during onBufferReady into vector.
-  std::swap(buffer_info.metadata, meta_buffer_tmp_);
-
-  available_buffers_.Append(std::move(buffer_info));
 }
 
 Status<std::shared_ptr<BufferHubBuffer>> BufferHubQueue::Dequeue(
     int timeout, size_t* slot, void* meta, LocalHandle* fence) {
-  ALOGD_IF(TRACE, "Dequeue: count=%zu, timeout=%d", count(), timeout);
+  ALOGD_IF(TRACE, "BufferHubQueue::Dequeue: count=%zu, timeout=%d", count(),
+           timeout);
 
   if (!WaitForBuffers(timeout))
     return ErrorStatus(ETIMEDOUT);
 
-  std::shared_ptr<BufferHubBuffer> buf;
-  BufferInfo& buffer_info = available_buffers_.Front();
+  auto& entry = available_buffers_.Front();
 
-  *fence = std::move(fences_[buffer_info.slot]);
-
-  // Report current pos as the output slot.
-  std::swap(buffer_info.slot, *slot);
-  // Swap buffer from vector to be returned later.
-  std::swap(buffer_info.buffer, buf);
-  // Swap metadata from vector into tmp so that we can write out to |meta|.
-  std::swap(buffer_info.metadata, meta_buffer_tmp_);
-
-  available_buffers_.PopFront();
-
-  if (!buf) {
-    ALOGE("BufferHubQueue::Dequeue: Buffer to be dequeued is nullptr");
-    return ErrorStatus(ENOBUFS);
-  }
-
-  if (meta) {
-    std::copy(meta_buffer_tmp_.get(), meta_buffer_tmp_.get() + meta_size_,
+  std::shared_ptr<BufferHubBuffer> buffer = std::move(entry.buffer);
+  *slot = entry.slot;
+  *fence = std::move(entry.fence);
+  if (meta && entry.metadata) {
+    std::copy(entry.metadata.get(), entry.metadata.get() + meta_size_,
               reinterpret_cast<uint8_t*>(meta));
   }
 
-  return {std::move(buf)};
+  available_buffers_.PopFront();
+
+  return {std::move(buffer)};
 }
 
-ProducerQueue::ProducerQueue(size_t meta_size)
-    : ProducerQueue(meta_size, 0, 0, 0, 0) {}
+void BufferHubQueue::SetBufferAvailableCallback(
+    BufferAvailableCallback callback) {
+  on_buffer_available_ = callback;
+}
+
+void BufferHubQueue::SetBufferRemovedCallback(BufferRemovedCallback callback) {
+  on_buffer_removed_ = callback;
+}
 
 ProducerQueue::ProducerQueue(LocalChannelHandle handle)
     : BASE(std::move(handle)) {
@@ -370,14 +427,11 @@
   }
 }
 
-ProducerQueue::ProducerQueue(size_t meta_size, uint64_t usage_set_mask,
-                             uint64_t usage_clear_mask,
-                             uint64_t usage_deny_set_mask,
-                             uint64_t usage_deny_clear_mask)
+ProducerQueue::ProducerQueue(const ProducerQueueConfig& config,
+                             const UsagePolicy& usage)
     : BASE(BufferHubRPC::kClientPath) {
-  auto status = InvokeRemoteMethod<BufferHubRPC::CreateProducerQueue>(
-      meta_size, UsagePolicy{usage_set_mask, usage_clear_mask,
-                             usage_deny_set_mask, usage_deny_clear_mask});
+  auto status =
+      InvokeRemoteMethod<BufferHubRPC::CreateProducerQueue>(config, usage);
   if (!status) {
     ALOGE("ProducerQueue::ProducerQueue: Failed to create producer queue: %s",
           status.GetErrorMessage().c_str());
@@ -385,74 +439,106 @@
     return;
   }
 
-  SetupQueue(status.get().meta_size_bytes, status.get().id);
+  SetupQueue(status.get());
 }
 
-int ProducerQueue::AllocateBuffer(uint32_t width, uint32_t height,
-                                  uint32_t layer_count, uint32_t format,
-                                  uint64_t usage, size_t* out_slot) {
-  if (out_slot == nullptr) {
-    ALOGE("ProducerQueue::AllocateBuffer: Parameter out_slot cannot be null.");
-    return -EINVAL;
+Status<std::vector<size_t>> ProducerQueue::AllocateBuffers(
+    uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
+    uint64_t usage, size_t buffer_count) {
+  if (capacity() + buffer_count > kMaxQueueCapacity) {
+    ALOGE(
+        "ProducerQueue::AllocateBuffers: queue is at capacity: %zu, cannot "
+        "allocate %zu more buffer(s).",
+        capacity(), buffer_count);
+    return ErrorStatus(E2BIG);
   }
 
-  if (is_full()) {
-    ALOGE("ProducerQueue::AllocateBuffer queue is at maximum capacity: %zu",
-          capacity());
-    return -E2BIG;
-  }
-
-  const size_t kBufferCount = 1U;
   Status<std::vector<std::pair<LocalChannelHandle, size_t>>> status =
       InvokeRemoteMethod<BufferHubRPC::ProducerQueueAllocateBuffers>(
-          width, height, layer_count, format, usage, kBufferCount);
+          width, height, layer_count, format, usage, buffer_count);
   if (!status) {
-    ALOGE("ProducerQueue::AllocateBuffer failed to create producer buffer: %s",
+    ALOGE("ProducerQueue::AllocateBuffers: failed to allocate buffers: %s",
           status.GetErrorMessage().c_str());
-    return -status.error();
+    return status.error_status();
   }
 
   auto buffer_handle_slots = status.take();
-  LOG_ALWAYS_FATAL_IF(buffer_handle_slots.size() != kBufferCount,
+  LOG_ALWAYS_FATAL_IF(buffer_handle_slots.size() != buffer_count,
                       "BufferHubRPC::ProducerQueueAllocateBuffers should "
-                      "return one and only one buffer handle.");
+                      "return %zu buffer handle(s), but returned %zu instead.",
+                      buffer_count, buffer_handle_slots.size());
 
-  // We only allocate one buffer at a time.
-  auto& buffer_handle = buffer_handle_slots[0].first;
-  size_t buffer_slot = buffer_handle_slots[0].second;
-  ALOGD_IF(TRACE,
-           "ProducerQueue::AllocateBuffer, new buffer, channel_handle: %d",
-           buffer_handle.value());
+  std::vector<size_t> buffer_slots;
+  buffer_slots.reserve(buffer_count);
 
-  *out_slot = buffer_slot;
-  return AddBuffer(BufferProducer::Import(std::move(buffer_handle)),
-                   buffer_slot);
-}
+  // Bookkeeping for each buffer.
+  for (auto& hs : buffer_handle_slots) {
+    auto& buffer_handle = hs.first;
+    size_t buffer_slot = hs.second;
 
-int ProducerQueue::AddBuffer(const std::shared_ptr<BufferProducer>& buf,
-                             size_t slot) {
-  ALOGD_IF(TRACE, "ProducerQueue::AddBuffer: queue_id=%d buffer_id=%d slot=%zu",
-           id(), buf->id(), slot);
-  // For producer buffer, we need to enqueue the newly added buffer
-  // immediately. Producer queue starts with all buffers in available state.
-  const int ret = BufferHubQueue::AddBuffer(buf, slot);
-  if (ret < 0)
-    return ret;
-
-  Enqueue(buf, slot);
-  return 0;
-}
-
-int ProducerQueue::DetachBuffer(size_t slot) {
-  auto status =
-      InvokeRemoteMethod<BufferHubRPC::ProducerQueueDetachBuffer>(slot);
-  if (!status) {
-    ALOGE("ProducerQueue::DetachBuffer: Failed to detach producer buffer: %s",
-          status.GetErrorMessage().c_str());
-    return -status.error();
+    // Note that import might (though very unlikely) fail. If so, buffer_handle
+    // will be closed and included in returned buffer_slots.
+    if (AddBuffer(BufferProducer::Import(std::move(buffer_handle)),
+                  buffer_slot)) {
+      ALOGD_IF(TRACE, "ProducerQueue::AllocateBuffers: new buffer at slot: %zu",
+               buffer_slot);
+      buffer_slots.push_back(buffer_slot);
+    }
   }
 
-  return BufferHubQueue::DetachBuffer(slot);
+  if (buffer_slots.size() == 0) {
+    // Error out if no buffer is allocated and improted.
+    ALOGE_IF(TRACE, "ProducerQueue::AllocateBuffers: no buffer allocated.");
+    ErrorStatus(ENOMEM);
+  }
+
+  return {std::move(buffer_slots)};
+}
+
+Status<size_t> ProducerQueue::AllocateBuffer(uint32_t width, uint32_t height,
+                                             uint32_t layer_count,
+                                             uint32_t format, uint64_t usage) {
+  // We only allocate one buffer at a time.
+  constexpr size_t buffer_count = 1;
+  auto status =
+      AllocateBuffers(width, height, layer_count, format, usage, buffer_count);
+  if (!status) {
+    ALOGE("ProducerQueue::AllocateBuffer: Failed to allocate buffer: %s",
+          status.GetErrorMessage().c_str());
+    return status.error_status();
+  }
+
+  if (status.get().size() == 0) {
+    ALOGE_IF(TRACE, "ProducerQueue::AllocateBuffer: no buffer allocated.");
+    ErrorStatus(ENOMEM);
+  }
+
+  return {status.get()[0]};
+}
+
+Status<void> ProducerQueue::AddBuffer(
+    const std::shared_ptr<BufferProducer>& buffer, size_t slot) {
+  ALOGD_IF(TRACE, "ProducerQueue::AddBuffer: queue_id=%d buffer_id=%d slot=%zu",
+           id(), buffer->id(), slot);
+  // For producer buffer, we need to enqueue the newly added buffer
+  // immediately. Producer queue starts with all buffers in available state.
+  auto status = BufferHubQueue::AddBuffer(buffer, slot);
+  if (!status)
+    return status;
+
+  return Enqueue(buffer, slot);
+}
+
+Status<void> ProducerQueue::RemoveBuffer(size_t slot) {
+  auto status =
+      InvokeRemoteMethod<BufferHubRPC::ProducerQueueRemoveBuffer>(slot);
+  if (!status) {
+    ALOGE("ProducerQueue::RemoveBuffer: Failed to remove producer buffer: %s",
+          status.GetErrorMessage().c_str());
+    return status.error_status();
+  }
+
+  return BufferHubQueue::RemoveBuffer(slot);
 }
 
 Status<std::shared_ptr<BufferProducer>> ProducerQueue::Dequeue(
@@ -471,12 +557,22 @@
   return {std::static_pointer_cast<BufferProducer>(buffer_status.take())};
 }
 
-int ProducerQueue::OnBufferReady(const std::shared_ptr<BufferHubBuffer>& buf,
-                                 LocalHandle* release_fence) {
-  ALOGD_IF(TRACE, "ProducerQueue::OnBufferReady: queue_id=%d buffer_id=%d",
-           id(), buf->id());
-  auto buffer = std::static_pointer_cast<BufferProducer>(buf);
-  return buffer->Gain(release_fence);
+Status<BufferHubQueue::Entry> ProducerQueue::OnBufferReady(
+    const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) {
+  ALOGD_IF(TRACE,
+           "ProducerQueue::OnBufferReady: queue_id=%d buffer_id=%d slot=%zu",
+           id(), buffer->id(), slot);
+
+  // Avoid taking a transient reference, buffer is valid for the duration of
+  // this method call.
+  auto* producer_buffer = static_cast<BufferProducer*>(buffer.get());
+  LocalHandle release_fence;
+
+  const int ret = producer_buffer->Gain(&release_fence);
+  if (ret < 0)
+    return ErrorStatus(-ret);
+  else
+    return {{buffer, nullptr, std::move(release_fence), slot}};
 }
 
 ConsumerQueue::ConsumerQueue(LocalChannelHandle handle, bool ignore_on_import)
@@ -503,12 +599,12 @@
   if (!status) {
     ALOGE("ConsumerQueue::ImportBuffers: Failed to import consumer buffer: %s",
           status.GetErrorMessage().c_str());
-    return ErrorStatus(status.error());
+    return status.error_status();
   }
 
   int ret;
-  int last_error = 0;
-  int imported_buffers = 0;
+  Status<void> last_error;
+  size_t imported_buffers_count = 0;
 
   auto buffer_handle_slots = status.take();
   for (auto& buffer_handle_slot : buffer_handle_slots) {
@@ -517,6 +613,12 @@
 
     std::unique_ptr<BufferConsumer> buffer_consumer =
         BufferConsumer::Import(std::move(buffer_handle_slot.first));
+    if (!buffer_consumer) {
+      ALOGE("ConsumerQueue::ImportBuffers: Failed to import buffer: slot=%zu",
+            buffer_handle_slot.second);
+      last_error = ErrorStatus(EPIPE);
+      continue;
+    }
 
     // Setup ignore state before adding buffer to the queue.
     if (ignore_on_import_) {
@@ -530,53 +632,52 @@
             "ConsumerQueue::ImportBuffers: Failed to set ignored state on "
             "imported buffer buffer_id=%d: %s",
             buffer_consumer->id(), strerror(-ret));
-        last_error = ret;
+        last_error = ErrorStatus(-ret);
       }
     }
 
-    ret = AddBuffer(std::move(buffer_consumer), buffer_handle_slot.second);
-    if (ret < 0) {
+    auto add_status =
+        AddBuffer(std::move(buffer_consumer), buffer_handle_slot.second);
+    if (!add_status) {
       ALOGE("ConsumerQueue::ImportBuffers: Failed to add buffer: %s",
-            strerror(-ret));
-      last_error = ret;
-      continue;
+            add_status.GetErrorMessage().c_str());
+      last_error = add_status;
     } else {
-      imported_buffers++;
+      imported_buffers_count++;
     }
   }
 
-  if (imported_buffers > 0)
-    return {imported_buffers};
+  if (imported_buffers_count > 0)
+    return {imported_buffers_count};
   else
-    return ErrorStatus(-last_error);
+    return last_error.error_status();
 }
 
-int ConsumerQueue::AddBuffer(const std::shared_ptr<BufferConsumer>& buf,
-                             size_t slot) {
+Status<void> ConsumerQueue::AddBuffer(
+    const std::shared_ptr<BufferConsumer>& buffer, size_t slot) {
   ALOGD_IF(TRACE, "ConsumerQueue::AddBuffer: queue_id=%d buffer_id=%d slot=%zu",
-           id(), buf->id(), slot);
-  const int ret = BufferHubQueue::AddBuffer(buf, slot);
-  if (ret < 0)
-    return ret;
+           id(), buffer->id(), slot);
+  auto status = BufferHubQueue::AddBuffer(buffer, slot);
+  if (!status)
+    return status;
 
   // Check to see if the buffer is already signaled. This is necessary to catch
   // cases where buffers are already available; epoll edge triggered mode does
   // not fire until and edge transition when adding new buffers to the epoll
-  // set.
-  const int kTimeoutMs = 0;
-  pollfd pfd{buf->event_fd(), POLLIN, 0};
-  const int count = RETRY_EINTR(poll(&pfd, 1, kTimeoutMs));
-  if (count < 0) {
-    const int error = errno;
+  // set. Note that we only poll the fd events because HandleBufferEvent() takes
+  // care of checking the translated buffer events.
+  auto poll_status = PollEvents(buffer->event_fd(), POLLIN);
+  if (!poll_status && poll_status.error() != ETIMEDOUT) {
     ALOGE("ConsumerQueue::AddBuffer: Failed to poll consumer buffer: %s",
-          strerror(errno));
-    return -error;
+          poll_status.GetErrorMessage().c_str());
+    return poll_status.error_status();
   }
 
-  if (count == 1)
-    HandleBufferEvent(slot, pfd.revents);
-
-  return 0;
+  // Update accounting if the buffer is available.
+  if (poll_status)
+    return HandleBufferEvent(slot, buffer->event_fd(), poll_status.get());
+  else
+    return {};
 }
 
 Status<std::shared_ptr<BufferConsumer>> ConsumerQueue::Dequeue(
@@ -606,15 +707,30 @@
   return {std::static_pointer_cast<BufferConsumer>(buffer_status.take())};
 }
 
-int ConsumerQueue::OnBufferReady(const std::shared_ptr<BufferHubBuffer>& buf,
-                                 LocalHandle* acquire_fence) {
-  ALOGD_IF(TRACE, "ConsumerQueue::OnBufferReady: queue_id=%d buffer_id=%d",
-           id(), buf->id());
-  auto buffer = std::static_pointer_cast<BufferConsumer>(buf);
-  return buffer->Acquire(acquire_fence, meta_buffer_tmp_.get(), meta_size_);
+Status<BufferHubQueue::Entry> ConsumerQueue::OnBufferReady(
+    const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) {
+  ALOGD_IF(TRACE,
+           "ConsumerQueue::OnBufferReady: queue_id=%d buffer_id=%d slot=%zu",
+           id(), buffer->id(), slot);
+
+  // Avoid taking a transient reference, buffer is valid for the duration of
+  // this method call.
+  auto* consumer_buffer = static_cast<BufferConsumer*>(buffer.get());
+  std::unique_ptr<uint8_t[]> metadata(meta_size_ ? new uint8_t[meta_size_]
+                                                 : nullptr);
+  LocalHandle acquire_fence;
+
+  const int ret =
+      consumer_buffer->Acquire(&acquire_fence, metadata.get(), meta_size_);
+  if (ret < 0)
+    return ErrorStatus(-ret);
+  else
+    return {{buffer, std::move(metadata), std::move(acquire_fence), slot}};
 }
 
 Status<void> ConsumerQueue::OnBufferAllocated() {
+  ALOGD_IF(TRACE, "ConsumerQueue::OnBufferAllocated: queue_id=%d", id());
+
   auto status = ImportBuffers();
   if (!status) {
     ALOGE("ConsumerQueue::OnBufferAllocated: Failed to import buffers: %s",
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
index 8582bbf..0f75a5c 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
@@ -3,6 +3,7 @@
 #include <dvr/dvr_api.h>
 #include <inttypes.h>
 #include <log/log.h>
+#include <system/window.h>
 
 namespace android {
 namespace dvr {
@@ -10,7 +11,10 @@
 /* static */
 sp<BufferHubQueueProducer> BufferHubQueueProducer::Create() {
   sp<BufferHubQueueProducer> producer = new BufferHubQueueProducer;
-  producer->queue_ = ProducerQueue::Create<DvrNativeBufferMetadata>();
+  auto config = ProducerQueueConfigBuilder()
+                    .SetMetadata<DvrNativeBufferMetadata>()
+                    .Build();
+  producer->queue_ = ProducerQueue::Create(config, UsagePolicy{});
   return producer;
 }
 
@@ -127,9 +131,9 @@
 
 status_t BufferHubQueueProducer::dequeueBuffer(
     int* out_slot, sp<Fence>* out_fence, uint32_t width, uint32_t height,
-    PixelFormat format, uint32_t usage,
+    PixelFormat format, uint64_t usage,
     FrameEventHistoryDelta* /* out_timestamps */) {
-  ALOGD_IF(TRACE, "dequeueBuffer: w=%u, h=%u, format=%d, usage=%u", width,
+  ALOGD_IF(TRACE, "dequeueBuffer: w=%u, h=%u, format=%d, usage=%llu", width,
            height, format, usage);
 
   status_t ret;
@@ -158,6 +162,8 @@
   for (size_t retry = 0; retry < BufferHubQueue::kMaxQueueCapacity; retry++) {
     LocalHandle fence;
     auto buffer_status = queue_->Dequeue(dequeue_timeout_ms_, &slot, &fence);
+    if (!buffer_status)
+      return NO_MEMORY;
 
     buffer_producer = buffer_status.take();
     if (!buffer_producer)
@@ -526,7 +532,7 @@
 void BufferHubQueueProducer::allocateBuffers(uint32_t /* width */,
                                              uint32_t /* height */,
                                              PixelFormat /* format */,
-                                             uint32_t /* usage */) {
+                                             uint64_t /* usage */) {
   // TODO(jwcai) |allocateBuffers| aims to preallocate up to the maximum number
   // of buffers permitted by the current BufferQueue configuration (aka
   // |max_buffer_count_|).
@@ -606,14 +612,16 @@
                                                 uint32_t layer_count,
                                                 PixelFormat format,
                                                 uint64_t usage) {
-  size_t slot;
-
-  if (queue_->AllocateBuffer(width, height, layer_count, format, usage, &slot) <
-      0) {
-    ALOGE("Failed to allocate new buffer in BufferHub.");
+  auto status =
+      queue_->AllocateBuffer(width, height, layer_count, format, usage);
+  if (!status) {
+    ALOGE(
+        "BufferHubQueueProducer::AllocateBuffer: Failed to allocate buffer: %s",
+        status.GetErrorMessage().c_str());
     return NO_MEMORY;
   }
 
+  size_t slot = status.get();
   auto buffer_producer = queue_->GetBuffer(slot);
 
   LOG_ALWAYS_FATAL_IF(buffer_producer == nullptr,
@@ -625,11 +633,11 @@
 }
 
 status_t BufferHubQueueProducer::RemoveBuffer(size_t slot) {
-  int ret = queue_->DetachBuffer(slot);
-  if (ret < 0) {
-    ALOGE("BufferHubQueueProducer::RemoveBuffer failed through RPC, ret=%s",
-          strerror(-ret));
-    return ret;
+  auto status = queue_->RemoveBuffer(slot);
+  if (!status) {
+    ALOGE("BufferHubQueueProducer::RemoveBuffer: Failed to remove buffer: %s",
+          status.GetErrorMessage().c_str());
+    return INVALID_OPERATION;
   }
 
   // Reset in memory objects related the the buffer.
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
index ed67f79..d57c7af 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
@@ -5,6 +5,7 @@
 
 #include <pdx/client.h>
 #include <pdx/status.h>
+#include <private/dvr/bufferhub_rpc.h>
 #include <private/dvr/buffer_hub_client.h>
 #include <private/dvr/epoll_file_descriptor.h>
 #include <private/dvr/ring_buffer.h>
@@ -21,45 +22,46 @@
 // automatically re-requeued when released by the remote side.
 class BufferHubQueue : public pdx::Client {
  public:
-  using LocalHandle = pdx::LocalHandle;
-  using LocalChannelHandle = pdx::LocalChannelHandle;
-  template <typename T>
-  using Status = pdx::Status<T>;
+  using BufferAvailableCallback = std::function<void()>;
+  using BufferRemovedCallback =
+      std::function<void(const std::shared_ptr<BufferHubBuffer>&)>;
 
   virtual ~BufferHubQueue() {}
-  void Initialize();
 
-  // Create a new consumer queue that is attached to the producer. Returns
+  // Creates a new consumer queue that is attached to the producer. Returns
   // a new consumer queue client or nullptr on failure.
   std::unique_ptr<ConsumerQueue> CreateConsumerQueue();
 
-  // Create a new consumer queue that is attached to the producer. This queue
+  // Creates a new consumer queue that is attached to the producer. This queue
   // sets each of its imported consumer buffers to the ignored state to avoid
   // participation in lifecycle events.
   std::unique_ptr<ConsumerQueue> CreateSilentConsumerQueue();
 
-  // Return the default buffer width of this buffer queue.
-  size_t default_width() const { return default_width_; }
+  // Returns whether the buffer queue is in async mode.
+  bool is_async() const { return is_async_; }
 
-  // Return the default buffer height of this buffer queue.
-  size_t default_height() const { return default_height_; }
+  // Returns the default buffer width of this buffer queue.
+  uint32_t default_width() const { return default_width_; }
 
-  // Return the default buffer format of this buffer queue.
-  int32_t default_format() const { return default_format_; }
+  // Returns the default buffer height of this buffer queue.
+  uint32_t default_height() const { return default_height_; }
 
-  // Create a new consumer in handle form for immediate transport over RPC.
-  Status<LocalChannelHandle> CreateConsumerQueueHandle();
+  // Returns the default buffer format of this buffer queue.
+  uint32_t default_format() const { return default_format_; }
 
-  // Return the number of buffers avaiable for dequeue.
+  // Creates a new consumer in handle form for immediate transport over RPC.
+  pdx::Status<pdx::LocalChannelHandle> CreateConsumerQueueHandle();
+
+  // Returns the number of buffers avaiable for dequeue.
   size_t count() const { return available_buffers_.GetSize(); }
 
-  // Return the total number of buffers that the queue is tracking.
+  // Returns the total number of buffers that the queue is tracking.
   size_t capacity() const { return capacity_; }
 
-  // Return the size of metadata structure associated with this BufferBubQueue.
+  // Returns the size of metadata structure associated with this queue.
   size_t metadata_size() const { return meta_size_; }
 
-  // Return whether the buffer queue is alrady full.
+  // Returns whether the buffer queue is full.
   bool is_full() const { return available_buffers_.IsFull(); }
 
   explicit operator bool() const { return epoll_fd_.IsValid(); }
@@ -68,7 +70,7 @@
     return buffers_[slot];
   }
 
-  Status<int> GetEventMask(int events) {
+  pdx::Status<int> GetEventMask(int events) {
     if (auto* client_channel = GetChannel()) {
       return client_channel->GetEventMask(events);
     } else {
@@ -86,81 +88,100 @@
   // occurred.
   bool HandleQueueEvents() { return WaitForBuffers(0); }
 
-  // Enqueue a buffer marks buffer to be available (|Gain|'ed for producer
-  // and |Acquire|'ed for consumer. This is only used for internal bookkeeping.
-  void Enqueue(const std::shared_ptr<BufferHubBuffer>& buf, size_t slot);
+  // Set buffer event callbacks, which are std::function wrappers. The caller is
+  // responsible for ensuring the validity of these callbacks' callable targets.
+  void SetBufferAvailableCallback(BufferAvailableCallback callback);
+  void SetBufferRemovedCallback(BufferRemovedCallback callback);
 
-  // |BufferHubQueue| will keep track of at most this value of buffers.
+  // The queue tracks at most this many buffers.
   static constexpr size_t kMaxQueueCapacity =
       android::BufferQueueDefs::NUM_BUFFER_SLOTS;
 
-  // Special epoll data field indicating that the epoll event refers to the
-  // queue.
-  static constexpr int64_t kEpollQueueEventIndex = -1;
-
-  // When pass |kNoTimeout| to |Dequeue|, it will block indefinitely without a
-  // timeout.
   static constexpr int kNoTimeOut = -1;
 
   int id() const { return id_; }
   bool hung_up() const { return hung_up_; }
 
  protected:
-  BufferHubQueue(LocalChannelHandle channel);
+  BufferHubQueue(pdx::LocalChannelHandle channel);
   BufferHubQueue(const std::string& endpoint_path);
 
   // Imports the queue parameters by querying BufferHub for the parameters for
   // this channel.
-  Status<void> ImportQueue();
+  pdx::Status<void> ImportQueue();
 
   // Sets up the queue with the given parameters.
-  void SetupQueue(size_t meta_size_bytes_, int id);
+  void SetupQueue(const QueueInfo& queue_info);
 
-  // Called by ProducerQueue::AddBuffer and ConsumerQueue::AddBuffer only. to
-  // register a buffer for epoll and internal bookkeeping.
-  int AddBuffer(const std::shared_ptr<BufferHubBuffer>& buf, size_t slot);
+  // Register a buffer for management by the queue. Used by subclasses to add a
+  // buffer to internal bookkeeping.
+  pdx::Status<void> AddBuffer(const std::shared_ptr<BufferHubBuffer>& buffer,
+                              size_t slot);
 
-  // Called by ProducerQueue::DetachBuffer and ConsumerQueue::DetachBuffer only.
+  // Called by ProducerQueue::RemoveBuffer and ConsumerQueue::RemoveBuffer only
   // to deregister a buffer for epoll and internal bookkeeping.
-  virtual int DetachBuffer(size_t slot);
+  virtual pdx::Status<void> RemoveBuffer(size_t slot);
 
   // Dequeue a buffer from the free queue, blocking until one is available. The
   // timeout argument specifies the number of milliseconds that |Dequeue()| will
-  // block. Specifying a timeout of -1 causes |Dequeue()| to block indefinitely,
-  // while specifying a timeout equal to zero cause |Dequeue()| to return
+  // block. Specifying a timeout of -1 causes Dequeue() to block indefinitely,
+  // while specifying a timeout equal to zero cause Dequeue() to return
   // immediately, even if no buffers are available.
-  pdx::Status<std::shared_ptr<BufferHubBuffer>> Dequeue(int timeout,
-                                                        size_t* slot,
-                                                        void* meta,
-                                                        LocalHandle* fence);
+  pdx::Status<std::shared_ptr<BufferHubBuffer>> Dequeue(
+      int timeout, size_t* slot, void* meta, pdx::LocalHandle* fence);
 
-  // Wait for buffers to be released and re-add them to the queue.
+  // Waits for buffers to become available and adds them to the available queue.
   bool WaitForBuffers(int timeout);
-  void HandleBufferEvent(size_t slot, int poll_events);
-  void HandleQueueEvent(int poll_events);
 
-  virtual int OnBufferReady(const std::shared_ptr<BufferHubBuffer>& buf,
-                            LocalHandle* fence) = 0;
+  pdx::Status<void> HandleBufferEvent(size_t slot, int event_fd,
+                                      int poll_events);
+  pdx::Status<void> HandleQueueEvent(int poll_events);
+
+  // Entry in the ring buffer of available buffers that stores related
+  // per-buffer data.
+  struct Entry {
+    Entry() : slot(0) {}
+    Entry(const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot)
+        : buffer(buffer), slot(slot) {}
+    Entry(const std::shared_ptr<BufferHubBuffer>& buffer,
+          std::unique_ptr<uint8_t[]> metadata, pdx::LocalHandle fence,
+          size_t slot)
+        : buffer(buffer),
+          metadata(std::move(metadata)),
+          fence(std::move(fence)),
+          slot(slot) {}
+    Entry(Entry&&) = default;
+    Entry& operator=(Entry&&) = default;
+
+    std::shared_ptr<BufferHubBuffer> buffer;
+    std::unique_ptr<uint8_t[]> metadata;
+    pdx::LocalHandle fence;
+    size_t slot;
+  };
+
+  // Enqueues a buffer to the available list (Gained for producer or Acquireed
+  // for consumer).
+  pdx::Status<void> Enqueue(Entry entry);
+
+  virtual pdx::Status<Entry> OnBufferReady(
+      const std::shared_ptr<BufferHubBuffer>& buf, size_t slot) = 0;
 
   // Called when a buffer is allocated remotely.
-  virtual Status<void> OnBufferAllocated() { return {}; }
+  virtual pdx::Status<void> OnBufferAllocated() { return {}; }
 
-  // Data members to handle arbitrary metadata passed through BufferHub. It is
-  // fair to enforce that all buffers in the same queue share the same metadata
-  // type. |meta_size_| is used to store the size of metadata on queue creation;
-  // and |meta_buffer_tmp_| is allocated and resized to |meta_size_| on queue
-  // creation to be later used as temporary space so that we can avoid
-  // additional dynamic memory allocation in each |Enqueue| and |Dequeue| call.
-  size_t meta_size_;
-
-  // Here we intentionally choose |unique_ptr<uint8_t[]>| over vector<uint8_t>
-  // to disallow dynamic resizing for stability reasons.
-  std::unique_ptr<uint8_t[]> meta_buffer_tmp_;
+  // Size of the metadata that buffers in this queue cary.
+  size_t meta_size_{0};
 
  private:
+  void Initialize();
+
+  // Special epoll data field indicating that the epoll event refers to the
+  // queue.
+  static constexpr int64_t kEpollQueueEventIndex = -1;
+
   static constexpr size_t kMaxEvents = 128;
 
-  // The |u64| data field of an epoll event is interpreted as int64_t:
+  // The u64 data field of an epoll event is interpreted as int64_t:
   // When |index| >= 0 and |index| < kMaxQueueCapacity it refers to a specific
   // element of |buffers_| as a direct index;
   static bool is_buffer_event_index(int64_t index) {
@@ -168,102 +189,40 @@
            index < static_cast<int64_t>(BufferHubQueue::kMaxQueueCapacity);
   }
 
-  // When |index| == kEpollQueueEventIndex, it refers to the queue itself.
+  // When |index| == kEpollQueueEventIndex it refers to the queue itself.
   static bool is_queue_event_index(int64_t index) {
     return index == BufferHubQueue::kEpollQueueEventIndex;
   }
 
-  struct BufferInfo {
-    // A logical slot number that is assigned to a buffer at allocation time.
-    // The slot number remains unchanged during the entire life cycle of the
-    // buffer and should not be confused with the enqueue and dequeue order.
-    size_t slot;
+  // Whether the buffer queue is operating in Async mode.
+  // From GVR's perspective of view, this means a buffer can be acquired
+  // asynchronously by the compositor.
+  // From Android Surface's perspective of view, this is equivalent to
+  // IGraphicBufferProducer's async mode. When in async mode, a producer
+  // will never block even if consumer is running slow.
+  bool is_async_{false};
 
-    // A BufferHubBuffer client.
-    std::shared_ptr<BufferHubBuffer> buffer;
-
-    // Metadata associated with the buffer.
-    std::unique_ptr<uint8_t[]> metadata;
-
-    BufferInfo() : BufferInfo(-1, 0) {}
-
-    BufferInfo(size_t slot, size_t metadata_size)
-        : slot(slot),
-          buffer(nullptr),
-          metadata(metadata_size ? new uint8_t[metadata_size] : nullptr) {}
-
-    BufferInfo(BufferInfo&& other)
-        : slot(other.slot),
-          buffer(std::move(other.buffer)),
-          metadata(std::move(other.metadata)) {}
-
-    BufferInfo& operator=(BufferInfo&& other) {
-      slot = other.slot;
-      buffer = std::move(other.buffer);
-      metadata = std::move(other.metadata);
-      return *this;
-    }
-
-   private:
-    BufferInfo(const BufferInfo&) = delete;
-    void operator=(BufferInfo&) = delete;
-  };
-
-  // Default buffer width that can be set to override the buffer width when a
-  // width and height of 0 are specified in AllocateBuffer.
+  // Default buffer width that is set during ProducerQueue's creation.
   size_t default_width_{1};
 
-  // Default buffer height that can be set to override the buffer height when a
-  // width and height of 0 are specified in AllocateBuffer.
+  // Default buffer height that is set during ProducerQueue's creation.
   size_t default_height_{1};
 
-  // Default buffer format that can be set to override the buffer format when it
-  // isn't specified in AllocateBuffer.
-  int32_t default_format_{PIXEL_FORMAT_RGBA_8888};
+  // Default buffer format that is set during ProducerQueue's creation.
+  int32_t default_format_{1};  // PIXEL_FORMAT_RGBA_8888
 
-  // Buffer queue:
-  // |buffers_| tracks all |BufferHubBuffer|s created by this |BufferHubQueue|.
-  std::vector<std::shared_ptr<BufferHubBuffer>> buffers_;
+  // Tracks the buffers belonging to this queue. Buffers are stored according to
+  // "slot" in this vector. Each slot is a logical id of the buffer within this
+  // queue regardless of its queue position or presence in the ring buffer.
+  std::vector<std::shared_ptr<BufferHubBuffer>> buffers_{kMaxQueueCapacity};
 
-  // |epollhup_pending_| tracks whether a slot of |buffers_| get detached before
-  // its corresponding EPOLLHUP event got handled. This could happen as the
-  // following sequence:
-  // 1. Producer queue's client side allocates a new buffer (at slot 1).
-  // 2. Producer queue's client side replaces an existing buffer (at slot 0).
-  //    This is implemented by first detaching the buffer and then allocating a
-  //    new buffer.
-  // 3. During the same epoll_wait, Consumer queue's client side gets EPOLLIN
-  //    event on the queue which indicates a new buffer is available and the
-  //    EPOLLHUP event for slot 0. Consumer handles these two events in order.
-  // 4. Consumer client calls BufferHubRPC::ConsumerQueueImportBuffers and both
-  //    slot 0 and (the new) slot 1 buffer will be imported. During the import
-  //    of the buffer at slot 1, consumer client detaches the old buffer so that
-  //    the new buffer can be registered. At the same time
-  //    |epollhup_pending_[slot]| is marked to indicate that buffer at this slot
-  //    was detached prior to EPOLLHUP event.
-  // 5. Consumer client continues to handle the EPOLLHUP. Since
-  //    |epollhup_pending_[slot]| is marked as true, it can safely ignore the
-  //    event without detaching the newly allocated buffer at slot 1.
-  //
-  // In normal situations where the previously described sequence doesn't
-  // happen, an EPOLLHUP event should trigger a regular buffer detach.
-  std::vector<bool> epollhup_pending_;
+  // Buffers and related data that are available for dequeue.
+  RingBuffer<Entry> available_buffers_{kMaxQueueCapacity};
 
-  // |available_buffers_| uses |dvr::RingBuffer| to implementation queue
-  // sematics. When |Dequeue|, we pop the front element from
-  // |available_buffers_|, and  that buffer's reference count will decrease by
-  // one, while another reference in |buffers_| keeps the last reference to
-  // prevent the buffer from being deleted.
-  RingBuffer<BufferInfo> available_buffers_;
+  // Keeps track with how many buffers have been added into the queue.
+  size_t capacity_{0};
 
-  // Fences (acquire fence for consumer and release fence for consumer) , one
-  // for each buffer slot.
-  std::vector<LocalHandle> fences_;
-
-  // Keep track with how many buffers have been added into the queue.
-  size_t capacity_;
-
-  // Epoll fd used to wait for BufferHub events.
+  // Epoll fd used to manage buffer events.
   EpollFileDescriptor epoll_fd_;
 
   // Flag indicating that the other side hung up. For ProducerQueues this
@@ -273,7 +232,11 @@
   bool hung_up_{false};
 
   // Global id for the queue that is consistent across processes.
-  int id_;
+  int id_{-1};
+
+  // Buffer event callbacks
+  BufferAvailableCallback on_buffer_available_;
+  BufferRemovedCallback on_buffer_removed_;
 
   BufferHubQueue(const BufferHubQueue&) = delete;
   void operator=(BufferHubQueue&) = delete;
@@ -281,14 +244,6 @@
 
 class ProducerQueue : public pdx::ClientBase<ProducerQueue, BufferHubQueue> {
  public:
-  template <typename Meta>
-  static std::unique_ptr<ProducerQueue> Create() {
-    return BASE::Create(sizeof(Meta));
-  }
-  static std::unique_ptr<ProducerQueue> Create(size_t meta_size_bytes) {
-    return BASE::Create(meta_size_bytes);
-  }
-
   // Usage bits in |usage_set_mask| will be automatically masked on. Usage bits
   // in |usage_clear_mask| will be automatically masked off. Note that
   // |usage_set_mask| and |usage_clear_mask| may conflict with each other, but
@@ -300,59 +255,59 @@
   // this will be rejected. Note that |usage_deny_set_mask| and
   // |usage_deny_clear_mask| shall not conflict with each other. Such
   // configuration will be treated as invalid input on creation.
-  template <typename Meta>
-  static std::unique_ptr<ProducerQueue> Create(uint32_t usage_set_mask,
-                                               uint32_t usage_clear_mask,
-                                               uint32_t usage_deny_set_mask,
-                                               uint32_t usage_deny_clear_mask) {
-    return BASE::Create(sizeof(Meta), usage_set_mask, usage_clear_mask,
-                        usage_deny_set_mask, usage_deny_clear_mask);
-  }
-  static std::unique_ptr<ProducerQueue> Create(size_t meta_size_bytes,
-                                               uint32_t usage_set_mask,
-                                               uint32_t usage_clear_mask,
-                                               uint32_t usage_deny_set_mask,
-                                               uint32_t usage_deny_clear_mask) {
-    return BASE::Create(meta_size_bytes, usage_set_mask, usage_clear_mask,
-                        usage_deny_set_mask, usage_deny_clear_mask);
+  static std::unique_ptr<ProducerQueue> Create(
+      const ProducerQueueConfig& config, const UsagePolicy& usage) {
+    return BASE::Create(config, usage);
   }
 
-  // Import a |ProducerQueue| from a channel handle.
-  static std::unique_ptr<ProducerQueue> Import(LocalChannelHandle handle) {
+  // Import a ProducerQueue from a channel handle.
+  static std::unique_ptr<ProducerQueue> Import(pdx::LocalChannelHandle handle) {
     return BASE::Create(std::move(handle));
   }
 
   // Get a buffer producer. Note that the method doesn't check whether the
   // buffer slot has a valid buffer that has been allocated already. When no
-  // buffer has been imported before it returns |nullptr|; otherwise it returns
-  // a shared pointer to a |BufferProducer|.
+  // buffer has been imported before it returns nullptr; otherwise it returns
+  // a shared pointer to a BufferProducer.
   std::shared_ptr<BufferProducer> GetBuffer(size_t slot) const {
     return std::static_pointer_cast<BufferProducer>(
         BufferHubQueue::GetBuffer(slot));
   }
 
+  // Batch allocate buffers. Once allocated, producer buffers are automatically
+  // enqueue'd into the ProducerQueue and available to use (i.e. in GAINED
+  // state). Upon success, returns a list of slots for each buffer allocated.
+  pdx::Status<std::vector<size_t>> AllocateBuffers(
+      uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
+      uint64_t usage, size_t buffer_count);
+
   // Allocate producer buffer to populate the queue. Once allocated, a producer
   // buffer is automatically enqueue'd into the ProducerQueue and available to
-  // use (i.e. in |Gain|'ed mode).
-  // Returns Zero on success and negative error code when buffer allocation
-  // fails.
-  int AllocateBuffer(uint32_t width, uint32_t height, uint32_t layer_count,
-                     uint32_t format, uint64_t usage, size_t* out_slot);
+  // use (i.e. in GAINED state). Upon success, returns the slot number for the
+  // buffer allocated.
+  pdx::Status<size_t> AllocateBuffer(uint32_t width, uint32_t height,
+                                     uint32_t layer_count, uint32_t format,
+                                     uint64_t usage);
 
   // Add a producer buffer to populate the queue. Once added, a producer buffer
-  // is available to use (i.e. in |Gain|'ed mode).
-  int AddBuffer(const std::shared_ptr<BufferProducer>& buf, size_t slot);
+  // is available to use (i.e. in GAINED state).
+  pdx::Status<void> AddBuffer(const std::shared_ptr<BufferProducer>& buffer,
+                              size_t slot);
 
-  // Detach producer buffer from the queue.
-  // Returns Zero on success and negative error code when buffer detach
-  // fails.
-  int DetachBuffer(size_t slot) override;
+  // Remove producer buffer from the queue.
+  pdx::Status<void> RemoveBuffer(size_t slot) override;
 
   // Dequeue a producer buffer to write. The returned buffer in |Gain|'ed mode,
   // and caller should call Post() once it's done writing to release the buffer
   // to the consumer side.
   pdx::Status<std::shared_ptr<BufferProducer>> Dequeue(
-      int timeout, size_t* slot, LocalHandle* release_fence);
+      int timeout, size_t* slot, pdx::LocalHandle* release_fence);
+
+  // Enqueues a producer buffer in the queue.
+  pdx::Status<void> Enqueue(const std::shared_ptr<BufferProducer>& buffer,
+                            size_t slot) {
+    return BufferHubQueue::Enqueue({buffer, slot});
+  }
 
  private:
   friend BASE;
@@ -360,29 +315,13 @@
   // Constructors are automatically exposed through ProducerQueue::Create(...)
   // static template methods inherited from ClientBase, which take the same
   // arguments as the constructors.
-  explicit ProducerQueue(size_t meta_size);
-  ProducerQueue(LocalChannelHandle handle);
-  ProducerQueue(size_t meta_size, uint64_t usage_set_mask,
-                uint64_t usage_clear_mask, uint64_t usage_deny_set_mask,
-                uint64_t usage_deny_clear_mask);
+  explicit ProducerQueue(pdx::LocalChannelHandle handle);
+  ProducerQueue(const ProducerQueueConfig& config, const UsagePolicy& usage);
 
-  int OnBufferReady(const std::shared_ptr<BufferHubBuffer>& buf,
-                    LocalHandle* release_fence) override;
+  pdx::Status<Entry> OnBufferReady(
+      const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) override;
 };
 
-// Explicit specializations of ProducerQueue::Create for void metadata type.
-template <>
-inline std::unique_ptr<ProducerQueue> ProducerQueue::Create<void>() {
-  return ProducerQueue::Create(0);
-}
-template <>
-inline std::unique_ptr<ProducerQueue> ProducerQueue::Create<void>(
-    uint32_t usage_set_mask, uint32_t usage_clear_mask,
-    uint32_t usage_deny_set_mask, uint32_t usage_deny_clear_mask) {
-  return ProducerQueue::Create(0, usage_set_mask, usage_clear_mask,
-                               usage_deny_set_mask, usage_deny_clear_mask);
-}
-
 class ConsumerQueue : public BufferHubQueue {
  public:
   // Get a buffer consumer. Note that the method doesn't check whether the
@@ -399,7 +338,7 @@
   // used to avoid participation in the buffer lifecycle by a consumer queue
   // that is only used to spawn other consumer queues, such as in an
   // intermediate service.
-  static std::unique_ptr<ConsumerQueue> Import(LocalChannelHandle handle,
+  static std::unique_ptr<ConsumerQueue> Import(pdx::LocalChannelHandle handle,
                                                bool ignore_on_import = false) {
     return std::unique_ptr<ConsumerQueue>(
         new ConsumerQueue(std::move(handle), ignore_on_import));
@@ -407,7 +346,7 @@
 
   // Import newly created buffers from the service side.
   // Returns number of buffers successfully imported or an error.
-  Status<size_t> ImportBuffers();
+  pdx::Status<size_t> ImportBuffers();
 
   // Dequeue a consumer buffer to read. The returned buffer in |Acquired|'ed
   // mode, and caller should call Releasse() once it's done writing to release
@@ -417,33 +356,34 @@
   // when the buffer is orignally created.
   template <typename Meta>
   pdx::Status<std::shared_ptr<BufferConsumer>> Dequeue(
-      int timeout, size_t* slot, Meta* meta, LocalHandle* acquire_fence) {
+      int timeout, size_t* slot, Meta* meta, pdx::LocalHandle* acquire_fence) {
     return Dequeue(timeout, slot, meta, sizeof(*meta), acquire_fence);
   }
   pdx::Status<std::shared_ptr<BufferConsumer>> Dequeue(
-      int timeout, size_t* slot, LocalHandle* acquire_fence) {
+      int timeout, size_t* slot, pdx::LocalHandle* acquire_fence) {
     return Dequeue(timeout, slot, nullptr, 0, acquire_fence);
   }
 
   pdx::Status<std::shared_ptr<BufferConsumer>> Dequeue(
       int timeout, size_t* slot, void* meta, size_t meta_size,
-      LocalHandle* acquire_fence);
+      pdx::LocalHandle* acquire_fence);
 
  private:
   friend BufferHubQueue;
 
-  ConsumerQueue(LocalChannelHandle handle, bool ignore_on_import = false);
+  ConsumerQueue(pdx::LocalChannelHandle handle, bool ignore_on_import = false);
 
   // Add a consumer buffer to populate the queue. Once added, a consumer buffer
   // is NOT available to use until the producer side |Post| it. |WaitForBuffers|
   // will catch the |Post| and |Acquire| the buffer to make it available for
   // consumer.
-  int AddBuffer(const std::shared_ptr<BufferConsumer>& buf, size_t slot);
+  pdx::Status<void> AddBuffer(const std::shared_ptr<BufferConsumer>& buffer,
+                              size_t slot);
 
-  int OnBufferReady(const std::shared_ptr<BufferHubBuffer>& buf,
-                    LocalHandle* acquire_fence) override;
+  pdx::Status<Entry> OnBufferReady(
+      const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) override;
 
-  Status<void> OnBufferAllocated() override;
+  pdx::Status<void> OnBufferAllocated() override;
 
   // Flag indicating that imported (consumer) buffers should be ignored when
   // imported to avoid participating in the buffer ownership flow.
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h
index 7890176..638a56c 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h
@@ -42,7 +42,7 @@
 
   // See |IGraphicBufferProducer::dequeueBuffer|
   status_t dequeueBuffer(int* out_slot, sp<Fence>* out_fence, uint32_t width,
-                         uint32_t height, PixelFormat format, uint32_t usage,
+                         uint32_t height, PixelFormat format, uint64_t usage,
                          FrameEventHistoryDelta* outTimestamps) override;
 
   // See |IGraphicBufferProducer::detachBuffer|
@@ -80,7 +80,7 @@
 
   // See |IGraphicBufferProducer::allocateBuffers|
   void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format,
-                       uint32_t usage) override;
+                       uint64_t usage) override;
 
   // See |IGraphicBufferProducer::allowAllocation|
   status_t allowAllocation(bool allow) override;
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
index fe0b12a..e0a4052 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
@@ -6,6 +6,9 @@
 
 #include <vector>
 
+// Enable/disable debug logging.
+#define TRACE 0
+
 namespace android {
 namespace dvr {
 
@@ -13,22 +16,17 @@
 
 namespace {
 
-constexpr int kBufferWidth = 100;
-constexpr int kBufferHeight = 1;
-constexpr int kBufferLayerCount = 1;
-constexpr int kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
-constexpr int kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY;
+constexpr uint32_t kBufferWidth = 100;
+constexpr uint32_t kBufferHeight = 1;
+constexpr uint32_t kBufferLayerCount = 1;
+constexpr uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
+constexpr uint64_t kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY;
 
 class BufferHubQueueTest : public ::testing::Test {
  public:
-  template <typename Meta>
-  bool CreateProducerQueue(uint64_t usage_set_mask = 0,
-                           uint64_t usage_clear_mask = 0,
-                           uint64_t usage_deny_set_mask = 0,
-                           uint64_t usage_deny_clear_mask = 0) {
-    producer_queue_ =
-        ProducerQueue::Create<Meta>(usage_set_mask, usage_clear_mask,
-                                    usage_deny_set_mask, usage_deny_clear_mask);
+  bool CreateProducerQueue(const ProducerQueueConfig& config,
+                           const UsagePolicy& usage) {
+    producer_queue_ = ProducerQueue::Create(config, usage);
     return producer_queue_ != nullptr;
   }
 
@@ -41,26 +39,25 @@
     }
   }
 
-  template <typename Meta>
-  bool CreateQueues(int usage_set_mask = 0, int usage_clear_mask = 0,
-                    int usage_deny_set_mask = 0,
-                    int usage_deny_clear_mask = 0) {
-    return CreateProducerQueue<Meta>(usage_set_mask, usage_clear_mask,
-                                     usage_deny_set_mask,
-                                     usage_deny_clear_mask) &&
-           CreateConsumerQueue();
+  bool CreateQueues(const ProducerQueueConfig& config,
+                    const UsagePolicy& usage) {
+    return CreateProducerQueue(config, usage) && CreateConsumerQueue();
   }
 
-  void AllocateBuffer() {
+  void AllocateBuffer(size_t* slot_out = nullptr) {
     // Create producer buffer.
-    size_t slot;
-    int ret = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
-                                              kBufferLayerCount, kBufferFormat,
-                                              kBufferUsage, &slot);
-    ASSERT_EQ(ret, 0);
+    auto status = producer_queue_->AllocateBuffer(
+        kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
+        kBufferUsage);
+
+    ASSERT_TRUE(status.ok());
+    size_t slot = status.take();
+    if (slot_out)
+      *slot_out = slot;
   }
 
  protected:
+  ProducerQueueConfigBuilder config_builder_;
   std::unique_ptr<ProducerQueue> producer_queue_;
   std::unique_ptr<ConsumerQueue> consumer_queue_;
 };
@@ -68,7 +65,8 @@
 TEST_F(BufferHubQueueTest, TestDequeue) {
   const size_t nb_dequeue_times = 16;
 
-  ASSERT_TRUE(CreateQueues<size_t>());
+  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<size_t>().Build(),
+                           UsagePolicy{}));
 
   // Allocate only one buffer.
   AllocateBuffer();
@@ -94,13 +92,14 @@
 }
 
 TEST_F(BufferHubQueueTest, TestProducerConsumer) {
-  const size_t nb_buffer = 16;
+  const size_t kBufferCount = 16;
   size_t slot;
   uint64_t seq;
 
-  ASSERT_TRUE(CreateQueues<uint64_t>());
+  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<uint64_t>().Build(),
+                           UsagePolicy{}));
 
-  for (size_t i = 0; i < nb_buffer; i++) {
+  for (size_t i = 0; i < kBufferCount; i++) {
     AllocateBuffer();
 
     // Producer queue has all the available buffers on initialize.
@@ -120,14 +119,23 @@
     ASSERT_EQ(consumer_queue_->capacity(), i + 1);
   }
 
-  for (size_t i = 0; i < nb_buffer; i++) {
+  // Use /dev/zero as a stand-in for a fence. As long as BufferHub does not need
+  // to merge fences, which only happens when multiple consumers release the
+  // same buffer with release fences, the file object should simply pass
+  // through.
+  LocalHandle post_fence("/dev/zero", O_RDONLY);
+  struct stat post_fence_stat;
+  ASSERT_EQ(0, fstat(post_fence.Get(), &post_fence_stat));
+
+  for (size_t i = 0; i < kBufferCount; i++) {
     LocalHandle fence;
-    // First time, there is no buffer available to dequeue.
+
+    // First time there is no buffer available to dequeue.
     auto consumer_status = consumer_queue_->Dequeue(0, &slot, &seq, &fence);
     ASSERT_FALSE(consumer_status.ok());
     ASSERT_EQ(ETIMEDOUT, consumer_status.error());
 
-    // Make sure Producer buffer is Post()'ed so that it's ready to Accquire
+    // Make sure Producer buffer is POSTED so that it's ready to Accquire
     // in the consumer's Dequeue() function.
     auto producer_status = producer_queue_->Dequeue(0, &slot, &fence);
     ASSERT_TRUE(producer_status.ok());
@@ -135,20 +143,137 @@
     ASSERT_NE(nullptr, producer);
 
     uint64_t seq_in = static_cast<uint64_t>(i);
-    ASSERT_EQ(producer->Post({}, &seq_in, sizeof(seq_in)), 0);
+    ASSERT_EQ(producer->Post(post_fence, &seq_in, sizeof(seq_in)), 0);
 
-    // Second time, the just |Post()|'ed buffer should be dequeued.
+    // Second time the just the POSTED buffer should be dequeued.
     uint64_t seq_out = 0;
     consumer_status = consumer_queue_->Dequeue(0, &slot, &seq_out, &fence);
     ASSERT_TRUE(consumer_status.ok());
+    EXPECT_TRUE(fence.IsValid());
+
+    struct stat acquire_fence_stat;
+    ASSERT_EQ(0, fstat(fence.Get(), &acquire_fence_stat));
+
+    // The file descriptors should refer to the same file object. Testing the
+    // device id and inode is a proxy for testing that the fds refer to the same
+    // file object.
+    EXPECT_NE(post_fence.Get(), fence.Get());
+    EXPECT_EQ(post_fence_stat.st_dev, acquire_fence_stat.st_dev);
+    EXPECT_EQ(post_fence_stat.st_ino, acquire_fence_stat.st_ino);
+
     auto consumer = consumer_status.take();
     ASSERT_NE(nullptr, consumer);
     ASSERT_EQ(seq_in, seq_out);
   }
 }
 
+TEST_F(BufferHubQueueTest, TestRemoveBuffer) {
+  ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{}));
+
+  // Allocate buffers.
+  const size_t kBufferCount = 4u;
+  for (size_t i = 0; i < kBufferCount; i++) {
+    AllocateBuffer();
+  }
+  ASSERT_EQ(kBufferCount, producer_queue_->count());
+  ASSERT_EQ(kBufferCount, producer_queue_->capacity());
+
+  consumer_queue_ = producer_queue_->CreateConsumerQueue();
+  ASSERT_NE(nullptr, consumer_queue_);
+
+  // Check that buffers are correctly imported on construction.
+  EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
+  EXPECT_EQ(0u, consumer_queue_->count());
+
+  // Dequeue all the buffers and keep track of them in an array. This prevents
+  // the producer queue ring buffer ref counts from interfering with the tests.
+  struct Entry {
+    std::shared_ptr<BufferProducer> buffer;
+    LocalHandle fence;
+    size_t slot;
+  };
+  std::array<Entry, kBufferCount> buffers;
+
+  for (size_t i = 0; i < kBufferCount; i++) {
+    Entry* entry = &buffers[i];
+    auto producer_status =
+        producer_queue_->Dequeue(0, &entry->slot, &entry->fence);
+    ASSERT_TRUE(producer_status.ok());
+    entry->buffer = producer_status.take();
+    ASSERT_NE(nullptr, entry->buffer);
+    EXPECT_EQ(i, entry->slot);
+  }
+
+  // Remove a buffer and make sure both queues reflect the change.
+  ASSERT_TRUE(producer_queue_->RemoveBuffer(buffers[0].slot));
+  EXPECT_EQ(kBufferCount - 1, producer_queue_->capacity());
+
+  // As long as the removed buffer is still alive the consumer queue won't know
+  // its gone.
+  EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
+  EXPECT_FALSE(consumer_queue_->HandleQueueEvents());
+  EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
+
+  // Release the removed buffer.
+  buffers[0].buffer = nullptr;
+
+  // Now the consumer queue should know it's gone.
+  EXPECT_FALSE(consumer_queue_->HandleQueueEvents());
+  EXPECT_EQ(kBufferCount - 1, consumer_queue_->capacity());
+
+  // Allocate a new buffer. This should take the first empty slot.
+  size_t slot;
+  AllocateBuffer(&slot);
+  ALOGE_IF(TRACE, "ALLOCATE %zu", slot);
+  EXPECT_EQ(buffers[0].slot, slot);
+  EXPECT_EQ(kBufferCount, producer_queue_->capacity());
+
+  // The consumer queue should pick up the new buffer.
+  EXPECT_EQ(kBufferCount - 1, consumer_queue_->capacity());
+  EXPECT_FALSE(consumer_queue_->HandleQueueEvents());
+  EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
+
+  // Remove and allocate a buffer.
+  ASSERT_TRUE(producer_queue_->RemoveBuffer(buffers[1].slot));
+  EXPECT_EQ(kBufferCount - 1, producer_queue_->capacity());
+  buffers[1].buffer = nullptr;
+
+  AllocateBuffer(&slot);
+  ALOGE_IF(TRACE, "ALLOCATE %zu", slot);
+  EXPECT_EQ(buffers[1].slot, slot);
+  EXPECT_EQ(kBufferCount, producer_queue_->capacity());
+
+  // The consumer queue should pick up the new buffer but the count shouldn't
+  // change.
+  EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
+  EXPECT_FALSE(consumer_queue_->HandleQueueEvents());
+  EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
+
+  // Remove and allocate a buffer, but don't free the buffer right away.
+  ASSERT_TRUE(producer_queue_->RemoveBuffer(buffers[2].slot));
+  EXPECT_EQ(kBufferCount - 1, producer_queue_->capacity());
+
+  AllocateBuffer(&slot);
+  ALOGE_IF(TRACE, "ALLOCATE %zu", slot);
+  EXPECT_EQ(buffers[2].slot, slot);
+  EXPECT_EQ(kBufferCount, producer_queue_->capacity());
+
+  EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
+  EXPECT_FALSE(consumer_queue_->HandleQueueEvents());
+  EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
+
+  // Release the producer buffer to trigger a POLLHUP event for an already
+  // removed buffer.
+  buffers[2].buffer = nullptr;
+  EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
+  EXPECT_FALSE(consumer_queue_->HandleQueueEvents());
+  EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
+}
+
 TEST_F(BufferHubQueueTest, TestMultipleConsumers) {
-  ASSERT_TRUE(CreateProducerQueue<void>());
+  // ProducerConfigureBuilder doesn't set Metadata{size}, which means there
+  // is no metadata associated with this BufferQueue's buffer.
+  ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{}));
 
   // Allocate buffers.
   const size_t kBufferCount = 4u;
@@ -226,7 +351,9 @@
 };
 
 TEST_F(BufferHubQueueTest, TestMetadata) {
-  ASSERT_TRUE(CreateQueues<TestMetadata>());
+  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<TestMetadata>().Build(),
+                           UsagePolicy{}));
+
   AllocateBuffer();
 
   std::vector<TestMetadata> ms = {
@@ -252,7 +379,9 @@
 }
 
 TEST_F(BufferHubQueueTest, TestMetadataMismatch) {
-  ASSERT_TRUE(CreateQueues<int64_t>());
+  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(),
+                           UsagePolicy{}));
+
   AllocateBuffer();
 
   int64_t mi = 3;
@@ -271,7 +400,8 @@
 }
 
 TEST_F(BufferHubQueueTest, TestEnqueue) {
-  ASSERT_TRUE(CreateQueues<int64_t>());
+  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(),
+                           UsagePolicy{}));
   AllocateBuffer();
 
   size_t slot;
@@ -288,7 +418,8 @@
 }
 
 TEST_F(BufferHubQueueTest, TestAllocateBuffer) {
-  ASSERT_TRUE(CreateQueues<int64_t>());
+  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(),
+                           UsagePolicy{}));
 
   size_t s1;
   AllocateBuffer();
@@ -343,16 +474,17 @@
 
 TEST_F(BufferHubQueueTest, TestUsageSetMask) {
   const uint32_t set_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
-  ASSERT_TRUE(CreateQueues<int64_t>(set_mask, 0, 0, 0));
+  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(),
+                           UsagePolicy{set_mask, 0, 0, 0}));
 
   // When allocation, leave out |set_mask| from usage bits on purpose.
-  size_t slot;
-  int ret = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
-                                            kBufferFormat, kBufferLayerCount,
-                                            kBufferUsage & ~set_mask, &slot);
-  ASSERT_EQ(0, ret);
+  auto status = producer_queue_->AllocateBuffer(
+      kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
+      kBufferUsage & ~set_mask);
+  ASSERT_TRUE(status.ok());
 
   LocalHandle fence;
+  size_t slot;
   auto p1_status = producer_queue_->Dequeue(0, &slot, &fence);
   ASSERT_TRUE(p1_status.ok());
   auto p1 = p1_status.take();
@@ -361,16 +493,17 @@
 
 TEST_F(BufferHubQueueTest, TestUsageClearMask) {
   const uint32_t clear_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
-  ASSERT_TRUE(CreateQueues<int64_t>(0, clear_mask, 0, 0));
+  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(),
+                           UsagePolicy{0, clear_mask, 0, 0}));
 
   // When allocation, add |clear_mask| into usage bits on purpose.
-  size_t slot;
-  int ret = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
-                                            kBufferLayerCount, kBufferFormat,
-                                            kBufferUsage | clear_mask, &slot);
-  ASSERT_EQ(0, ret);
+  auto status = producer_queue_->AllocateBuffer(
+      kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
+      kBufferUsage | clear_mask);
+  ASSERT_TRUE(status.ok());
 
   LocalHandle fence;
+  size_t slot;
   auto p1_status = producer_queue_->Dequeue(0, &slot, &fence);
   ASSERT_TRUE(p1_status.ok());
   auto p1 = p1_status.take();
@@ -379,40 +512,62 @@
 
 TEST_F(BufferHubQueueTest, TestUsageDenySetMask) {
   const uint32_t deny_set_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
-  ASSERT_TRUE(CreateQueues<int64_t>(0, 0, deny_set_mask, 0));
+  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(),
+                           UsagePolicy{0, 0, deny_set_mask, 0}));
 
   // Now that |deny_set_mask| is illegal, allocation without those bits should
   // be able to succeed.
-  size_t slot;
-  int ret = producer_queue_->AllocateBuffer(
+  auto status = producer_queue_->AllocateBuffer(
       kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
-      kBufferUsage & ~deny_set_mask, &slot);
-  ASSERT_EQ(ret, 0);
+      kBufferUsage & ~deny_set_mask);
+  ASSERT_TRUE(status.ok());
 
   // While allocation with those bits should fail.
-  ret = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
-                                        kBufferLayerCount, kBufferFormat,
-                                        kBufferUsage | deny_set_mask, &slot);
-  ASSERT_EQ(ret, -EINVAL);
+  status = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
+                                           kBufferLayerCount, kBufferFormat,
+                                           kBufferUsage | deny_set_mask);
+  ASSERT_FALSE(status.ok());
+  ASSERT_EQ(EINVAL, status.error());
 }
 
 TEST_F(BufferHubQueueTest, TestUsageDenyClearMask) {
   const uint32_t deny_clear_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
-  ASSERT_TRUE(CreateQueues<int64_t>(0, 0, 0, deny_clear_mask));
+  ASSERT_TRUE(CreateQueues(config_builder_.SetMetadata<int64_t>().Build(),
+                           UsagePolicy{0, 0, 0, deny_clear_mask}));
 
   // Now that clearing |deny_clear_mask| is illegal (i.e. setting these bits are
   // mandatory), allocation with those bits should be able to succeed.
-  size_t slot;
-  int ret = producer_queue_->AllocateBuffer(
+  auto status = producer_queue_->AllocateBuffer(
       kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
-      kBufferUsage | deny_clear_mask, &slot);
-  ASSERT_EQ(ret, 0);
+      kBufferUsage | deny_clear_mask);
+  ASSERT_TRUE(status.ok());
 
   // While allocation without those bits should fail.
-  ret = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
-                                        kBufferLayerCount, kBufferFormat,
-                                        kBufferUsage & ~deny_clear_mask, &slot);
-  ASSERT_EQ(ret, -EINVAL);
+  status = producer_queue_->AllocateBuffer(
+      kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
+      kBufferUsage & ~deny_clear_mask);
+  ASSERT_FALSE(status.ok());
+  ASSERT_EQ(EINVAL, status.error());
+}
+
+TEST_F(BufferHubQueueTest, TestQueueInfo) {
+  static const bool kIsAsync = true;
+  ASSERT_TRUE(CreateQueues(config_builder_.SetIsAsync(kIsAsync)
+                               .SetDefaultWidth(kBufferWidth)
+                               .SetDefaultHeight(kBufferHeight)
+                               .SetDefaultFormat(kBufferFormat)
+                               .Build(),
+                           UsagePolicy{}));
+
+  EXPECT_EQ(producer_queue_->default_width(), kBufferWidth);
+  EXPECT_EQ(producer_queue_->default_height(), kBufferHeight);
+  EXPECT_EQ(producer_queue_->default_format(), kBufferFormat);
+  EXPECT_EQ(producer_queue_->is_async(), kIsAsync);
+
+  EXPECT_EQ(consumer_queue_->default_width(), kBufferWidth);
+  EXPECT_EQ(consumer_queue_->default_height(), kBufferHeight);
+  EXPECT_EQ(consumer_queue_->default_format(), kBufferFormat);
+  EXPECT_EQ(consumer_queue_->is_async(), kIsAsync);
 }
 
 }  // namespace
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
index 2b6239f..c7692d0 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
@@ -192,7 +192,7 @@
   EXPECT_EQ(NO_ERROR,
             mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &value));
   EXPECT_LE(0, value);
-  EXPECT_GE(BufferQueueDefs::NUM_BUFFER_SLOTS, static_cast<size_t>(value));
+  EXPECT_GE(BufferQueueDefs::NUM_BUFFER_SLOTS, value);
 
   EXPECT_EQ(NO_ERROR,
             mProducer->query(NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &value));
diff --git a/libs/vr/libdisplay/Android.bp b/libs/vr/libdisplay/Android.bp
index d90521a..e3ab7fa 100644
--- a/libs/vr/libdisplay/Android.bp
+++ b/libs/vr/libdisplay/Android.bp
@@ -17,6 +17,7 @@
     "display_manager_client.cpp",
     "display_protocol.cpp",
     "vsync_client.cpp",
+    "shared_buffer_helpers.cpp",
 ]
 
 localIncludeFiles = [
@@ -39,12 +40,13 @@
     "libdvrcommon",
     "libbufferhubqueue",
     "libbufferhub",
-    "libvrsensor",
+    "libbroadcastring",
     "libpdx_default_transport",
 ]
 
 headerLibraries = [
     "vulkan_headers",
+    "libdvr_headers",
 ]
 
 cc_library {
diff --git a/libs/vr/libdisplay/display_client.cpp b/libs/vr/libdisplay/display_client.cpp
index 935ca2e..442c82d 100644
--- a/libs/vr/libdisplay/display_client.cpp
+++ b/libs/vr/libdisplay/display_client.cpp
@@ -104,9 +104,16 @@
   return {};
 }
 
-Status<std::unique_ptr<ProducerQueue>> Surface::CreateQueue() {
+Status<std::unique_ptr<ProducerQueue>> Surface::CreateQueue(
+    uint32_t width, uint32_t height, uint32_t format, size_t metadata_size) {
   ALOGD_IF(TRACE, "Surface::CreateQueue: Creating empty queue.");
-  auto status = InvokeRemoteMethod<DisplayProtocol::CreateQueue>(0);
+  auto status = InvokeRemoteMethod<DisplayProtocol::CreateQueue>(
+      ProducerQueueConfigBuilder()
+          .SetDefaultWidth(width)
+          .SetDefaultHeight(height)
+          .SetDefaultFormat(format)
+          .SetMetadataSize(metadata_size)
+          .Build());
   if (!status) {
     ALOGE("Surface::CreateQueue: Failed to create queue: %s",
           status.GetErrorMessage().c_str());
@@ -124,32 +131,24 @@
 
 Status<std::unique_ptr<ProducerQueue>> Surface::CreateQueue(
     uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
-    uint64_t usage, size_t capacity) {
+    uint64_t usage, size_t capacity, size_t metadata_size) {
   ALOGD_IF(TRACE,
            "Surface::CreateQueue: width=%u height=%u layer_count=%u format=%u "
            "usage=%" PRIx64 " capacity=%zu",
            width, height, layer_count, format, usage, capacity);
-  auto status = CreateQueue();
+  auto status = CreateQueue(width, height, format, metadata_size);
   if (!status)
     return status.error_status();
 
   auto producer_queue = status.take();
 
   ALOGD_IF(TRACE, "Surface::CreateQueue: Allocating %zu buffers...", capacity);
-  for (size_t i = 0; i < capacity; i++) {
-    size_t slot;
-    const int ret = producer_queue->AllocateBuffer(width, height, layer_count,
-                                                   format, usage, &slot);
-    if (ret < 0) {
-      ALOGE(
-          "Surface::CreateQueue: Failed to allocate buffer on queue_id=%d: %s",
-          producer_queue->id(), strerror(-ret));
-      return ErrorStatus(ENOMEM);
-    }
-    ALOGD_IF(
-        TRACE,
-        "Surface::CreateQueue: Allocated buffer at slot=%zu of capacity=%zu",
-        slot, capacity);
+  auto allocate_status = producer_queue->AllocateBuffers(
+      width, height, layer_count, format, usage, capacity);
+  if (!allocate_status) {
+    ALOGE("Surface::CreateQueue: Failed to allocate buffer on queue_id=%d: %s",
+          producer_queue->id(), allocate_status.GetErrorMessage().c_str());
+    return allocate_status.error_status();
   }
 
   return {std::move(producer_queue)};
@@ -167,6 +166,19 @@
   return InvokeRemoteMethod<DisplayProtocol::GetMetrics>();
 }
 
+Status<std::string> DisplayClient::GetConfigurationData(
+    ConfigFileType config_type) {
+  auto status =
+      InvokeRemoteMethod<DisplayProtocol::GetConfigurationData>(config_type);
+  if (!status && status.error() != ENOENT) {
+    ALOGE(
+        "DisplayClient::GetConfigurationData: Unable to get"
+        "configuration data. Error: %s",
+        status.GetErrorMessage().c_str());
+  }
+  return status;
+}
+
 Status<std::unique_ptr<Surface>> DisplayClient::CreateSurface(
     const SurfaceAttributes& attributes) {
   int error;
@@ -176,14 +188,15 @@
     return ErrorStatus(error);
 }
 
-Status<std::unique_ptr<IonBuffer>> DisplayClient::GetNamedBuffer(
-    const std::string& name) {
-  auto status = InvokeRemoteMethod<DisplayProtocol::GetNamedBuffer>(name);
+pdx::Status<std::unique_ptr<IonBuffer>> DisplayClient::SetupGlobalBuffer(
+    DvrGlobalBufferKey key, size_t size, uint64_t usage) {
+  auto status =
+      InvokeRemoteMethod<DisplayProtocol::SetupGlobalBuffer>(key, size, usage);
   if (!status) {
     ALOGE(
-        "DisplayClient::GetNamedBuffer: Failed to get named buffer: name=%s; "
-        "error=%s",
-        name.c_str(), status.GetErrorMessage().c_str());
+        "DisplayClient::SetupGlobalBuffer: Failed to create the global buffer "
+        "%s",
+        status.GetErrorMessage().c_str());
     return status.error_status();
   }
 
@@ -192,9 +205,44 @@
   const int ret = native_buffer_handle.Import(ion_buffer.get());
   if (ret < 0) {
     ALOGE(
-        "DisplayClient::GetNamedBuffer: Failed to import named buffer: "
-        "name=%s; error=%s",
-        name.c_str(), strerror(-ret));
+        "DisplayClient::GetGlobalBuffer: Failed to import global buffer: "
+        "key=%d; error=%s",
+        key, strerror(-ret));
+    return ErrorStatus(-ret);
+  }
+
+  return {std::move(ion_buffer)};
+}
+
+pdx::Status<void> DisplayClient::DeleteGlobalBuffer(DvrGlobalBufferKey key) {
+  auto status = InvokeRemoteMethod<DisplayProtocol::DeleteGlobalBuffer>(key);
+  if (!status) {
+    ALOGE("DisplayClient::DeleteGlobalBuffer Failed: %s",
+          status.GetErrorMessage().c_str());
+  }
+
+  return status;
+}
+
+Status<std::unique_ptr<IonBuffer>> DisplayClient::GetGlobalBuffer(
+    DvrGlobalBufferKey key) {
+  auto status = InvokeRemoteMethod<DisplayProtocol::GetGlobalBuffer>(key);
+  if (!status) {
+    ALOGE(
+        "DisplayClient::GetGlobalBuffer: Failed to get named buffer: key=%d; "
+        "error=%s",
+        key, status.GetErrorMessage().c_str());
+    return status.error_status();
+  }
+
+  auto ion_buffer = std::make_unique<IonBuffer>();
+  auto native_buffer_handle = status.take();
+  const int ret = native_buffer_handle.Import(ion_buffer.get());
+  if (ret < 0) {
+    ALOGE(
+        "DisplayClient::GetGlobalBuffer: Failed to import global buffer: "
+        "key=%d; error=%s",
+        key, strerror(-ret));
     return ErrorStatus(-ret);
   }
 
diff --git a/libs/vr/libdisplay/display_manager_client.cpp b/libs/vr/libdisplay/display_manager_client.cpp
index 82dacf7..974c231 100644
--- a/libs/vr/libdisplay/display_manager_client.cpp
+++ b/libs/vr/libdisplay/display_manager_client.cpp
@@ -32,32 +32,6 @@
   return status;
 }
 
-pdx::Status<std::unique_ptr<IonBuffer>> DisplayManagerClient::SetupNamedBuffer(
-    const std::string& name, size_t size, uint64_t usage) {
-  auto status = InvokeRemoteMethod<DisplayManagerProtocol::SetupNamedBuffer>(
-      name, size, usage);
-  if (!status) {
-    ALOGE(
-        "DisplayManagerClient::SetupPoseBuffer: Failed to create the named "
-        "buffer %s",
-        status.GetErrorMessage().c_str());
-    return status.error_status();
-  }
-
-  auto ion_buffer = std::make_unique<IonBuffer>();
-  auto native_buffer_handle = status.take();
-  const int ret = native_buffer_handle.Import(ion_buffer.get());
-  if (ret < 0) {
-    ALOGE(
-        "DisplayClient::GetNamedBuffer: Failed to import named buffer: "
-        "name=%s; error=%s",
-        name.c_str(), strerror(-ret));
-    return ErrorStatus(-ret);
-  }
-
-  return {std::move(ion_buffer)};
-}
-
 pdx::Status<std::unique_ptr<ConsumerQueue>>
 DisplayManagerClient::GetSurfaceQueue(int surface_id, int queue_id) {
   auto status = InvokeRemoteMethod<DisplayManagerProtocol::GetSurfaceQueue>(
diff --git a/libs/vr/libdisplay/include/private/dvr/display_client.h b/libs/vr/libdisplay/include/private/dvr/display_client.h
index 7a7f670..caf3182 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_client.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_client.h
@@ -1,6 +1,7 @@
 #ifndef ANDROID_DVR_DISPLAY_CLIENT_H_
 #define ANDROID_DVR_DISPLAY_CLIENT_H_
 
+#include <dvr/dvr_api.h>
 #include <hardware/hwcomposer.h>
 #include <pdx/client.h>
 #include <pdx/file_handle.h>
@@ -36,7 +37,10 @@
   pdx::Status<void> SetAttributes(const SurfaceAttributes& attributes);
 
   // Creates an empty queue.
-  pdx::Status<std::unique_ptr<ProducerQueue>> CreateQueue();
+  pdx::Status<std::unique_ptr<ProducerQueue>> CreateQueue(uint32_t width,
+                                                          uint32_t height,
+                                                          uint32_t format,
+                                                          size_t metadata_size);
 
   // Creates a queue and populates it with |capacity| buffers of the specified
   // parameters.
@@ -45,7 +49,8 @@
                                                           uint32_t layer_count,
                                                           uint32_t format,
                                                           uint64_t usage,
-                                                          size_t capacity);
+                                                          size_t capacity,
+                                                          size_t metadata_size);
 
  private:
   friend BASE;
@@ -67,8 +72,12 @@
 class DisplayClient : public pdx::ClientBase<DisplayClient> {
  public:
   pdx::Status<Metrics> GetDisplayMetrics();
-  pdx::Status<std::unique_ptr<IonBuffer>> GetNamedBuffer(
-      const std::string& name);
+  pdx::Status<std::string> GetConfigurationData(ConfigFileType config_type);
+  pdx::Status<std::unique_ptr<IonBuffer>> SetupGlobalBuffer(
+      DvrGlobalBufferKey key, size_t size, uint64_t usage);
+  pdx::Status<void> DeleteGlobalBuffer(DvrGlobalBufferKey key);
+  pdx::Status<std::unique_ptr<IonBuffer>> GetGlobalBuffer(
+      DvrGlobalBufferKey key);
   pdx::Status<std::unique_ptr<Surface>> CreateSurface(
       const SurfaceAttributes& attributes);
 
diff --git a/libs/vr/libdisplay/include/private/dvr/display_manager_client.h b/libs/vr/libdisplay/include/private/dvr/display_manager_client.h
index fea8415..45aef51 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_manager_client.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_manager_client.h
@@ -21,8 +21,6 @@
   ~DisplayManagerClient() override;
 
   pdx::Status<std::vector<SurfaceState>> GetSurfaceState();
-  pdx::Status<std::unique_ptr<IonBuffer>> SetupNamedBuffer(
-      const std::string& name, size_t size, uint64_t usage);
   pdx::Status<std::unique_ptr<ConsumerQueue>> GetSurfaceQueue(int surface_id,
                                                               int queue_id);
 
diff --git a/libs/vr/libdisplay/include/private/dvr/display_protocol.h b/libs/vr/libdisplay/include/private/dvr/display_protocol.h
index f34d61f..eff50ba 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_protocol.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_protocol.h
@@ -8,6 +8,8 @@
 
 #include <dvr/dvr_display_types.h>
 
+#include <dvr/dvr_api.h>
+#include <pdx/rpc/buffer_wrapper.h>
 #include <pdx/rpc/remote_method.h>
 #include <pdx/rpc/serializable.h>
 #include <pdx/rpc/variant.h>
@@ -184,6 +186,12 @@
   PDX_SERIALIZABLE_MEMBERS(SurfaceInfo, surface_id, visible, z_order);
 };
 
+enum class ConfigFileType : uint32_t {
+  kLensMetrics,
+  kDeviceMetrics,
+  kDeviceConfiguration
+};
+
 struct DisplayProtocol {
   // Service path.
   static constexpr char kClientPath[] = "system/vr/display/client";
@@ -191,7 +199,10 @@
   // Op codes.
   enum {
     kOpGetMetrics = 0,
-    kOpGetNamedBuffer,
+    kOpGetConfigurationData,
+    kOpSetupGlobalBuffer,
+    kOpDeleteGlobalBuffer,
+    kOpGetGlobalBuffer,
     kOpIsVrAppRunning,
     kOpCreateSurface,
     kOpGetSurfaceInfo,
@@ -205,14 +216,22 @@
 
   // Methods.
   PDX_REMOTE_METHOD(GetMetrics, kOpGetMetrics, Metrics(Void));
-  PDX_REMOTE_METHOD(GetNamedBuffer, kOpGetNamedBuffer,
-                    LocalNativeBufferHandle(std::string name));
+  PDX_REMOTE_METHOD(GetConfigurationData, kOpGetConfigurationData,
+                    std::string(ConfigFileType config_type));
+  PDX_REMOTE_METHOD(SetupGlobalBuffer, kOpSetupGlobalBuffer,
+                    LocalNativeBufferHandle(DvrGlobalBufferKey key, size_t size,
+                                            uint64_t usage));
+  PDX_REMOTE_METHOD(DeleteGlobalBuffer, kOpDeleteGlobalBuffer,
+                    void(DvrGlobalBufferKey key));
+  PDX_REMOTE_METHOD(GetGlobalBuffer, kOpGetGlobalBuffer,
+                    LocalNativeBufferHandle(DvrGlobalBufferKey key));
   PDX_REMOTE_METHOD(IsVrAppRunning, kOpIsVrAppRunning, bool(Void));
   PDX_REMOTE_METHOD(CreateSurface, kOpCreateSurface,
                     SurfaceInfo(const SurfaceAttributes& attributes));
   PDX_REMOTE_METHOD(GetSurfaceInfo, kOpGetSurfaceInfo, SurfaceInfo(Void));
-  PDX_REMOTE_METHOD(CreateQueue, kOpCreateQueue,
-                    LocalChannelHandle(size_t meta_size_bytes));
+  PDX_REMOTE_METHOD(
+      CreateQueue, kOpCreateQueue,
+      LocalChannelHandle(const ProducerQueueConfig& producer_config));
   PDX_REMOTE_METHOD(SetAttributes, kOpSetAttributes,
                     void(const SurfaceAttributes& attributes));
 };
@@ -225,7 +244,6 @@
   enum {
     kOpGetSurfaceState = 0,
     kOpGetSurfaceQueue,
-    kOpSetupNamedBuffer,
   };
 
   // Aliases.
@@ -237,9 +255,6 @@
                     std::vector<SurfaceState>(Void));
   PDX_REMOTE_METHOD(GetSurfaceQueue, kOpGetSurfaceQueue,
                     LocalChannelHandle(int surface_id, int queue_id));
-  PDX_REMOTE_METHOD(SetupNamedBuffer, kOpSetupNamedBuffer,
-                    LocalNativeBufferHandle(const std::string& name,
-                                            size_t size, uint64_t usage));
 };
 
 struct VSyncSchedInfo {
diff --git a/libs/vr/libdisplay/include/private/dvr/shared_buffer_helpers.h b/libs/vr/libdisplay/include/private/dvr/shared_buffer_helpers.h
new file mode 100644
index 0000000..20541a6
--- /dev/null
+++ b/libs/vr/libdisplay/include/private/dvr/shared_buffer_helpers.h
@@ -0,0 +1,146 @@
+#ifndef ANDROID_DVR_SHARED_BUFFER_HELPERS_H_
+#define ANDROID_DVR_SHARED_BUFFER_HELPERS_H_
+
+#include <assert.h>
+#include <tuple>
+
+#include <libbroadcastring/broadcast_ring.h>
+#include <private/dvr/display_client.h>
+
+namespace android {
+namespace dvr {
+
+// The buffer usage type for mapped shared buffers.
+enum class CPUUsageMode { READ_OFTEN, READ_RARELY, WRITE_OFTEN, WRITE_RARELY };
+
+// Holds the memory for the mapped shared buffer. Unlocks and releases the
+// underlying IonBuffer in destructor.
+class CPUMappedBuffer {
+ public:
+  // This constructor will create a display client and get the buffer from it.
+  CPUMappedBuffer(DvrGlobalBufferKey key, CPUUsageMode mode);
+
+  // If you already have the IonBuffer, use this. It will take ownership.
+  CPUMappedBuffer(std::unique_ptr<IonBuffer> buffer, CPUUsageMode mode);
+
+  // Use this if you do not want to take ownership.
+  CPUMappedBuffer(IonBuffer* buffer, CPUUsageMode mode);
+
+  ~CPUMappedBuffer();
+
+  // Getters.
+  size_t Size() const { return size_; }
+  void* Address() const { return address_; }
+  bool IsMapped() const { return Address() != nullptr; }
+
+  // Attempt mapping this buffer to the CPU addressable space.
+  // This will create a display client and see if the buffer exists.
+  // If the buffer has not been setup yet, you will need to try again later.
+  void TryMapping();
+
+ protected:
+  // The memory area if we managed to map it.
+  size_t size_ = 0;
+  void* address_ = nullptr;
+
+  // If we are polling the display client, the buffer key here.
+  DvrGlobalBufferKey buffer_key_;
+
+  // If we just own the IonBuffer outright, it's here.
+  std::unique_ptr<IonBuffer> owned_buffer_ = nullptr;
+
+  // The last time we connected to the display service.
+  int64_t last_display_service_connection_ns_ = 0;
+
+  // If we do not own the IonBuffer, it's here
+  IonBuffer* buffer_ = nullptr;
+
+  // The usage mode.
+  CPUUsageMode usage_mode_ = CPUUsageMode::READ_OFTEN;
+};
+
+// Represents a broadcast ring inside a mapped shared memory buffer.
+// If has the same set of constructors as CPUMappedBuffer.
+// The template argument is the concrete BroadcastRing class that this buffer
+// holds.
+template <class RingType>
+class CPUMappedBroadcastRing : public CPUMappedBuffer {
+ public:
+  CPUMappedBroadcastRing(DvrGlobalBufferKey key, CPUUsageMode mode)
+      : CPUMappedBuffer(key, mode) {}
+
+  CPUMappedBroadcastRing(std::unique_ptr<IonBuffer> buffer, CPUUsageMode mode)
+      : CPUMappedBuffer(std::move(buffer), mode) {}
+
+  CPUMappedBroadcastRing(IonBuffer* buffer, CPUUsageMode mode)
+      : CPUMappedBuffer(buffer, mode) {}
+
+  // Helper function for publishing records in the ring.
+  void Publish(const typename RingType::Record& record) {
+    assert((usage_mode_ == CPUUsageMode::WRITE_OFTEN) ||
+           (usage_mode_ == CPUUsageMode::WRITE_RARELY));
+
+    auto ring = Ring();
+    if (ring) {
+      ring->Put(record);
+    }
+  }
+
+  // Helper function for getting records from the ring.
+  // Returns true if we were able to retrieve the latest.
+  bool GetNewest(typename RingType::Record* record) {
+    assert((usage_mode_ == CPUUsageMode::READ_OFTEN) ||
+           (usage_mode_ == CPUUsageMode::READ_RARELY));
+
+    auto ring = Ring();
+    if (ring) {
+      return ring->GetNewest(&sequence_, record);
+    }
+
+    return false;
+  }
+
+  // Try obtaining the ring. If the named buffer has not been created yet, it
+  // will return nullptr.
+  RingType* Ring() {
+    // No ring created yet?
+    if (ring_ == nullptr) {
+      // Not mapped the memory yet?
+      if (IsMapped() == false) {
+        TryMapping();
+      }
+
+      // If have the memory mapped, allocate the ring.
+      if (IsMapped()) {
+        switch (usage_mode_) {
+          case CPUUsageMode::READ_OFTEN:
+          case CPUUsageMode::READ_RARELY: {
+            RingType ring;
+            bool import_ok;
+            std::tie(ring, import_ok) = RingType::Import(address_, size_);
+            if (import_ok) {
+              ring_ = std::make_unique<RingType>(ring);
+            }
+          } break;
+          case CPUUsageMode::WRITE_OFTEN:
+          case CPUUsageMode::WRITE_RARELY:
+            ring_ =
+                std::make_unique<RingType>(RingType::Create(address_, size_));
+            break;
+        }
+      }
+    }
+
+    return ring_.get();
+  }
+
+ protected:
+  std::unique_ptr<RingType> ring_ = nullptr;
+
+  uint32_t sequence_ = 0;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_SHARED_BUFFER_HELPERS_H_
diff --git a/libs/vr/libdisplay/shared_buffer_helpers.cpp b/libs/vr/libdisplay/shared_buffer_helpers.cpp
new file mode 100644
index 0000000..6ebf487
--- /dev/null
+++ b/libs/vr/libdisplay/shared_buffer_helpers.cpp
@@ -0,0 +1,98 @@
+#include <private/dvr/clock_ns.h>
+#include <private/dvr/shared_buffer_helpers.h>
+
+namespace android {
+namespace dvr {
+namespace {
+
+// We will not poll the display service for buffers more frequently than this.
+constexpr size_t kDisplayServiceTriesPerSecond = 2;
+}  // namespace
+
+CPUMappedBuffer::CPUMappedBuffer(DvrGlobalBufferKey key, CPUUsageMode mode)
+    : buffer_key_(key), usage_mode_(mode) {
+  TryMapping();
+}
+
+CPUMappedBuffer::CPUMappedBuffer(std::unique_ptr<IonBuffer> buffer,
+                                 CPUUsageMode mode)
+    : owned_buffer_(std::move(buffer)),
+      buffer_(owned_buffer_.get()),
+      usage_mode_(mode) {
+  TryMapping();
+}
+
+CPUMappedBuffer::CPUMappedBuffer(IonBuffer* buffer, CPUUsageMode mode)
+    : buffer_(buffer), usage_mode_(mode) {
+  TryMapping();
+}
+
+CPUMappedBuffer::~CPUMappedBuffer() {
+  if (IsMapped()) {
+    buffer_->Unlock();
+  }
+}
+
+void CPUMappedBuffer::TryMapping() {
+  // Do we have an IonBuffer for this shared memory object?
+  if (buffer_ == nullptr) {
+    // Has it been too long since we last connected to the display service?
+    const auto current_time_ns = GetSystemClockNs();
+    if ((current_time_ns - last_display_service_connection_ns_) <
+        (1e9 / kDisplayServiceTriesPerSecond)) {
+      // Early exit.
+      return;
+    }
+    last_display_service_connection_ns_ = current_time_ns;
+
+    // Create a display client and get the buffer.
+    auto display_client = display::DisplayClient::Create();
+    if (display_client) {
+      auto get_result = display_client->GetGlobalBuffer(buffer_key_);
+      if (get_result.ok()) {
+        owned_buffer_ = get_result.take();
+        buffer_ = owned_buffer_.get();
+      } else {
+        // The buffer has not been created yet. This is OK, we will keep
+        // retrying.
+      }
+    } else {
+      ALOGE("Unable to create display client for shared buffer access");
+    }
+  }
+
+  if (buffer_) {
+    auto usage = buffer_->usage() & ~GRALLOC_USAGE_SW_READ_MASK &
+                 ~GRALLOC_USAGE_SW_WRITE_MASK;
+
+    // Figure out the usage bits.
+    switch (usage_mode_) {
+      case CPUUsageMode::READ_OFTEN:
+        usage |= GRALLOC_USAGE_SW_READ_OFTEN;
+        break;
+      case CPUUsageMode::READ_RARELY:
+        usage |= GRALLOC_USAGE_SW_READ_RARELY;
+        break;
+      case CPUUsageMode::WRITE_OFTEN:
+        usage |= GRALLOC_USAGE_SW_WRITE_OFTEN;
+        break;
+      case CPUUsageMode::WRITE_RARELY:
+        usage |= GRALLOC_USAGE_SW_WRITE_RARELY;
+        break;
+    }
+
+    int width = static_cast<int>(buffer_->width());
+    int height = 1;
+    const auto ret = buffer_->Lock(usage, 0, 0, width, height, &address_);
+
+    if (ret < 0 || !address_) {
+      ALOGE("Pose failed to map ring buffer: ret:%d, addr:%p", ret, address_);
+      buffer_->Unlock();
+    } else {
+      size_ = width;
+    }
+  }
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp
index fa78b1c..7fe9825 100644
--- a/libs/vr/libdvr/Android.bp
+++ b/libs/vr/libdvr/Android.bp
@@ -21,27 +21,32 @@
 
 cflags = [
     "-DLOG_TAG=\"libdvr\"",
+    "-DTRACE=0",
 ]
 
 srcs = [
     "dvr_api.cpp",
     "dvr_buffer.cpp",
     "dvr_buffer_queue.cpp",
+    "dvr_configuration_data.cpp",
     "dvr_display_manager.cpp",
     "dvr_hardware_composer_client.cpp",
+    "dvr_performance.cpp",
     "dvr_surface.cpp",
     "dvr_vsync.cpp",
 ]
 
 static_libs = [
+    "libbroadcastring",
     "libbufferhub",
     "libbufferhubqueue",
-    "libdisplay",
     "libvrsensor",
+    "libdisplay",
     "libvirtualtouchpadclient",
     "libvr_hwc-impl",
     "libvr_hwc-binder",
     "libgrallocusage",
+    "libperformance",
     "libpdx_default_transport",
 ]
 
diff --git a/libs/vr/libdvr/dvr_api.cpp b/libs/vr/libdvr/dvr_api.cpp
index 2c95583..7d4e2d1 100644
--- a/libs/vr/libdvr/dvr_api.cpp
+++ b/libs/vr/libdvr/dvr_api.cpp
@@ -3,10 +3,14 @@
 #include <errno.h>
 #include <utils/Log.h>
 
+#include <algorithm>
+
 // Headers from libdvr
 #include <dvr/dvr_buffer.h>
 #include <dvr/dvr_buffer_queue.h>
+#include <dvr/dvr_configuration_data.h>
 #include <dvr/dvr_display_manager.h>
+#include <dvr/dvr_performance.h>
 #include <dvr/dvr_surface.h>
 #include <dvr/dvr_vsync.h>
 
@@ -22,15 +26,20 @@
   ALOGI("dvrGetApi: api=%p struct_size=%zu version=%d", api, struct_size,
         version);
   if (version == 1) {
-    if (struct_size != sizeof(DvrApi_v1)) {
-      ALOGE("dvrGetApi: Size mismatch: expected %zu; actual %zu",
-            sizeof(DvrApi_v1), struct_size);
-      return -EINVAL;
-    }
+    // New entry points are added at the end. If the caller's struct and
+    // this library have different sizes, we define the entry points in common.
+    // The caller is expected to handle unset entry points if necessary.
+    size_t clamped_struct_size = std::min(struct_size, sizeof(DvrApi_v1));
     DvrApi_v1* dvr_api = static_cast<DvrApi_v1*>(api);
 
 // Defines an API entry for V1 (no version suffix).
-#define DVR_V1_API_ENTRY(name) dvr_api->name = dvr##name
+#define DVR_V1_API_ENTRY(name)                                 \
+  do {                                                         \
+    if ((offsetof(DvrApi_v1, name) + sizeof(dvr_api->name)) <= \
+        clamped_struct_size) {                                 \
+      dvr_api->name = dvr##name;                               \
+    }                                                          \
+  } while (0)
 
 #include "include/dvr/dvr_api_entries.h"
 
diff --git a/libs/vr/libdvr/dvr_buffer.cpp b/libs/vr/libdvr/dvr_buffer.cpp
index 82469b8..4d9b215 100644
--- a/libs/vr/libdvr/dvr_buffer.cpp
+++ b/libs/vr/libdvr/dvr_buffer.cpp
@@ -1,6 +1,7 @@
 #include "include/dvr/dvr_buffer.h"
 
 #include <android/hardware_buffer.h>
+#include <dvr/dvr_shared_buffers.h>
 #include <private/dvr/buffer_hub_client.h>
 #include <ui/GraphicBuffer.h>
 
@@ -176,6 +177,11 @@
                                   hardware_buffer);
 }
 
+// Retrieve the shared buffer layout version defined in dvr_shared_buffers.h.
+int dvrBufferGlobalLayoutVersionGet() {
+  return android::dvr::kSharedBufferLayoutVersion;
+}
+
 const struct native_handle* dvrWriteBufferGetNativeHandle(
     DvrWriteBuffer* write_buffer) {
   if (!write_buffer || !write_buffer->write_buffer)
diff --git a/libs/vr/libdvr/dvr_buffer_queue.cpp b/libs/vr/libdvr/dvr_buffer_queue.cpp
index f668510..018abbb 100644
--- a/libs/vr/libdvr/dvr_buffer_queue.cpp
+++ b/libs/vr/libdvr/dvr_buffer_queue.cpp
@@ -2,60 +2,176 @@
 #include "include/dvr/dvr_buffer_queue.h"
 
 #include <android/native_window.h>
-#include <gui/Surface.h>
-#include <private/dvr/buffer_hub_queue_client.h>
 #include <private/dvr/buffer_hub_queue_producer.h>
 
 #include "dvr_internal.h"
-
-#define CHECK_PARAM(param)                                               \
-  LOG_ALWAYS_FATAL_IF(param == nullptr, "%s: " #param "cannot be NULL.", \
-                      __FUNCTION__)
+#include "dvr_buffer_queue_internal.h"
 
 using namespace android;
-
-namespace android {
-namespace dvr {
-
-DvrWriteBufferQueue* CreateDvrWriteBufferQueueFromProducerQueue(
-    const std::shared_ptr<dvr::ProducerQueue>& producer_queue) {
-  return new DvrWriteBufferQueue{std::move(producer_queue)};
-}
-
-DvrReadBufferQueue* CreateDvrReadBufferQueueFromConsumerQueue(
-    const std::shared_ptr<dvr::ConsumerQueue>& consumer_queue) {
-  return new DvrReadBufferQueue{std::move(consumer_queue)};
-}
-
-dvr::ProducerQueue* GetProducerQueueFromDvrWriteBufferQueue(
-    DvrWriteBufferQueue* write_queue) {
-  return write_queue->producer_queue.get();
-}
-
-}  // namespace dvr
-}  // namespace android
+using android::dvr::BufferConsumer;
+using android::dvr::BufferHubBuffer;
+using android::dvr::BufferHubQueueProducer;
+using android::dvr::BufferProducer;
+using android::dvr::ConsumerQueue;
+using android::dvr::ProducerQueue;
 
 extern "C" {
 
-void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue) {
-  if (write_queue != nullptr && write_queue->native_window != nullptr)
-    ANativeWindow_release(write_queue->native_window);
+DvrWriteBufferQueue::DvrWriteBufferQueue(
+    const std::shared_ptr<ProducerQueue>& producer_queue)
+    : producer_queue_(producer_queue),
+      width_(producer_queue->default_width()),
+      height_(producer_queue->default_height()),
+      format_(producer_queue->default_format()) {}
 
+int DvrWriteBufferQueue::GetNativeWindow(ANativeWindow** out_window) {
+  if (producer_queue_->metadata_size() != sizeof(DvrNativeBufferMetadata)) {
+    ALOGE(
+        "DvrWriteBufferQueue::GetNativeWindow: The size of buffer metadata "
+        "(%zu) of the write queue does not match  of size of "
+        "DvrNativeBufferMetadata (%zu).",
+        producer_queue_->metadata_size(), sizeof(DvrNativeBufferMetadata));
+    return -EINVAL;
+  }
+
+  if (native_window_ == nullptr) {
+    // Lazy creation of |native_window|, as not everyone is using
+    // DvrWriteBufferQueue as an external surface.
+    sp<IGraphicBufferProducer> gbp =
+        BufferHubQueueProducer::Create(producer_queue_);
+    native_window_ = new Surface(gbp, true);
+  }
+
+  *out_window = static_cast<ANativeWindow*>(native_window_.get());
+  return 0;
+}
+
+int DvrWriteBufferQueue::CreateReadQueue(DvrReadBufferQueue** out_read_queue) {
+  std::unique_ptr<ConsumerQueue> consumer_queue =
+      producer_queue_->CreateConsumerQueue();
+  if (consumer_queue == nullptr) {
+    ALOGE(
+        "DvrWriteBufferQueue::CreateReadQueue: Failed to create consumer queue "
+        "from producer queue: queue_id=%d.", producer_queue_->id());
+    return -ENOMEM;
+  }
+
+  *out_read_queue = new DvrReadBufferQueue(std::move(consumer_queue));
+  return 0;
+}
+
+int DvrWriteBufferQueue::Dequeue(int timeout, DvrWriteBuffer* write_buffer,
+                                 int* out_fence_fd) {
+  size_t slot;
+  pdx::LocalHandle fence;
+  std::shared_ptr<BufferProducer> buffer_producer;
+
+  // Need to retry N+1 times, where N is total number of buffers in the queue.
+  // As in the worst case, we will dequeue all N buffers and reallocate them, on
+  // the {N+1}th dequeue, we are guaranteed to get a buffer with new dimension.
+  size_t max_retries = 1 + producer_queue_->capacity();
+  size_t retry = 0;
+
+  for (; retry < max_retries; retry++) {
+    auto buffer_status = producer_queue_->Dequeue(timeout, &slot, &fence);
+    if (!buffer_status) {
+      ALOGE_IF(buffer_status.error() != ETIMEDOUT,
+               "DvrWriteBufferQueue::Dequeue: Failed to dequeue buffer: %s",
+               buffer_status.GetErrorMessage().c_str());
+      return -buffer_status.error();
+    }
+
+    buffer_producer = buffer_status.take();
+    if (!buffer_producer)
+      return -ENOMEM;
+
+    if (width_ == buffer_producer->width() &&
+        height_ == buffer_producer->height() &&
+        format_ == buffer_producer->format()) {
+      // Producer queue returns a buffer matches the current request.
+      break;
+    }
+
+    // Needs reallocation. Note that if there are already multiple available
+    // buffers in the queue, the next one returned from |queue_->Dequeue| may
+    // still have the old buffer dimension or format. Retry up to N+1 times or
+    // until we dequeued a buffer with new configuration.
+    ALOGD_IF(TRACE,
+             "DvrWriteBufferQueue::Dequeue: requested buffer at slot: %zu "
+             "(w=%u, h=%u, fmt=%u) is different from the buffer returned "
+             "(w=%u, h=%u, fmt=%u). Need re-allocation.",
+             slot, width_, height_, format_, buffer_producer->width(),
+             buffer_producer->height(), buffer_producer->format());
+
+    // Currently, we are not storing |layer_count| and |usage| in queue
+    // configuration. Copy those setup from the last buffer dequeued before we
+    // remove it.
+    uint32_t old_layer_count = buffer_producer->layer_count();
+    uint64_t old_usage = buffer_producer->usage();
+
+    // Allocate a new producer buffer with new buffer configs. Note that if
+    // there are already multiple available buffers in the queue, the next one
+    // returned from |queue_->Dequeue| may still have the old buffer dimension
+    // or format. Retry up to BufferHubQueue::kMaxQueueCapacity times or until
+    // we dequeued a buffer with new configuration.
+    auto remove_status = producer_queue_->RemoveBuffer(slot);
+    if (!remove_status) {
+      ALOGE("DvrWriteBufferQueue::Dequeue: Failed to remove buffer: %s",
+            remove_status.GetErrorMessage().c_str());
+      return -remove_status.error();
+    }
+
+    auto allocate_status = producer_queue_->AllocateBuffer(
+        width_, height_, old_layer_count, format_, old_usage);
+    if (!allocate_status) {
+      ALOGE("DvrWriteBufferQueue::Dequeue: Failed to allocate buffer: %s",
+            allocate_status.GetErrorMessage().c_str());
+      return -allocate_status.error();
+    }
+  }
+
+  if (retry >= max_retries) {
+    ALOGE(
+        "DvrWriteBufferQueue::Dequeue: Failed to re-allocate buffer after "
+        "resizing.");
+    return -ENOMEM;
+  }
+
+  write_buffer->write_buffer = std::move(buffer_producer);
+  *out_fence_fd = fence.Release();
+  return 0;
+}
+
+int DvrWriteBufferQueue::ResizeBuffer(uint32_t width, uint32_t height) {
+  if (width == 0 || height == 0) {
+    ALOGE(
+        "DvrWriteBufferQueue::ResizeBuffer: invalid buffer dimension: w=%u, "
+        "h=%u.",
+        width, height);
+    return -EINVAL;
+  }
+
+  width_ = width;
+  height_ = height;
+  return 0;
+}
+
+void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue) {
   delete write_queue;
 }
 
 ssize_t dvrWriteBufferQueueGetCapacity(DvrWriteBufferQueue* write_queue) {
-  if (!write_queue || !write_queue->producer_queue)
+  if (!write_queue)
     return -EINVAL;
 
-  return write_queue->producer_queue->capacity();
+  return write_queue->capacity();
 }
 
 int dvrWriteBufferQueueGetId(DvrWriteBufferQueue* write_queue) {
   if (!write_queue)
     return -EINVAL;
 
-  return write_queue->producer_queue->id();
+  return write_queue->id();
 }
 
 int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
@@ -63,131 +179,68 @@
   if (!write_queue || !out_window)
     return -EINVAL;
 
-  if (write_queue->producer_queue->metadata_size() !=
-      sizeof(DvrNativeBufferMetadata)) {
-    ALOGE(
-        "The size of buffer metadata (%zu) of the write queue does not match "
-        "of size of DvrNativeBufferMetadata (%zu).",
-        write_queue->producer_queue->metadata_size(),
-        sizeof(DvrNativeBufferMetadata));
-    return -EINVAL;
-  }
-
-  // Lazy creation of |native_window|.
-  if (write_queue->native_window == nullptr) {
-    sp<IGraphicBufferProducer> gbp =
-        dvr::BufferHubQueueProducer::Create(write_queue->producer_queue);
-    sp<Surface> surface = new Surface(gbp, true);
-    write_queue->native_window = static_cast<ANativeWindow*>(surface.get());
-    ANativeWindow_acquire(write_queue->native_window);
-  }
-
-  *out_window = write_queue->native_window;
-  return 0;
+  return write_queue->GetNativeWindow(out_window);
 }
 
 int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue,
                                        DvrReadBufferQueue** out_read_queue) {
-  if (!write_queue || !write_queue->producer_queue || !out_read_queue)
+  if (!write_queue || !out_read_queue)
     return -EINVAL;
 
-  auto read_queue = std::make_unique<DvrReadBufferQueue>();
-  read_queue->consumer_queue =
-      write_queue->producer_queue->CreateConsumerQueue();
-  if (read_queue->consumer_queue == nullptr) {
-    ALOGE(
-        "dvrWriteBufferQueueCreateReadQueue: Failed to create consumer queue "
-        "from DvrWriteBufferQueue[%p].",
-        write_queue);
-    return -ENOMEM;
-  }
-
-  *out_read_queue = read_queue.release();
-  return 0;
+  return write_queue->CreateReadQueue(out_read_queue);
 }
 
 int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout,
                                DvrWriteBuffer* write_buffer,
                                int* out_fence_fd) {
-  if (!write_queue || !write_queue->producer_queue || !write_buffer ||
-      !out_fence_fd) {
+  if (!write_queue || !write_buffer || !out_fence_fd)
     return -EINVAL;
-  }
 
-  size_t slot;
-  pdx::LocalHandle release_fence;
-  auto buffer_status =
-      write_queue->producer_queue->Dequeue(timeout, &slot, &release_fence);
-  if (!buffer_status) {
-    ALOGE_IF(buffer_status.error() != ETIMEDOUT,
-             "dvrWriteBufferQueueDequeue: Failed to dequeue buffer: %s",
-             buffer_status.GetErrorMessage().c_str());
-    return -buffer_status.error();
-  }
+  return write_queue->Dequeue(timeout, write_buffer, out_fence_fd);
+}
 
-  write_buffer->write_buffer = buffer_status.take();
-  *out_fence_fd = release_fence.Release();
-  return 0;
+int dvrWriteBufferQueueResizeBuffer(DvrWriteBufferQueue* write_queue,
+                                    uint32_t width, uint32_t height) {
+  if (!write_queue)
+    return -EINVAL;
+
+  return write_queue->ResizeBuffer(width, height);
 }
 
 // ReadBufferQueue
-void dvrReadBufferQueueDestroy(DvrReadBufferQueue* read_queue) {
-  delete read_queue;
-}
 
-ssize_t dvrReadBufferQueueGetCapacity(DvrReadBufferQueue* read_queue) {
-  if (!read_queue)
-    return -EINVAL;
+DvrReadBufferQueue::DvrReadBufferQueue(
+    const std::shared_ptr<ConsumerQueue>& consumer_queue)
+    : consumer_queue_(consumer_queue) {}
 
-  return read_queue->consumer_queue->capacity();
-}
-
-int dvrReadBufferQueueGetId(DvrReadBufferQueue* read_queue) {
-  if (!read_queue)
-    return -EINVAL;
-
-  return read_queue->consumer_queue->id();
-}
-
-int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
-                                      DvrReadBufferQueue** out_read_queue) {
-  if (!read_queue || !read_queue->consumer_queue || !out_read_queue)
-    return -EINVAL;
-
-  auto new_read_queue = std::make_unique<DvrReadBufferQueue>();
-  new_read_queue->consumer_queue =
-      read_queue->consumer_queue->CreateConsumerQueue();
-  if (new_read_queue->consumer_queue == nullptr) {
+int DvrReadBufferQueue::CreateReadQueue(DvrReadBufferQueue** out_read_queue) {
+  std::unique_ptr<ConsumerQueue> consumer_queue =
+      consumer_queue_->CreateConsumerQueue();
+  if (consumer_queue == nullptr) {
     ALOGE(
-        "dvrReadBufferQueueCreateReadQueue: Failed to create consumer queue "
-        "from DvrReadBufferQueue[%p].",
-        read_queue);
+        "DvrReadBufferQueue::CreateReadQueue: Failed to create consumer queue "
+        "from producer queue: queue_id=%d.", consumer_queue_->id());
     return -ENOMEM;
   }
 
-  *out_read_queue = new_read_queue.release();
+  *out_read_queue = new DvrReadBufferQueue(std::move(consumer_queue));
   return 0;
 }
 
-int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
-                              DvrReadBuffer* read_buffer, int* out_fence_fd,
-                              void* out_meta, size_t meta_size_bytes) {
-  if (!read_queue || !read_queue->consumer_queue || !read_buffer ||
-      !out_fence_fd || !out_meta) {
-    return -EINVAL;
-  }
-
-  if (meta_size_bytes != read_queue->consumer_queue->metadata_size()) {
+int DvrReadBufferQueue::Dequeue(int timeout, DvrReadBuffer* read_buffer,
+                                int* out_fence_fd, void* out_meta,
+                                size_t meta_size_bytes) {
+  if (meta_size_bytes != consumer_queue_->metadata_size()) {
     ALOGE(
-        "dvrReadBufferQueueDequeue: Invalid metadata size, expected (%zu), "
+        "DvrReadBufferQueue::Dequeue: Invalid metadata size, expected (%zu), "
         "but actual (%zu).",
-        read_queue->consumer_queue->metadata_size(), meta_size_bytes);
+        consumer_queue_->metadata_size(), meta_size_bytes);
     return -EINVAL;
   }
 
   size_t slot;
   pdx::LocalHandle acquire_fence;
-  auto buffer_status = read_queue->consumer_queue->Dequeue(
+  auto buffer_status = consumer_queue_->Dequeue(
       timeout, &slot, out_meta, meta_size_bytes, &acquire_fence);
   if (!buffer_status) {
     ALOGE_IF(buffer_status.error() != ETIMEDOUT,
@@ -201,4 +254,107 @@
   return 0;
 }
 
+void DvrReadBufferQueue::SetBufferAvailableCallback(
+    DvrReadBufferQueueBufferAvailableCallback callback, void* context) {
+  if (callback == nullptr) {
+    consumer_queue_->SetBufferAvailableCallback(nullptr);
+  } else {
+    consumer_queue_->SetBufferAvailableCallback(
+        [callback, context]() { callback(context); });
+  }
+}
+
+void DvrReadBufferQueue::SetBufferRemovedCallback(
+    DvrReadBufferQueueBufferRemovedCallback callback, void* context) {
+  if (callback == nullptr) {
+    consumer_queue_->SetBufferRemovedCallback(nullptr);
+  } else {
+    consumer_queue_->SetBufferRemovedCallback(
+        [callback, context](const std::shared_ptr<BufferHubBuffer>& buffer) {
+          DvrReadBuffer read_buffer{
+              std::static_pointer_cast<BufferConsumer>(buffer)};
+          callback(&read_buffer, context);
+        });
+  }
+}
+
+int DvrReadBufferQueue::HandleEvents() {
+  // TODO(jwcai) Probably should change HandleQueueEvents to return Status.
+  consumer_queue_->HandleQueueEvents();
+  return 0;
+}
+
+void dvrReadBufferQueueDestroy(DvrReadBufferQueue* read_queue) {
+  delete read_queue;
+}
+
+ssize_t dvrReadBufferQueueGetCapacity(DvrReadBufferQueue* read_queue) {
+  if (!read_queue)
+    return -EINVAL;
+
+  return read_queue->capacity();
+}
+
+int dvrReadBufferQueueGetId(DvrReadBufferQueue* read_queue) {
+  if (!read_queue)
+    return -EINVAL;
+
+  return read_queue->id();
+}
+
+int dvrReadBufferQueueGetEventFd(DvrReadBufferQueue* read_queue) {
+  if (!read_queue)
+    return -EINVAL;
+
+  return read_queue->event_fd();
+}
+
+int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
+                                      DvrReadBufferQueue** out_read_queue) {
+  if (!read_queue || !out_read_queue)
+    return -EINVAL;
+
+  return read_queue->CreateReadQueue(out_read_queue);
+}
+
+int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
+                              DvrReadBuffer* read_buffer, int* out_fence_fd,
+                              void* out_meta, size_t meta_size_bytes) {
+  if (!read_queue || !read_buffer || !out_fence_fd)
+    return -EINVAL;
+
+  if (meta_size_bytes != 0 && !out_meta)
+    return -EINVAL;
+
+  return read_queue->Dequeue(timeout, read_buffer, out_fence_fd, out_meta,
+                             meta_size_bytes);
+}
+
+int dvrReadBufferQueueSetBufferAvailableCallback(
+    DvrReadBufferQueue* read_queue,
+    DvrReadBufferQueueBufferAvailableCallback callback, void* context) {
+  if (!read_queue)
+    return -EINVAL;
+
+  read_queue->SetBufferAvailableCallback(callback, context);
+  return 0;
+}
+
+int dvrReadBufferQueueSetBufferRemovedCallback(
+    DvrReadBufferQueue* read_queue,
+    DvrReadBufferQueueBufferRemovedCallback callback, void* context) {
+  if (!read_queue)
+    return -EINVAL;
+
+  read_queue->SetBufferRemovedCallback(callback, context);
+  return 0;
+}
+
+int dvrReadBufferQueueHandleEvents(DvrReadBufferQueue* read_queue) {
+  if (!read_queue)
+    return -EINVAL;
+
+  return read_queue->HandleEvents();
+}
+
 }  // extern "C"
diff --git a/libs/vr/libdvr/dvr_buffer_queue_internal.h b/libs/vr/libdvr/dvr_buffer_queue_internal.h
new file mode 100644
index 0000000..ffbe7a5
--- /dev/null
+++ b/libs/vr/libdvr/dvr_buffer_queue_internal.h
@@ -0,0 +1,68 @@
+#ifndef ANDROID_DVR_BUFFER_QUEUE_INTERNAL_H_
+#define ANDROID_DVR_BUFFER_QUEUE_INTERNAL_H_
+
+#include <gui/Surface.h>
+#include <private/dvr/buffer_hub_queue_client.h>
+#include <sys/cdefs.h>
+
+#include <memory>
+
+struct ANativeWindow;
+
+struct DvrWriteBufferQueue {
+  using ProducerQueue = android::dvr::ProducerQueue;
+
+  // Create a concrete object for DvrWriteBufferQueue.
+  //
+  // @param producer_queue The BufferHub's ProducerQueue that is used to back
+  //     this DvrWriteBufferQueue, must not be NULL.
+  explicit DvrWriteBufferQueue(
+      const std::shared_ptr<ProducerQueue>& producer_queue);
+
+  int id() const { return producer_queue_->id(); }
+  uint32_t width() const { return width_; };
+  uint32_t height() const { return height_; };
+  uint32_t format() const { return format_; };
+  size_t capacity() const { return producer_queue_->capacity(); }
+  const std::shared_ptr<ProducerQueue>& producer_queue() const {
+    return producer_queue_;
+  }
+
+  int GetNativeWindow(ANativeWindow** out_window);
+  int CreateReadQueue(DvrReadBufferQueue** out_read_queue);
+  int Dequeue(int timeout, DvrWriteBuffer* write_buffer, int* out_fence_fd);
+  int ResizeBuffer(uint32_t width, uint32_t height);
+
+ private:
+  std::shared_ptr<ProducerQueue> producer_queue_;
+
+  uint32_t width_;
+  uint32_t height_;
+  uint32_t format_;
+  android::sp<android::Surface> native_window_;
+};
+
+struct DvrReadBufferQueue {
+  using ConsumerQueue = android::dvr::ConsumerQueue;
+
+  explicit DvrReadBufferQueue(
+      const std::shared_ptr<ConsumerQueue>& consumer_queue);
+
+  int id() const { return consumer_queue_->id(); }
+  int event_fd() const { return consumer_queue_->queue_fd(); }
+  size_t capacity() const { return consumer_queue_->capacity(); }
+
+  int CreateReadQueue(DvrReadBufferQueue** out_read_queue);
+  int Dequeue(int timeout, DvrReadBuffer* read_buffer, int* out_fence_fd,
+              void* out_meta, size_t meta_size_bytes);
+  void SetBufferAvailableCallback(
+      DvrReadBufferQueueBufferAvailableCallback callback, void* context);
+  void SetBufferRemovedCallback(
+      DvrReadBufferQueueBufferRemovedCallback callback, void* context);
+  int HandleEvents();
+
+ private:
+  std::shared_ptr<ConsumerQueue> consumer_queue_;
+};
+
+#endif  // ANDROID_DVR_BUFFER_QUEUE_INTERNAL_H_
diff --git a/libs/vr/libdvr/dvr_configuration_data.cpp b/libs/vr/libdvr/dvr_configuration_data.cpp
new file mode 100644
index 0000000..df0d54e
--- /dev/null
+++ b/libs/vr/libdvr/dvr_configuration_data.cpp
@@ -0,0 +1,40 @@
+#include "include/dvr/dvr_configuration_data.h"
+
+#include <private/dvr/display_client.h>
+
+using android::dvr::display::ConfigFileType;
+using android::dvr::display::DisplayClient;
+
+extern "C" {
+
+int dvrConfigurationDataGet(int config_type, uint8_t** data,
+                            size_t* data_size) {
+  if (!data || !data_size) {
+    return -EINVAL;
+  }
+
+  auto client = DisplayClient::Create();
+  if (!client) {
+    ALOGE("dvrGetGlobalBuffer: Failed to create display client!");
+    return -ECOMM;
+  }
+
+  ConfigFileType config_file_type = static_cast<ConfigFileType>(config_type);
+  auto config_data_status =
+      client->GetConfigurationData(config_file_type);
+
+  if (!config_data_status) {
+    return -config_data_status.error();
+  }
+
+  *data_size = config_data_status.get().size();
+  *data = new uint8_t[*data_size];
+  std::copy_n(config_data_status.get().begin(), *data_size, *data);
+  return 0;
+}
+
+void dvrConfigurationDataDestroy(uint8_t* data) {
+  delete[] data;
+}
+
+}  // extern "C"
diff --git a/libs/vr/libdvr/dvr_display_manager.cpp b/libs/vr/libdvr/dvr_display_manager.cpp
index 87636ec..852f9a4 100644
--- a/libs/vr/libdvr/dvr_display_manager.cpp
+++ b/libs/vr/libdvr/dvr_display_manager.cpp
@@ -2,20 +2,19 @@
 
 #include <dvr/dvr_buffer.h>
 #include <pdx/rpc/variant.h>
-#include <private/android/AHardwareBufferHelpers.h>
 #include <private/dvr/buffer_hub_client.h>
 #include <private/dvr/buffer_hub_queue_client.h>
+#include <private/dvr/display_client.h>
 #include <private/dvr/display_manager_client.h>
 
 #include "dvr_internal.h"
+#include "dvr_buffer_queue_internal.h"
 
-using android::AHardwareBuffer_convertToGrallocUsageBits;
 using android::dvr::BufferConsumer;
 using android::dvr::display::DisplayManagerClient;
 using android::dvr::display::SurfaceAttributes;
 using android::dvr::display::SurfaceAttribute;
 using android::dvr::display::SurfaceState;
-using android::dvr::CreateDvrReadBufferQueueFromConsumerQueue;
 using android::pdx::rpc::EmptyVariant;
 
 namespace {
@@ -111,26 +110,6 @@
 
 void dvrDisplayManagerDestroy(DvrDisplayManager* client) { delete client; }
 
-int dvrDisplayManagerSetupNamedBuffer(DvrDisplayManager* client,
-                                      const char* name, size_t size,
-                                      uint64_t usage, DvrBuffer** buffer_out) {
-  if (!client || !name || !buffer_out)
-    return -EINVAL;
-
-  uint64_t gralloc_usage = AHardwareBuffer_convertToGrallocUsageBits(usage);
-
-  auto buffer_status =
-      client->client->SetupNamedBuffer(name, size, gralloc_usage);
-  if (!buffer_status) {
-    ALOGE("dvrDisplayManagerSetupPoseBuffer: Failed to setup named buffer: %s",
-          buffer_status.GetErrorMessage().c_str());
-    return -buffer_status.error();
-  }
-
-  *buffer_out = CreateDvrBufferFromIonBuffer(buffer_status.take());
-  return 0;
-}
-
 int dvrDisplayManagerGetEventFd(DvrDisplayManager* client) {
   if (!client)
     return -EINVAL;
@@ -177,7 +156,7 @@
     return -status.error();
   }
 
-  *queue_out = CreateDvrReadBufferQueueFromConsumerQueue(status.take());
+  *queue_out = new DvrReadBufferQueue(status.take());
   return 0;
 }
 
diff --git a/libs/vr/libdvr/dvr_hardware_composer_client.cpp b/libs/vr/libdvr/dvr_hardware_composer_client.cpp
index d3ae299..4e87cf6 100644
--- a/libs/vr/libdvr/dvr_hardware_composer_client.cpp
+++ b/libs/vr/libdvr/dvr_hardware_composer_client.cpp
@@ -6,7 +6,9 @@
 #include <binder/IServiceManager.h>
 #include <private/android/AHardwareBufferHelpers.h>
 
+#include <functional>
 #include <memory>
+#include <mutex>
 
 struct DvrHwcFrame {
   android::dvr::ComposerView::Frame frame;
@@ -16,10 +18,15 @@
 
 class HwcCallback : public android::dvr::BnVrComposerCallback {
  public:
-  explicit HwcCallback(DvrHwcOnFrameCallback callback,
-                       void* client_state);
+  using CallbackFunction = std::function<int(DvrHwcFrame*)>;
+
+  explicit HwcCallback(const CallbackFunction& callback);
   ~HwcCallback() override;
 
+  // Reset the callback. This needs to be done early to avoid use after free
+  // accesses from binder thread callbacks.
+  void Shutdown();
+
   std::unique_ptr<DvrHwcFrame> DequeueFrame();
 
  private:
@@ -28,26 +35,41 @@
       const android::dvr::ParcelableComposerFrame& frame,
       android::dvr::ParcelableUniqueFd* fence) override;
 
-  DvrHwcOnFrameCallback callback_;
-  void* client_state_;
+  // Protects the |callback_| from uses from multiple threads. During shutdown
+  // there may be in-flight frame update events. In those cases the callback
+  // access needs to be protected otherwise binder threads may access an invalid
+  // callback.
+  std::mutex mutex_;
+  CallbackFunction callback_;
 
   HwcCallback(const HwcCallback&) = delete;
   void operator=(const HwcCallback&) = delete;
 };
 
-HwcCallback::HwcCallback(DvrHwcOnFrameCallback callback, void* client_state)
-    : callback_(callback), client_state_(client_state) {}
+HwcCallback::HwcCallback(const CallbackFunction& callback)
+    : callback_(callback) {}
 
 HwcCallback::~HwcCallback() {}
 
+void HwcCallback::Shutdown() {
+  std::lock_guard<std::mutex> guard(mutex_);
+  callback_ = nullptr;
+}
+
 android::binder::Status HwcCallback::onNewFrame(
     const android::dvr::ParcelableComposerFrame& frame,
     android::dvr::ParcelableUniqueFd* fence) {
+  std::lock_guard<std::mutex> guard(mutex_);
+
+  if (!callback_) {
+    fence->set_fence(android::base::unique_fd());
+    return android::binder::Status::ok();
+  }
+
   std::unique_ptr<DvrHwcFrame> dvr_frame(new DvrHwcFrame());
   dvr_frame->frame = frame.frame();
 
-  fence->set_fence(android::base::unique_fd(callback_(client_state_,
-                                                      dvr_frame.release())));
+  fence->set_fence(android::base::unique_fd(callback_(dvr_frame.release())));
   return android::binder::Status::ok();
 }
 
@@ -67,7 +89,8 @@
   if (!client->composer.get())
     return nullptr;
 
-  client->callback = new HwcCallback(callback, data);
+  client->callback = new HwcCallback(std::bind(callback, data,
+                                               std::placeholders::_1));
   android::binder::Status status = client->composer->registerObserver(
       client->callback);
   if (!status.isOk())
@@ -77,6 +100,13 @@
 }
 
 void dvrHwcClientDestroy(DvrHwcClient* client) {
+  client->composer->clearObserver();
+
+  // NOTE: Deleting DvrHwcClient* isn't enough since DvrHwcClient::callback is a
+  // shared pointer that could be referenced from a binder thread. But the
+  // client callback isn't valid past this calls so that needs to be reset.
+  client->callback->Shutdown();
+
   delete client;
 }
 
diff --git a/libs/vr/libdvr/dvr_internal.h b/libs/vr/libdvr/dvr_internal.h
index 89bef09..28b6c28 100644
--- a/libs/vr/libdvr/dvr_internal.h
+++ b/libs/vr/libdvr/dvr_internal.h
@@ -10,8 +10,6 @@
 typedef struct DvrBuffer DvrBuffer;
 typedef struct DvrReadBuffer DvrReadBuffer;
 typedef struct DvrWriteBuffer DvrWriteBuffer;
-typedef struct DvrWriteBufferQueue DvrWriteBufferQueue;
-typedef struct DvrReadBufferQueue DvrReadBufferQueue;
 
 }  // extern "C"
 
@@ -20,9 +18,7 @@
 
 class BufferProducer;
 class BufferConsumer;
-class ConsumerQueue;
 class IonBuffer;
-class ProducerQueue;
 
 DvrBuffer* CreateDvrBufferFromIonBuffer(
     const std::shared_ptr<IonBuffer>& ion_buffer);
@@ -32,13 +28,6 @@
 DvrWriteBuffer* CreateDvrWriteBufferFromBufferProducer(
     const std::shared_ptr<BufferProducer>& buffer_producer);
 
-DvrReadBufferQueue* CreateDvrReadBufferQueueFromConsumerQueue(
-    const std::shared_ptr<ConsumerQueue>& consumer_queue);
-DvrWriteBufferQueue* CreateDvrWriteBufferQueueFromProducerQueue(
-    const std::shared_ptr<ProducerQueue>& producer_queue);
-ProducerQueue* GetProducerQueueFromDvrWriteBufferQueue(
-    DvrWriteBufferQueue* write_queue);
-
 }  // namespace dvr
 }  // namespace android
 
@@ -56,15 +45,6 @@
   std::shared_ptr<android::dvr::IonBuffer> buffer;
 };
 
-struct DvrWriteBufferQueue {
-  std::shared_ptr<android::dvr::ProducerQueue> producer_queue;
-  ANativeWindow* native_window{nullptr};
-};
-
-struct DvrReadBufferQueue {
-  std::shared_ptr<android::dvr::ConsumerQueue> consumer_queue;
-};
-
 }  // extern "C"
 
 #endif  // ANDROID_DVR_INTERNAL_H_
diff --git a/libs/vr/libdvr/dvr_performance.cpp b/libs/vr/libdvr/dvr_performance.cpp
new file mode 100644
index 0000000..599101f
--- /dev/null
+++ b/libs/vr/libdvr/dvr_performance.cpp
@@ -0,0 +1,18 @@
+#include "include/dvr/dvr_performance.h"
+
+#include <private/dvr/performance_client.h>
+
+using android::dvr::PerformanceClient;
+
+extern "C" {
+
+int dvrPerformanceSetSchedulerPolicy(pid_t task_id,
+                                     const char* scheduler_policy) {
+  int error;
+  if (auto client = PerformanceClient::Create(&error))
+    return client->SetSchedulerPolicy(task_id, scheduler_policy);
+  else
+    return error;
+}
+
+}  // extern "C"
diff --git a/libs/vr/libdvr/dvr_surface.cpp b/libs/vr/libdvr/dvr_surface.cpp
index 67e2ae8..a3a47f1 100644
--- a/libs/vr/libdvr/dvr_surface.cpp
+++ b/libs/vr/libdvr/dvr_surface.cpp
@@ -2,19 +2,33 @@
 
 #include <inttypes.h>
 
+#include <pdx/rpc/variant.h>
+#include <private/android/AHardwareBufferHelpers.h>
 #include <private/dvr/display_client.h>
 
+#include "dvr_buffer_queue_internal.h"
 #include "dvr_internal.h"
 
+using android::AHardwareBuffer_convertToGrallocUsageBits;
 using android::dvr::display::DisplayClient;
 using android::dvr::display::Surface;
 using android::dvr::display::SurfaceAttributes;
 using android::dvr::display::SurfaceAttributeValue;
 using android::dvr::CreateDvrReadBufferFromBufferConsumer;
-using android::dvr::CreateDvrWriteBufferQueueFromProducerQueue;
+using android::pdx::rpc::EmptyVariant;
 
 namespace {
 
+// Sets the Variant |destination| to the target std::array type and copies the C
+// array into it. Unsupported std::array configurations will fail to compile.
+template <typename T, std::size_t N>
+void ArrayCopy(SurfaceAttributeValue* destination, const T (&source)[N]) {
+  using ArrayType = std::array<T, N>;
+  *destination = ArrayType{};
+  std::copy(std::begin(source), std::end(source),
+            std::get<ArrayType>(*destination).begin());
+}
+
 bool ConvertSurfaceAttributes(const DvrSurfaceAttribute* attributes,
                               size_t attribute_count,
                               SurfaceAttributes* surface_attributes,
@@ -29,25 +43,31 @@
         value = attributes[i].value.int64_value;
         break;
       case DVR_SURFACE_ATTRIBUTE_TYPE_BOOL:
-        value = attributes[i].value.bool_value;
+        // bool_value is defined in an extern "C" block, which makes it look
+        // like an int to C++. Use a cast to assign the correct type to the
+        // Variant type SurfaceAttributeValue.
+        value = static_cast<bool>(attributes[i].value.bool_value);
         break;
       case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT:
         value = attributes[i].value.float_value;
         break;
       case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT2:
-        value = attributes[i].value.float2_value;
+        ArrayCopy(&value, attributes[i].value.float2_value);
         break;
       case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT3:
-        value = attributes[i].value.float3_value;
+        ArrayCopy(&value, attributes[i].value.float3_value);
         break;
       case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT4:
-        value = attributes[i].value.float4_value;
+        ArrayCopy(&value, attributes[i].value.float4_value);
         break;
       case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT8:
-        value = attributes[i].value.float8_value;
+        ArrayCopy(&value, attributes[i].value.float8_value);
         break;
       case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT16:
-        value = attributes[i].value.float16_value;
+        ArrayCopy(&value, attributes[i].value.float16_value);
+        break;
+      case DVR_SURFACE_ATTRIBUTE_TYPE_NONE:
+        value = EmptyVariant{};
         break;
       default:
         *error_index = i;
@@ -134,7 +154,7 @@
 int dvrSurfaceCreateWriteBufferQueue(DvrSurface* surface, uint32_t width,
                                      uint32_t height, uint32_t format,
                                      uint32_t layer_count, uint64_t usage,
-                                     size_t capacity,
+                                     size_t capacity, size_t metadata_size,
                                      DvrWriteBufferQueue** out_writer) {
   if (surface == nullptr || out_writer == nullptr) {
     ALOGE(
@@ -144,39 +164,115 @@
     return -EINVAL;
   }
 
-  auto status = surface->surface->CreateQueue(width, height, layer_count,
-                                              format, usage, capacity);
+  auto status = surface->surface->CreateQueue(
+      width, height, layer_count, format, usage, capacity, metadata_size);
   if (!status) {
     ALOGE("dvrSurfaceCreateWriteBufferQueue: Failed to create queue: %s",
           status.GetErrorMessage().c_str());
     return -status.error();
   }
 
-  *out_writer = CreateDvrWriteBufferQueueFromProducerQueue(status.take());
+  *out_writer = new DvrWriteBufferQueue(status.take());
   return 0;
 }
 
-int dvrGetNamedBuffer(const char* name, DvrBuffer** out_buffer) {
-  auto client = DisplayClient::Create();
-  if (!client) {
-    ALOGE("dvrGetNamedBuffer: Failed to create display client!");
-    return -ECOMM;
-  }
-
-  if (out_buffer == nullptr || name == nullptr) {
-    ALOGE("dvrGetNamedBuffer: Invalid inputs: name=%p, out_buffer=%p.", name,
-          out_buffer);
+int dvrSetupGlobalBuffer(DvrGlobalBufferKey key, size_t size, uint64_t usage,
+                         DvrBuffer** buffer_out) {
+  if (!buffer_out)
     return -EINVAL;
+
+  int error;
+  auto client = DisplayClient::Create(&error);
+  if (!client) {
+    ALOGE("dvrSetupGlobalBuffer: Failed to create display client: %s",
+          strerror(-error));
+    return error;
   }
 
-  auto status = client->GetNamedBuffer(name);
+  uint64_t gralloc_usage = AHardwareBuffer_convertToGrallocUsageBits(usage);
+
+  auto buffer_status = client->SetupGlobalBuffer(key, size, gralloc_usage);
+  if (!buffer_status) {
+    ALOGE("dvrSetupGlobalBuffer: Failed to setup global buffer: %s",
+          buffer_status.GetErrorMessage().c_str());
+    return -buffer_status.error();
+  }
+
+  *buffer_out = CreateDvrBufferFromIonBuffer(buffer_status.take());
+  return 0;
+}
+
+int dvrDeleteGlobalBuffer(DvrGlobalBufferKey key) {
+  int error;
+  auto client = DisplayClient::Create(&error);
+  if (!client) {
+    ALOGE("dvrDeleteGlobalBuffer: Failed to create display client: %s",
+          strerror(-error));
+    return error;
+  }
+
+  auto buffer_status = client->DeleteGlobalBuffer(key);
+  if (!buffer_status) {
+    ALOGE("dvrDeleteGlobalBuffer: Failed to delete named buffer: %s",
+          buffer_status.GetErrorMessage().c_str());
+    return -buffer_status.error();
+  }
+
+  return 0;
+}
+
+int dvrGetGlobalBuffer(DvrGlobalBufferKey key, DvrBuffer** out_buffer) {
+  if (!out_buffer)
+    return -EINVAL;
+
+  int error;
+  auto client = DisplayClient::Create(&error);
+  if (!client) {
+    ALOGE("dvrGetGlobalBuffer: Failed to create display client: %s",
+          strerror(-error));
+    return error;
+  }
+
+  auto status = client->GetGlobalBuffer(key);
   if (!status) {
-    ALOGE("dvrGetNamedBuffer: Failed to find named buffer name=%s: %s", name,
-          status.GetErrorMessage().c_str());
     return -status.error();
   }
   *out_buffer = CreateDvrBufferFromIonBuffer(status.take());
   return 0;
 }
 
+int dvrGetNativeDisplayMetrics(size_t sizeof_metrics,
+                               DvrNativeDisplayMetrics* metrics) {
+  ALOGE_IF(sizeof_metrics != sizeof(DvrNativeDisplayMetrics),
+           "dvrGetNativeDisplayMetrics: metrics struct mismatch, your dvr api "
+           "header is out of date.");
+
+  auto client = DisplayClient::Create();
+  if (!client) {
+    ALOGE("dvrGetNativeDisplayMetrics: Failed to create display client!");
+    return -ECOMM;
+  }
+
+  if (metrics == nullptr) {
+    ALOGE("dvrGetNativeDisplayMetrics: output metrics buffer must be non-null");
+    return -EINVAL;
+  }
+
+  auto status = client->GetDisplayMetrics();
+
+  if (!status) {
+    return -status.error();
+  }
+
+  if (sizeof_metrics >= 20) {
+    metrics->display_width = status.get().display_width;
+    metrics->display_height = status.get().display_height;
+    metrics->display_x_dpi = status.get().display_x_dpi;
+    metrics->display_y_dpi = status.get().display_y_dpi;
+    metrics->vsync_period_ns = status.get().vsync_period_ns;
+  }
+
+  return 0;
+}
+
 }  // extern "C"
diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h
index 8a203e0..d0dbd8d 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api.h
@@ -4,12 +4,16 @@
 #include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
-#include <sys/cdefs.h>
 #include <unistd.h>
+#include <cstdio>
 
-#include <dvr/dvr_hardware_composer_defs.h>
+#include <dvr/dvr_display_types.h>
+#include <dvr/dvr_hardware_composer_types.h>
+#include <dvr/dvr_pose.h>
 
-__BEGIN_DECLS
+#ifdef __cplusplus
+extern "C" {
+#endif
 
 typedef struct ANativeWindow ANativeWindow;
 
@@ -18,7 +22,7 @@
 typedef uint64_t DvrSurfaceUpdateFlags;
 typedef struct DvrDisplayManager DvrDisplayManager;
 typedef struct DvrSurfaceState DvrSurfaceState;
-typedef struct DvrPose DvrPose;
+typedef struct DvrPoseClient DvrPoseClient;
 typedef struct DvrVSyncClient DvrVSyncClient;
 typedef struct DvrVirtualTouchpad DvrVirtualTouchpad;
 
@@ -33,19 +37,44 @@
 typedef struct DvrSurface DvrSurface;
 typedef uint64_t DvrSurfaceAttributeType;
 typedef int32_t DvrSurfaceAttributeKey;
+typedef int32_t DvrGlobalBufferKey;
 
 typedef struct DvrSurfaceAttributeValue DvrSurfaceAttributeValue;
 typedef struct DvrSurfaceAttribute DvrSurfaceAttribute;
 
+// Note: To avoid breaking others during active development, only modify this
+// struct by appending elements to the end.
+// If you do feel we should to re-arrange or remove elements, please make a
+// note of it, and wait until we're about to finalize for an API release to do
+// so.
+typedef struct DvrNativeDisplayMetrics {
+  uint32_t display_width;
+  uint32_t display_height;
+  uint32_t display_x_dpi;
+  uint32_t display_y_dpi;
+  uint32_t vsync_period_ns;
+} DvrNativeDisplayMetrics;
+
+// native_handle contains the fds for the underlying ION allocations inside
+// the gralloc buffer. This is needed temporarily while GPU vendors work on
+// better support for AHardwareBuffer via glBindSharedBuffer APIs. See
+// b/37207909. For now we can declare the native_handle struct where it is
+// used for GPU late latching. See cutils/native_handle.h for the struct layout.
 struct native_handle;
 
+// Device metrics data type enums.
+enum {
+  // Request the device lens metrics protobuf. This matches cardboard protos.
+  DVR_CONFIGURATION_DATA_LENS_METRICS = 0,
+  // Request the device metrics protobuf.
+  DVR_CONFIGURATION_DATA_DEVICE_METRICS = 1,
+  // Request the per device configuration data file.
+  DVR_CONFIGURATION_DATA_DEVICE_CONFIG = 2,
+};
+
 // dvr_display_manager.h
 typedef int (*DvrDisplayManagerCreatePtr)(DvrDisplayManager** client_out);
 typedef void (*DvrDisplayManagerDestroyPtr)(DvrDisplayManager* client);
-typedef int (*DvrDisplayManagerSetupNamedBufferPtr)(DvrDisplayManager* client,
-                                                    const char* name,
-                                                    size_t size, uint64_t usage,
-                                                    DvrBuffer** buffer_out);
 typedef int (*DvrDisplayManagerGetEventFdPtr)(DvrDisplayManager* client);
 typedef int (*DvrDisplayManagerTranslateEpollEventMaskPtr)(
     DvrDisplayManager* client, int in_events, int* out_events);
@@ -54,6 +83,9 @@
 typedef int (*DvrDisplayManagerGetReadBufferQueuePtr)(
     DvrDisplayManager* client, int surface_id, int queue_id,
     DvrReadBufferQueue** queue_out);
+typedef int (*DvrConfigurationDataGetPtr)(int config_type, uint8_t** data,
+                                          size_t* data_size);
+typedef void (*DvrConfigurationDataDestroyPtr)(uint8_t* data);
 typedef int (*DvrSurfaceStateCreatePtr)(DvrSurfaceState** surface_state);
 typedef void (*DvrSurfaceStateDestroyPtr)(DvrSurfaceState* surface_state);
 typedef int (*DvrSurfaceStateGetSurfaceCountPtr)(DvrSurfaceState* surface_state,
@@ -122,6 +154,7 @@
 typedef void (*DvrBufferDestroyPtr)(DvrBuffer* buffer);
 typedef int (*DvrBufferGetAHardwareBufferPtr)(
     DvrBuffer* buffer, AHardwareBuffer** hardware_buffer);
+typedef int (*DvrBufferGlobalLayoutVersionGetPtr)();
 typedef const struct native_handle* (*DvrBufferGetNativeHandlePtr)(
     DvrBuffer* buffer);
 
@@ -138,10 +171,13 @@
                                              int timeout,
                                              DvrWriteBuffer* out_buffer,
                                              int* out_fence_fd);
+typedef int (*DvrWriteBufferQueueResizeBufferPtr)(
+    DvrWriteBufferQueue* write_queue, uint32_t width, uint32_t height);
 typedef void (*DvrReadBufferQueueDestroyPtr)(DvrReadBufferQueue* read_queue);
 typedef ssize_t (*DvrReadBufferQueueGetCapacityPtr)(
     DvrReadBufferQueue* read_queue);
 typedef int (*DvrReadBufferQueueGetIdPtr)(DvrReadBufferQueue* read_queue);
+typedef int (*DvrReadBufferQueueGetEventFdPtr)(DvrReadBufferQueue* read_queue);
 typedef int (*DvrReadBufferQueueCreateReadQueuePtr)(
     DvrReadBufferQueue* read_queue, DvrReadBufferQueue** out_read_queue);
 typedef int (*DvrReadBufferQueueDequeuePtr)(DvrReadBufferQueue* read_queue,
@@ -149,9 +185,24 @@
                                             DvrReadBuffer* out_buffer,
                                             int* out_fence_fd, void* out_meta,
                                             size_t meta_size_bytes);
+typedef void (*DvrReadBufferQueueBufferAvailableCallback)(void* context);
+typedef int (*DvrReadBufferQueueSetBufferAvailableCallbackPtr)(
+    DvrReadBufferQueue* read_queue,
+    DvrReadBufferQueueBufferAvailableCallback callback, void* context);
+typedef void (*DvrReadBufferQueueBufferRemovedCallback)(DvrReadBuffer* buffer,
+                                                        void* context);
+typedef int (*DvrReadBufferQueueSetBufferRemovedCallbackPtr)(
+    DvrReadBufferQueue* read_queue,
+    DvrReadBufferQueueBufferRemovedCallback callback, void* context);
+typedef int (*DvrReadBufferQueueHandleEventsPtr)(
+    DvrReadBufferQueue* read_queue);
 
 // dvr_surface.h
-typedef int (*DvrGetNamedBufferPtr)(const char* name, DvrBuffer** out_buffer);
+typedef int (*DvrSetupGlobalBufferPtr)(DvrGlobalBufferKey key, size_t size,
+                                       uint64_t usage, DvrBuffer** buffer_out);
+typedef int (*DvrDeleteGlobalBufferPtr)(DvrGlobalBufferKey key);
+typedef int (*DvrGetGlobalBufferPtr)(DvrGlobalBufferKey key,
+                                     DvrBuffer** out_buffer);
 typedef int (*DvrSurfaceCreatePtr)(const DvrSurfaceAttribute* attributes,
                                    size_t attribute_count,
                                    DvrSurface** surface_out);
@@ -162,10 +213,12 @@
                                           size_t attribute_count);
 typedef int (*DvrSurfaceCreateWriteBufferQueuePtr)(
     DvrSurface* surface, uint32_t width, uint32_t height, uint32_t format,
-    uint32_t layer_count, uint64_t usage, size_t capacity,
+    uint32_t layer_count, uint64_t usage, size_t capacity, size_t metadata_size,
     DvrWriteBufferQueue** queue_out);
+typedef int (*DvrGetNativeDisplayMetricsPtr)(size_t sizeof_metrics,
+                                             DvrNativeDisplayMetrics* metrics);
 
-// vsync_client_api.h
+// dvr_vsync.h
 typedef int (*DvrVSyncClientCreatePtr)(DvrVSyncClient** client_out);
 typedef void (*DvrVSyncClientDestroyPtr)(DvrVSyncClient* client);
 typedef int (*DvrVSyncClientGetSchedInfoPtr)(DvrVSyncClient* client,
@@ -173,18 +226,27 @@
                                              int64_t* next_timestamp_ns,
                                              uint32_t* next_vsync_count);
 
-// pose_client.h
-typedef DvrPose* (*DvrPoseCreatePtr)(void);
-typedef void (*DvrPoseDestroyPtr)(DvrPose* client);
-typedef int (*DvrPoseGetPtr)(DvrPose* client, uint32_t vsync_count,
-                             DvrPoseAsync* out_pose);
-typedef uint32_t (*DvrPoseGetVsyncCountPtr)(DvrPose* client);
-typedef int (*DvrPoseGetControllerPtr)(DvrPose* client, int32_t controller_id,
-                                       uint32_t vsync_count,
-                                       DvrPoseAsync* out_pose);
+// libs/vr/libvrsensor/include/dvr/pose_client.h
+typedef DvrPoseClient* (*DvrPoseClientCreatePtr)();
+typedef void (*DvrPoseClientDestroyPtr)(DvrPoseClient* client);
+typedef int (*DvrPoseClientGetPtr)(DvrPoseClient* client, uint32_t vsync_count,
+                                   DvrPoseAsync* out_pose);
+typedef uint32_t (*DvrPoseClientGetVsyncCountPtr)(DvrPoseClient* client);
+typedef int (*DvrPoseClientGetControllerPtr)(DvrPoseClient* client,
+                                             int32_t controller_id,
+                                             uint32_t vsync_count,
+                                             DvrPoseAsync* out_pose);
+typedef int (*DvrPoseClientSensorsEnablePtr)(DvrPoseClient* client,
+                                             bool enabled);
 
-// virtual_touchpad_client.h
-typedef DvrVirtualTouchpad* (*DvrVirtualTouchpadCreatePtr)(void);
+// services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h
+
+// Touchpad IDs for *Touch*() and *ButtonState*() calls.
+enum {
+  DVR_VIRTUAL_TOUCHPAD_PRIMARY = 0,
+  DVR_VIRTUAL_TOUCHPAD_VIRTUAL = 1,
+};
+typedef DvrVirtualTouchpad* (*DvrVirtualTouchpadCreatePtr)();
 typedef void (*DvrVirtualTouchpadDestroyPtr)(DvrVirtualTouchpad* client);
 typedef int (*DvrVirtualTouchpadAttachPtr)(DvrVirtualTouchpad* client);
 typedef int (*DvrVirtualTouchpadDetachPtr)(DvrVirtualTouchpad* client);
@@ -193,6 +255,8 @@
                                           float pressure);
 typedef int (*DvrVirtualTouchpadButtonStatePtr)(DvrVirtualTouchpad* client,
                                                 int touchpad, int buttons);
+typedef int (*DvrVirtualTouchpadScrollPtr)(DvrVirtualTouchpad* client,
+                                           int touchpad, float x, float y);
 
 // dvr_hardware_composer_client.h
 typedef struct DvrHwcClient DvrHwcClient;
@@ -260,6 +324,10 @@
                                                            size_t layer_index,
                                                            size_t index);
 
+// dvr_performance.h
+typedef int (*DvrPerformanceSetSchedulerPolicyPtr)(
+    pid_t task_id, const char* scheduler_policy);
+
 // The buffer metadata that an Android Surface (a.k.a. ANativeWindow)
 // will populate. A DvrWriteBufferQueue must be created with this metadata iff
 // ANativeWindow access is needed. Please do not remove, modify, or reorder
@@ -298,7 +366,6 @@
 // Defines an API entry for V1 (no version suffix).
 #define DVR_V1_API_ENTRY(name) Dvr##name##Ptr name
 
-// Include file with API entries.
 #include "dvr_api_entries.h"
 
 // Undefine macro definitions to play nice with Google3 style rules.
@@ -307,6 +374,8 @@
 
 int dvrGetApi(void* api, size_t struct_size, int version);
 
-__END_DECLS
+#ifdef __cplusplus
+}  // extern "C"
+#endif
 
 #endif  // ANDROID_DVR_API_H_
diff --git a/libs/vr/libdvr/include/dvr/dvr_api_entries.h b/libs/vr/libdvr/include/dvr/dvr_api_entries.h
index 09568fd..72e0f67 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api_entries.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api_entries.h
@@ -8,14 +8,16 @@
 #error Do not include this header directly.
 #endif
 
+// Do not delete this line: BEGIN CODEGEN OUTPUT
 // Display manager client
 DVR_V1_API_ENTRY(DisplayManagerCreate);
 DVR_V1_API_ENTRY(DisplayManagerDestroy);
-DVR_V1_API_ENTRY(DisplayManagerSetupNamedBuffer);
 DVR_V1_API_ENTRY(DisplayManagerGetEventFd);
 DVR_V1_API_ENTRY(DisplayManagerTranslateEpollEventMask);
 DVR_V1_API_ENTRY(DisplayManagerGetSurfaceState);
 DVR_V1_API_ENTRY(DisplayManagerGetReadBufferQueue);
+DVR_V1_API_ENTRY(ConfigurationDataGet);
+DVR_V1_API_ENTRY(ConfigurationDataDestroy);
 DVR_V1_API_ENTRY(SurfaceStateCreate);
 DVR_V1_API_ENTRY(SurfaceStateDestroy);
 DVR_V1_API_ENTRY(SurfaceStateGetSurfaceCount);
@@ -57,6 +59,7 @@
 DVR_V1_API_ENTRY(BufferDestroy);
 DVR_V1_API_ENTRY(BufferGetAHardwareBuffer);
 DVR_V1_API_ENTRY(BufferGetNativeHandle);
+DVR_V1_API_ENTRY(BufferGlobalLayoutVersionGet);
 
 // Write buffer queue
 DVR_V1_API_ENTRY(WriteBufferQueueDestroy);
@@ -65,6 +68,7 @@
 DVR_V1_API_ENTRY(WriteBufferQueueGetExternalSurface);
 DVR_V1_API_ENTRY(WriteBufferQueueCreateReadQueue);
 DVR_V1_API_ENTRY(WriteBufferQueueDequeue);
+DVR_V1_API_ENTRY(WriteBufferQueueResizeBuffer);
 
 // Read buffer queue
 DVR_V1_API_ENTRY(ReadBufferQueueDestroy);
@@ -72,6 +76,9 @@
 DVR_V1_API_ENTRY(ReadBufferQueueGetId);
 DVR_V1_API_ENTRY(ReadBufferQueueCreateReadQueue);
 DVR_V1_API_ENTRY(ReadBufferQueueDequeue);
+DVR_V1_API_ENTRY(ReadBufferQueueSetBufferAvailableCallback);
+DVR_V1_API_ENTRY(ReadBufferQueueSetBufferRemovedCallback);
+DVR_V1_API_ENTRY(ReadBufferQueueHandleEvents);
 
 // V-Sync client
 DVR_V1_API_ENTRY(VSyncClientCreate);
@@ -84,14 +91,16 @@
 DVR_V1_API_ENTRY(SurfaceGetId);
 DVR_V1_API_ENTRY(SurfaceSetAttributes);
 DVR_V1_API_ENTRY(SurfaceCreateWriteBufferQueue);
-DVR_V1_API_ENTRY(GetNamedBuffer);
+DVR_V1_API_ENTRY(SetupGlobalBuffer);
+DVR_V1_API_ENTRY(DeleteGlobalBuffer);
+DVR_V1_API_ENTRY(GetGlobalBuffer);
 
 // Pose client
-DVR_V1_API_ENTRY(PoseCreate);
-DVR_V1_API_ENTRY(PoseDestroy);
-DVR_V1_API_ENTRY(PoseGet);
-DVR_V1_API_ENTRY(PoseGetVsyncCount);
-DVR_V1_API_ENTRY(PoseGetController);
+DVR_V1_API_ENTRY(PoseClientCreate);
+DVR_V1_API_ENTRY(PoseClientDestroy);
+DVR_V1_API_ENTRY(PoseClientGet);
+DVR_V1_API_ENTRY(PoseClientGetVsyncCount);
+DVR_V1_API_ENTRY(PoseClientGetController);
 
 // Virtual touchpad client
 DVR_V1_API_ENTRY(VirtualTouchpadCreate);
@@ -133,3 +142,21 @@
 DVR_V1_API_ENTRY(HwcFrameGetLayerVisibleRegion);
 DVR_V1_API_ENTRY(HwcFrameGetLayerNumDamagedRegions);
 DVR_V1_API_ENTRY(HwcFrameGetLayerDamagedRegion);
+
+// New entries added at the end to allow the DVR platform library API
+// to be updated before updating VrCore.
+
+// Virtual touchpad client
+DVR_V1_API_ENTRY(VirtualTouchpadScroll);
+
+// Read the native display metrics from the hardware composer
+DVR_V1_API_ENTRY(GetNativeDisplayMetrics);
+
+// Performance
+DVR_V1_API_ENTRY(PerformanceSetSchedulerPolicy);
+
+// Pose client
+DVR_V1_API_ENTRY(PoseClientSensorsEnable);
+
+// Read buffer queue
+DVR_V1_API_ENTRY(ReadBufferQueueGetEventFd);
diff --git a/libs/vr/libdvr/include/dvr/dvr_buffer.h b/libs/vr/libdvr/include/dvr/dvr_buffer.h
index af55698..935a7b2 100644
--- a/libs/vr/libdvr/include/dvr/dvr_buffer.h
+++ b/libs/vr/libdvr/include/dvr/dvr_buffer.h
@@ -95,6 +95,9 @@
 int dvrBufferGetAHardwareBuffer(DvrBuffer* buffer,
                                 AHardwareBuffer** hardware_buffer);
 
+// Retrieve the shared buffer layout version defined in dvr_shared_buffers.h.
+int dvrBufferGlobalLayoutVersionGet();
+
 // TODO(eieio): Switch to return int and take an out parameter for the native
 // handle.
 const struct native_handle* dvrBufferGetNativeHandle(DvrBuffer* buffer);
diff --git a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
index dd669dc..e2127f8 100644
--- a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
+++ b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
@@ -12,33 +12,191 @@
 typedef struct DvrWriteBufferQueue DvrWriteBufferQueue;
 typedef struct DvrReadBufferQueue DvrReadBufferQueue;
 
-// WriteBufferQueue
+// Destroy a write buffer queue.
+//
+// @param write_queue The DvrWriteBufferQueue of interest.
 void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue);
+
+// Get the total number of buffers in a write buffer queue.
+//
+// @param write_queue The DvrWriteBufferQueue of interest.
+// @return The capacity on success; or negative error code.
 ssize_t dvrWriteBufferQueueGetCapacity(DvrWriteBufferQueue* write_queue);
+
+// Get the system unique queue id of a write buffer queue.
+//
+// @param write_queue The DvrWriteBufferQueue of interest.
+// @return Queue id on success; or negative error code.
 int dvrWriteBufferQueueGetId(DvrWriteBufferQueue* write_queue);
 
-// Returns ANativeWindow. Can be casted to a Java Surface using
-// ANativeWindow_toSurface NDK API. Note that this method does not acquire an
-// additional reference to the ANativeWindow returned, don't call
-// ANativeWindow_release on it.
+// Gets an ANativeWindow backed by the DvrWriteBufferQueue
+//
+// Can be casted to a Java Surface using ANativeWindow_toSurface NDK API. Note
+// that the native window is lazily created at the first time |GetNativeWindow|
+// is called, and the created ANativeWindow will be cached so that multiple
+// calls to this method will return the same object. Also note that this method
+// does not acquire an additional reference to the ANativeWindow returned, don't
+// call ANativeWindow_release on it.
+//
+// @param write_queue The DvrWriteBufferQueue of interest.
+// @param out_window The pointer of an ANativeWindow will be filled here if
+//     the method call succeeds.
+// @return Zero on success; or -EINVAL if this DvrWriteBufferQueue does not
+//     support being used as an android Surface.
 int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
                                           ANativeWindow** out_window);
 
+// Create a read buffer queue from an existing write buffer queue.
+//
+// @param write_queue The DvrWriteBufferQueue of interest.
+// @param out_read_queue The pointer of a DvrReadBufferQueue will be filled here
+//     if the method call succeeds.
+// @return Zero on success, or negative error code.
 int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue,
                                        DvrReadBufferQueue** out_read_queue);
+
+// Dequeue a buffer to write into.
+//
+// @param write_queue The DvrWriteBufferQueue of interest.
+// @param timeout Specifies the number of milliseconds that the method will
+//     block. Specifying a timeout of -1 causes it to block indefinitely,
+//     while specifying a timeout equal to zero cause it to return immediately,
+//     even if no buffers are available.
+// @param out_buffer A targeting DvrWriteBuffer object to hold the output of the
+//     dequeue operation. Must be created by |dvrWriteBufferCreateEmpty|.
+// @param out_fence_fd A sync fence fd defined in NDK's sync.h API, which
+//     signals the release of underlying buffer. The producer should wait until
+//     this fence clears before writing data into it.
+// @return Zero on success, or negative error code.
 int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout,
                                DvrWriteBuffer* out_buffer, int* out_fence_fd);
 
-// ReadeBufferQueue
+// Overrides buffer dimension with new width and height.
+//
+// After the call successfully returns, each |dvrWriteBufferQueueDequeue| call
+// will return buffer with newly assigned |width| and |height|. When necessary,
+// old buffer will be removed from the buffer queue and replaced with new buffer
+// matching the new buffer size.
+//
+// @param write_queue The DvrWriteBufferQueue of interest.
+// @param width Desired width, cannot be Zero.
+// @param height Desired height, cannot be Zero.
+// @return Zero on success, or negative error code.
+int dvrWriteBufferQueueResizeBuffer(DvrWriteBufferQueue* write_queue,
+                                    uint32_t width, uint32_t height);
+
+// Destroy a read buffer queue.
+//
+// @param read_queue The DvrReadBufferQueue of interest.
 void dvrReadBufferQueueDestroy(DvrReadBufferQueue* read_queue);
+
+// Get the total number of buffers in a read buffer queue.
+//
+// @param read_queue The DvrReadBufferQueue of interest.
+// @return The capacity on success; or negative error code.
 ssize_t dvrReadBufferQueueGetCapacity(DvrReadBufferQueue* read_queue);
+
+// Get the system unique queue id of a read buffer queue.
+//
+// @param read_queue The DvrReadBufferQueue of interest.
+// @return Queue id on success; or negative error code.
 int dvrReadBufferQueueGetId(DvrReadBufferQueue* read_queue);
+
+// Get the event fd that signals when queue updates occur.
+//
+// Use ReadBufferQueueHandleEvents to trigger registered event callbacks.
+//
+// @param read_queue The DvrReadBufferQueue of interest.
+// @return Fd on success; or negative error code.
+int dvrReadBufferQueueGetEventFd(DvrReadBufferQueue* read_queue);
+
+// Create a read buffer queue from an existing read buffer queue.
+//
+// @param read_queue The DvrReadBufferQueue of interest.
+// @param out_read_queue The pointer of a DvrReadBufferQueue will be filled here
+//     if the method call succeeds.
+// @return Zero on success, or negative error code.
 int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
                                       DvrReadBufferQueue** out_read_queue);
+
+// Dequeue a buffer to read from.
+//
+// @param read_queue The DvrReadBufferQueue of interest.
+// @param timeout Specifies the number of milliseconds that the method will
+//     block. Specifying a timeout of -1 causes it to block indefinitely,
+//     while specifying a timeout equal to zero cause it to return immediately,
+//     even if no buffers are available.
+// @param out_buffer A targeting DvrReadBuffer object to hold the output of the
+//     dequeue operation. Must be created by |dvrReadBufferCreateEmpty|.
+// @param out_fence_fd A sync fence fd defined in NDK's sync.h API, which
+//     signals the release of underlying buffer. The consumer should wait until
+//     this fence clears before reading data from it.
+// @param out_meta The memory area where a metadata object will be filled.
+//     Can be nullptr iff |meta_size_bytes| is zero (i.e., there is no
+//     metadata).
+// @param meta_size_bytes Size of the metadata object caller expects. If it
+//     doesn't match the size of actually metadata transported by the buffer
+//     queue, the method returns -EINVAL.
+// @return Zero on success, or negative error code.
 int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
                               DvrReadBuffer* out_buffer, int* out_fence_fd,
                               void* out_meta, size_t meta_size_bytes);
 
+// Callback function which will be called when a buffer is avaiable.
+//
+// Note that there is no guarantee of thread safety and on which thread the
+// callback will be fired.
+//
+// @param context User provided opaque pointer.
+typedef void (*DvrReadBufferQueueBufferAvailableCallback)(void* context);
+
+// Set buffer avaiable callback.
+//
+// @param read_queue The DvrReadBufferQueue of interest.
+// @param callback The callback function. Set this to NULL if caller no longer
+//     needs to listen to new buffer available events.
+// @param context User provided opaque pointer, will be passed back during
+//     callback. The caller is responsible for ensuring the validity of the
+//     context through the life cycle of the DvrReadBufferQueue.
+// @return Zero on success, or negative error code.
+int dvrReadBufferQueueSetBufferAvailableCallback(
+    DvrReadBufferQueue* read_queue,
+    DvrReadBufferQueueBufferAvailableCallback callback, void* context);
+
+// Callback function which will be called when a buffer is about to be removed.
+//
+// Note that there is no guarantee of thread safety and on which thread the
+// callback will be fired.
+//
+// @param buffer The buffer being removed. Once the callbacks returns, this
+//     buffer will be dereferenced from the buffer queue. If user has ever
+//     cached other DvrReadBuffer/AHardwareBuffer/EglImageKHR objects derived
+//     from this buffer, it's the user's responsibility to clean them up.
+//     Note that the ownership of the read buffer is not passed to this
+//     callback, so it should call dvrReadBufferDestroy on the buffer.
+// @param context User provided opaque pointer.
+typedef void (*DvrReadBufferQueueBufferRemovedCallback)(DvrReadBuffer* buffer,
+                                                        void* context);
+
+// Set buffer removed callback.
+//
+// @param read_queue The DvrReadBufferQueue of interest.
+// @param callback The callback function. Set this to NULL if caller no longer
+//     needs to listen to buffer removed events.
+// @param context User provided opaque pointer, will be passed back during
+//     callback. The caller is responsible for ensuring the validity of the
+//     context through the life cycle of the DvrReadBufferQueue.
+// @return Zero on success, or negative error code.
+int dvrReadBufferQueueSetBufferRemovedCallback(
+    DvrReadBufferQueue* read_queue,
+    DvrReadBufferQueueBufferRemovedCallback callback, void* context);
+
+// Handle all pending events on the read queue.
+//
+// @param read_queue The DvrReadBufferQueue of interest.
+// @return Zero on success, or negative error code.
+int dvrReadBufferQueueHandleEvents(DvrReadBufferQueue* read_queue);
+
 __END_DECLS
 
 #endif  // ANDROID_DVR_BUFFER_QUEUE_H_
diff --git a/libs/vr/libdvr/include/dvr/dvr_config.h b/libs/vr/libdvr/include/dvr/dvr_config.h
new file mode 100644
index 0000000..3d2c066
--- /dev/null
+++ b/libs/vr/libdvr/include/dvr/dvr_config.h
@@ -0,0 +1,34 @@
+#ifndef ANDROID_DVR_CONFIG_H
+#define ANDROID_DVR_CONFIG_H
+
+// This header is shared by VrCore and Android and must be kept in sync.
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+// This is a shared memory buffer for passing config data from VrCore to
+// libvrflinger in SurfaceFlinger.
+struct __attribute__((packed, aligned(16))) DvrConfig {
+  // Offset before vsync to submit frames to hardware composer.
+  int32_t frame_post_offset_ns{4000000};
+
+  // If the number of pending fences goes over this count at the point when we
+  // are about to submit a new frame to HWC, we will drop the frame. This
+  // should be a signal that the display driver has begun queuing frames. Note
+  // that with smart displays (with RAM), the fence is signaled earlier than
+  // the next vsync, at the point when the DMA to the display completes.
+  // Currently we use a smart display and the EDS timing coincides with zero
+  // pending fences, so this is 0.
+  int32_t allowed_pending_fence_count{0};
+
+  // New fields should always be added to the end for backwards compat.
+
+  // Reserved padding to 16 bytes.
+  uint8_t pad[8];
+};
+
+__END_DECLS
+
+#endif  // ANDROID_DVR_CONFIG_H
diff --git a/libs/vr/libdvr/include/dvr/dvr_configuration_data.h b/libs/vr/libdvr/include/dvr/dvr_configuration_data.h
new file mode 100644
index 0000000..22a509f
--- /dev/null
+++ b/libs/vr/libdvr/include/dvr/dvr_configuration_data.h
@@ -0,0 +1,24 @@
+#ifndef DVR_CONFIGURATION_DATA_H_
+#define DVR_CONFIGURATION_DATA_H_
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+#include <dvr/dvr_display_types.h>
+#include <dvr/dvr_surface.h>
+
+__BEGIN_DECLS
+
+// Loads device configuration data of DVR_CONFIGURATION_DATA_*.
+// @return 0 on success. Otherwise returns a negative error value.
+int dvrConfigurationDataGet(int config_type,
+                            uint8_t** data, size_t* data_size);
+
+// Destroy the configuration data returned from dvrGetConfigurationData.
+void dvrConfigurationDataDestroy(uint8_t* data);
+
+__END_DECLS
+
+#endif  // DVR_CONFIGURATION_DATA_H_
diff --git a/libs/vr/libdvr/include/dvr/dvr_display_manager.h b/libs/vr/libdvr/include/dvr/dvr_display_manager.h
index d5aef8b..f910d61 100644
--- a/libs/vr/libdvr/include/dvr/dvr_display_manager.h
+++ b/libs/vr/libdvr/include/dvr/dvr_display_manager.h
@@ -1,5 +1,5 @@
-#ifndef DVR_DISPLAY_MANAGER_CLIENT_H_
-#define DVR_DISPLAY_MANAGER_CLIENT_H_
+#ifndef ANDROID_DVR_DISPLAY_MANAGER_H_
+#define ANDROID_DVR_DISPLAY_MANAGER_H_
 
 #include <stdbool.h>
 #include <stddef.h>
@@ -25,13 +25,6 @@
 // Destroys the display manager client object.
 void dvrDisplayManagerDestroy(DvrDisplayManager* client);
 
-// Sets up a named buffer for shared memory data transfer between display
-// clients and the display manager.
-// @return 0 on success. Otherwise returns a negative error value.
-int dvrDisplayManagerSetupNamedBuffer(DvrDisplayManager* client,
-                                      const char* name, size_t size,
-                                      uint64_t usage, DvrBuffer** buffer_out);
-
 // Returns an fd used to signal when surface updates occur. Note that depending
 // on the underlying transport, only a subset of the real event bits may be
 // supported. Use dvrDisplayManagerClientTranslateEpollEventMask to get the real
@@ -76,7 +69,7 @@
                                    size_t* count_out);
 
 // Returns the update flags for the surface at |surface_index| in the state
-// object. The flags may be used to determine what changes, if any, occured to
+// object. The flags may be used to determine what changes, if any, occurred to
 // the surface since the last state update.
 // @return 0 on success. Otherwise returns a negative error value.
 int dvrSurfaceStateGetUpdateFlags(DvrSurfaceState* surface_state,
@@ -137,4 +130,4 @@
 
 __END_DECLS
 
-#endif  // DVR_DISPLAY_MANAGER_CLIENT_H_
+#endif  // ANDROID_DVR_DISPLAY_MANAGER_H_
diff --git a/libs/vr/libdisplay/include/dvr/dvr_display_types.h b/libs/vr/libdvr/include/dvr/dvr_display_types.h
similarity index 100%
rename from libs/vr/libdisplay/include/dvr/dvr_display_types.h
rename to libs/vr/libdvr/include/dvr/dvr_display_types.h
diff --git a/libs/vr/libdvr/include/dvr/dvr_hardware_composer_client.h b/libs/vr/libdvr/include/dvr/dvr_hardware_composer_client.h
index 7ee7f9e..0ba76e2 100644
--- a/libs/vr/libdvr/include/dvr/dvr_hardware_composer_client.h
+++ b/libs/vr/libdvr/include/dvr/dvr_hardware_composer_client.h
@@ -1,7 +1,7 @@
 #ifndef ANDROID_DVR_HARDWARE_COMPOSER_CLIENT_H
 #define ANDROID_DVR_HARDWARE_COMPOSER_CLIENT_H
 
-#include <dvr/dvr_hardware_composer_defs.h>
+#include <dvr/dvr_hardware_composer_types.h>
 #include <stdbool.h>
 
 #ifdef __cplusplus
@@ -24,37 +24,73 @@
 DvrHwcClient* dvrHwcClientCreate(DvrHwcOnFrameCallback callback,
                                  void* client_state);
 
+// Called to free the DvrHwcClient pointer.
 void dvrHwcClientDestroy(DvrHwcClient* client);
 
 // Called to free the frame information.
+// @param frame Pointer for the valid frame used for the query.
 void dvrHwcFrameDestroy(DvrHwcFrame* frame);
 
+// @param frame Pointer for the valid frame used for the query.
+// @return Identifier for the display associated by the frame.
 DvrHwcDisplay dvrHwcFrameGetDisplayId(DvrHwcFrame* frame);
 
+// @param frame Pointer for the valid frame used for the query.
+// @return width of the physical display associated with |frame|. This does not
+// take into account any orientation changes.
 int32_t dvrHwcFrameGetDisplayWidth(DvrHwcFrame* frame);
 
+// @param frame Pointer for the valid frame used for the query.
+// @return height of the physical display associated with |frame|. This does not
+// take into account any orientation changes.
 int32_t dvrHwcFrameGetDisplayHeight(DvrHwcFrame* frame);
 
+// @param frame Pointer for the valid frame used for the query.
 // @return True if the display has been removed. In this case the current frame
 // does not contain any valid layers to display. It is a signal to clean up any
 // display related state.
 bool dvrHwcFrameGetDisplayRemoved(DvrHwcFrame* frame);
 
+// @param frame Pointer for the valid frame used for the query.
 // @return Number of layers in the frame.
 size_t dvrHwcFrameGetLayerCount(DvrHwcFrame* frame);
 
+// @param frame Pointer for the valid frame used for the query.
+// @return The ID of the currently active display configuration.
 uint32_t dvrHwcFrameGetActiveConfig(DvrHwcFrame* frame);
+
+// @param frame Pointer for the valid frame used for the query.
+// @return The ID of the current color mode. See HAL_COLOR_MODE_* for valid
+// values.
 uint32_t dvrHwcFrameGetColorMode(DvrHwcFrame* frame);
+
+// @param frame Pointer for the valid frame used for the query.
+// @param out_matrix Output parameter for a float[16] array which will be filled
+// with the color transform matrix.
+// @param out_hint Output parameter which will contain the color transform hint.
+// See HAL_COLOR_TRANSFORM_* for valid values.
 void dvrHwcFrameGetColorTransform(DvrHwcFrame* frame, float* out_matrix,
                                   int32_t* out_hint);
+
+// @param frame Pointer for the valid frame used for the query.
+// @return The current power mode for the display. See HWC2_POWER_MODE_* for
+// valid values.
 uint32_t dvrHwcFrameGetPowerMode(DvrHwcFrame* frame);
+
+// @param frame Pointer for the valid frame used for the query.
+// @return The current state of vsync. See HWC2_VSYNC_* for valid values.
 uint32_t dvrHwcFrameGetVsyncEnabled(DvrHwcFrame* frame);
 
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return A unique ID for the layer.
 DvrHwcLayer dvrHwcFrameGetLayerId(DvrHwcFrame* frame, size_t layer_index);
 
 // Return the graphic buffer associated with the layer at |layer_index| in
 // |frame|.
 //
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
 // @return Graphic buffer. Caller owns the buffer and is responsible for freeing
 // it. (see AHardwareBuffer_release())
 AHardwareBuffer* dvrHwcFrameGetLayerBuffer(DvrHwcFrame* frame,
@@ -62,42 +98,98 @@
 
 // Returns the fence FD for the layer at index |layer_index| in |frame|.
 //
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
 // @return Fence FD. Caller owns the FD and is responsible for closing it.
 int dvrHwcFrameGetLayerFence(DvrHwcFrame* frame, size_t layer_index);
 
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return describing the portion of the display covered by the layer. Will
+// not exceed the display dimensions.
 DvrHwcRecti dvrHwcFrameGetLayerDisplayFrame(DvrHwcFrame* frame,
                                             size_t layer_index);
 
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return describing the portion of the layer that will fill the display
+// frame. Will not exceed the layer dimensions.
 DvrHwcRectf dvrHwcFrameGetLayerCrop(DvrHwcFrame* frame, size_t layer_index);
 
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The blend mode of the layer.
 DvrHwcBlendMode dvrHwcFrameGetLayerBlendMode(DvrHwcFrame* frame,
                                              size_t layer_index);
 
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The alpha value to be applied to the whole layer. Will be in the
+// [0.0, 1.0] range.
 float dvrHwcFrameGetLayerAlpha(DvrHwcFrame* frame, size_t layer_index);
 
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The type of the layer assigned by the window manager.
 uint32_t dvrHwcFrameGetLayerType(DvrHwcFrame* frame, size_t layer_index);
 
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The application id the layer belongs to.
 uint32_t dvrHwcFrameGetLayerApplicationId(DvrHwcFrame* frame,
                                           size_t layer_index);
 
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The z-order for the layer.
 uint32_t dvrHwcFrameGetLayerZOrder(DvrHwcFrame* frame, size_t layer_index);
 
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @param out_x Output parameter for the x coordinate of the cursor location.
+// @param out_y Output parameter for the y coordinate of the cursor location.
 void dvrHwcFrameGetLayerCursor(DvrHwcFrame* frame, size_t layer_index,
                                int32_t* out_x, int32_t* out_y);
 
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The transformation that needs to be applied to the layer before
+// presenting it. See DVR_HWC_TRANSFORM_* for valid values.
 uint32_t dvrHwcFrameGetLayerTransform(DvrHwcFrame* frame, size_t layer_index);
 
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The dataspace which represents how the pixel values should be
+// interpreted. See HAL_DATASPACE_* for valid values.
 uint32_t dvrHwcFrameGetLayerDataspace(DvrHwcFrame* frame, size_t layer_index);
 
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The color of the layer if layer composition is SOLID_COLOR.
 uint32_t dvrHwcFrameGetLayerColor(DvrHwcFrame* frame, size_t layer_index);
 
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The number of visible regions.
 uint32_t dvrHwcFrameGetLayerNumVisibleRegions(DvrHwcFrame* frame,
                                               size_t layer_index);
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @param index The index of the visible region for the layer.
+// @return The rectangle describing the visible region.
 DvrHwcRecti dvrHwcFrameGetLayerVisibleRegion(DvrHwcFrame* frame,
                                              size_t layer_index, size_t index);
 
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @return The number of damanged regions.
 uint32_t dvrHwcFrameGetLayerNumDamagedRegions(DvrHwcFrame* frame,
                                               size_t layer_index);
+
+// @param frame Pointer for the valid frame used for the query.
+// @param layer_index The index of the layer in the frame.
+// @param index The index of the damanged region for the layer.
+// @return The rectangle describing the damaged region.
 DvrHwcRecti dvrHwcFrameGetLayerDamagedRegion(DvrHwcFrame* frame,
                                              size_t layer_index, size_t index);
 #ifdef __cplusplus
diff --git a/libs/vr/libdvr/include/dvr/dvr_hardware_composer_defs.h b/libs/vr/libdvr/include/dvr/dvr_hardware_composer_types.h
similarity index 82%
rename from libs/vr/libdvr/include/dvr/dvr_hardware_composer_defs.h
rename to libs/vr/libdvr/include/dvr/dvr_hardware_composer_types.h
index 36c30f9..1d5eda6 100644
--- a/libs/vr/libdvr/include/dvr/dvr_hardware_composer_defs.h
+++ b/libs/vr/libdvr/include/dvr/dvr_hardware_composer_types.h
@@ -26,6 +26,15 @@
   DVR_HWC_COMPOSITION_SIDEBAND = 5,
 };
 
+enum DvrHwcTransform {
+  DVR_HWC_TRANSFORM_NONE = 0,
+  DVR_HWC_TRANSFORM_FLIP_H = 1,
+  DVR_HWC_TRANSFORM_FLIP_V = 2,
+  DVR_HWC_TRANSFORM_ROT_90 = 4,
+  DVR_HWC_TRANSFORM_ROT_180 = 3,
+  DVR_HWC_TRANSFORM_ROT_270 = 7,
+};
+
 typedef uint64_t DvrHwcDisplay;
 typedef uint64_t DvrHwcLayer;
 
diff --git a/libs/vr/libdvr/include/dvr/dvr_performance.h b/libs/vr/libdvr/include/dvr/dvr_performance.h
new file mode 100644
index 0000000..5df35ad
--- /dev/null
+++ b/libs/vr/libdvr/include/dvr/dvr_performance.h
@@ -0,0 +1,26 @@
+#ifndef ANDROID_DVR_PERFORMANCE_H_
+#define ANDROID_DVR_PERFORMANCE_H_
+
+#include <stddef.h>
+#include <unistd.h>
+
+__BEGIN_DECLS
+
+/// Sets the scheduler policy for a task.
+///
+/// Sets the scheduler policy for a task to the class described by a semantic
+/// string.
+///
+/// Supported policies are device-specific.
+///
+/// @param task_id The task id of task to set the policy for. When task_id is 0
+/// the current task id is substituted.
+/// @param scheduler_policy NULL-terminated ASCII string containing the desired
+/// scheduler policy.
+/// @returns Returns 0 on success or a negative errno error code on error.
+int dvrPerformanceSetSchedulerPolicy(pid_t task_id, const char* scheduler_policy);
+
+__END_DECLS
+
+#endif  // ANDROID_DVR_PERFORMANCE_H_
+
diff --git a/libs/vr/libdvr/include/dvr/dvr_pose.h b/libs/vr/libdvr/include/dvr/dvr_pose.h
new file mode 100644
index 0000000..b3df028
--- /dev/null
+++ b/libs/vr/libdvr/include/dvr/dvr_pose.h
@@ -0,0 +1,100 @@
+#ifndef ANDROID_DVR_PUBLIC_POSE_H_
+#define ANDROID_DVR_PUBLIC_POSE_H_
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+#ifdef __ARM_NEON
+#include <arm_neon.h>
+#else
+#ifndef __FLOAT32X4T_86
+#define __FLOAT32X4T_86
+typedef float float32x4_t __attribute__((__vector_size__(16)));
+#endif
+#endif
+
+// Represents an estimated pose, accessed asynchronously through a shared ring
+// buffer. No assumptions should be made about the data in padding space.
+// The size of this struct is 128 bytes.
+typedef struct __attribute__((packed, aligned(16))) DvrPoseAsync {
+  // Left eye head-from-start orientation quaternion x,y,z,w.
+  float32x4_t orientation;
+  // Left eye head-from-start position x,y,z,pad in meters.
+  float32x4_t position;
+  // Right eye head-from-start orientation quaternion x,y,z,w.
+  float32x4_t right_orientation;
+  // Right eye head-from-start position x,y,z,pad in meters.
+  float32x4_t right_position;
+  // Start-space angular velocity x,y,z,pad in radians per second.
+  float32x4_t angular_velocity;
+  // Start-space positional velocity x,y,z,pad in meters per second.
+  float32x4_t velocity;
+  // Timestamp of when this pose is predicted for, typically halfway through
+  // scanout.
+  int64_t timestamp_ns;
+  // Bitmask of DVR_POSE_FLAG_* constants that apply to this pose.
+  //
+  // If DVR_POSE_FLAG_INVALID is set, the pose is indeterminate.
+  uint64_t flags;
+  // Reserved padding to 128 bytes.
+  uint8_t pad[16];
+} DvrPoseAsync;
+
+enum {
+  DVR_POSE_FLAG_INVALID = (1ULL << 0),       // This pose is invalid.
+  DVR_POSE_FLAG_INITIALIZING = (1ULL << 1),  // The pose delivered during
+                                             // initialization and it may not be
+                                             // correct.
+  DVR_POSE_FLAG_3DOF =
+      (1ULL << 2),  // This pose is derived from 3Dof sensors. If
+                    // this is not set, pose is derived using
+                    // 3Dof and 6Dof sensors.
+  DVR_POSE_FLAG_FLOOR_HEIGHT_INVALID =
+      (1ULL << 3),  // If set the floor height is invalid.
+
+  // Bits that indicate the tracking system state.
+  DVR_POSE_FLAG_SERVICE_EXCEPTION = (1ULL << 32),
+  DVR_POSE_FLAG_FISHEYE_OVER_EXPOSED = (1ULL << 33),
+  DVR_POSE_FLAG_FISHEYE_UNDER_EXPOSED = (1ULL << 34),
+  DVR_POSE_FLAG_COLOR_OVER_EXPOSED = (1ULL << 35),
+  DVR_POSE_FLAG_COLOR_UNDER_EXPOSED = (1ULL << 36),
+  DVR_POSE_FLAG_TOO_FEW_FEATURES_TRACKED = (1ULL << 37)
+};
+
+// Represents a sensor pose sample.
+typedef struct __attribute__((packed, aligned(16))) DvrPose {
+  // Head-from-start orientation quaternion x,y,z,w.
+  float32x4_t orientation;
+
+  // The angular velocity where the x,y,z is the rotation axis and the
+  // magnitude is the radians / second in the same coordinate frame as
+  // orientation.
+  float32x4_t angular_velocity;
+
+  // Head-from-start position x,y,z,pad in meters.
+  float32x4_t position;
+
+  // In meters / second in the same coordinate frame as position.
+  float32x4_t velocity;
+
+  // In meters / second ^ 2 in the same coordinate frame as position.
+  float32x4_t acceleration;
+
+  // Timestamp for the measurement in nanoseconds.
+  int64_t timestamp_ns;
+
+  // The combination of flags above.
+  uint64_t flags;
+
+  // The current floor height. May be updated at a lower cadence than pose.
+  float floor_height;
+
+  // Padding to 112 bytes so the size is a multiple of 16.
+  uint8_t padding[12];
+} DvrPose;
+
+__END_DECLS
+
+#endif  // ANDROID_DVR_PUBLIC_POSE_H_
diff --git a/libs/vr/libdvr/include/dvr/dvr_shared_buffers.h b/libs/vr/libdvr/include/dvr/dvr_shared_buffers.h
new file mode 100644
index 0000000..63c7385
--- /dev/null
+++ b/libs/vr/libdvr/include/dvr/dvr_shared_buffers.h
@@ -0,0 +1,102 @@
+#ifndef ANDROID_DVR_SHARED_BUFFERS_H_
+#define ANDROID_DVR_SHARED_BUFFERS_H_
+
+#include <dvr/dvr_config.h>
+#include <dvr/dvr_pose.h>
+#include <dvr/dvr_vsync.h>
+#include <libbroadcastring/broadcast_ring.h>
+
+// This header is shared by VrCore and Android and must be kept in sync.
+namespace android {
+namespace dvr {
+
+// Increment when the layout for the buffers change.
+enum : uint32_t { kSharedBufferLayoutVersion = 2 };
+
+// Note: These buffers will be mapped from various system processes as well
+// as VrCore and the application processes in a r/w manner.
+//
+// Therefore it is possible for the application to mess with the contents of
+// these buffers.
+//
+// While using them, assume garbage memory: Your logic must not crash or lead
+// to execution of unsafe code as a function of the contents of these buffers.
+
+// Sanity check for basic type sizes.
+static_assert(sizeof(DvrPoseAsync) == 128, "Unexpected size for DvrPoseAsync");
+static_assert(sizeof(DvrPose) == 112, "Unexpected size for DvrPose");
+static_assert(sizeof(DvrVsync) == 32, "Unexpected size for DvrVsync");
+static_assert(sizeof(DvrConfig) == 16, "Unexpected size for DvrConfig");
+
+// A helper class that provides compile time sized traits for the BroadcastRing.
+template <class DvrType, size_t StaticCount>
+class DvrRingBufferTraits {
+ public:
+  using Record = DvrType;
+  static constexpr bool kUseStaticRecordSize = false;
+  static constexpr uint32_t kStaticRecordCount = StaticCount;
+  static constexpr int kMaxReservedRecords = 1;
+  static constexpr int kMinAvailableRecords = 1;
+};
+
+// Traits classes.
+using DvrPoseTraits = DvrRingBufferTraits<DvrPose, 0>;
+using DvrVsyncTraits = DvrRingBufferTraits<DvrVsync, 2>;
+using DvrConfigTraits = DvrRingBufferTraits<DvrConfig, 2>;
+
+// The broadcast ring classes that will expose the data.
+using DvrPoseRing = BroadcastRing<DvrPose, DvrPoseTraits>;
+using DvrVsyncRing = BroadcastRing<DvrVsync, DvrVsyncTraits>;
+using DvrConfigRing = BroadcastRing<DvrConfig, DvrConfigTraits>;
+
+// This is a shared memory buffer for passing pose data estimated at vsyncs.
+//
+// This will be primarily used for late latching and EDS where we bind this
+// buffer in a shader and extract the right vsync-predicted pose.
+struct __attribute__((packed, aligned(16))) DvrVsyncPoseBuffer {
+  enum : int {
+    // The number vsync predicted poses to keep in the ring buffer.
+    // Must be a power of 2.
+    kSize = 8,
+    kIndexMask = kSize - 1,
+
+    // The number of vsyncs (from the current vsync) we predict in vsync buffer.
+    // The other poses are left alone.
+    kMinFutureCount = 4
+  };
+
+  // The vsync predicted poses.
+  // The pose for the vsync n is:
+  // vsync_poses[n % kSize]
+  //
+  // This buffer is unsynchronized: It is possible to get torn reads as the
+  // sensor service updates the predictions as new sensor measurements come
+  // in. In particular, it is possible to get the position and an updated
+  // orientation while reading.
+  DvrPoseAsync vsync_poses[kSize];
+
+  // The latest sensor pose for GPU usage.
+  DvrPose current_pose;
+
+  // Current vsync_count (where sensord is writing poses from).
+  uint32_t vsync_count;
+
+  // For 16 byte alignment.
+  uint8_t padding[12];
+};
+
+static_assert(sizeof(DvrVsyncPoseBuffer) == 1152,
+              "Unexpected size for DvrVsyncPoseBuffer");
+
+// The keys for the dvr global buffers.
+enum DvrGlobalBuffers : int32_t {
+  kVsyncPoseBuffer = 1,
+  kVsyncBuffer = 2,
+  kSensorPoseBuffer = 3,
+  kVrFlingerConfigBufferKey = 4
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_SHARED_BUFFERS_H_
diff --git a/libs/vr/libdvr/include/dvr/dvr_surface.h b/libs/vr/libdvr/include/dvr/dvr_surface.h
index 361488e..74a68a1 100644
--- a/libs/vr/libdvr/include/dvr/dvr_surface.h
+++ b/libs/vr/libdvr/include/dvr/dvr_surface.h
@@ -6,16 +6,13 @@
 #include <stdint.h>
 #include <sys/cdefs.h>
 
+#include <dvr/dvr_api.h>
 #include <dvr/dvr_buffer.h>
 #include <dvr/dvr_buffer_queue.h>
 #include <dvr/dvr_display_types.h>
 
 __BEGIN_DECLS
 
-typedef struct DvrBuffer DvrBuffer;
-typedef struct DvrSurface DvrSurface;
-typedef struct DvrWriteBufferQueue DvrWriteBufferQueue;
-
 // Attribute types. The values are one-hot encoded to support singluar types or
 // masks of supported types.
 enum {
@@ -79,12 +76,37 @@
 int dvrSurfaceCreateWriteBufferQueue(DvrSurface* surface, uint32_t width,
                                      uint32_t height, uint32_t format,
                                      uint32_t layer_count, uint64_t usage,
-                                     size_t capacity,
+                                     size_t capacity, size_t metadata_size,
                                      DvrWriteBufferQueue** queue_out);
 
-// Get a named buffer from the display service.
+// Sets up a named buffer for shared memory data transfer between display
+// clients and the system. Protected API that may only be called with sufficient
+// privilege.
 // @return 0 on success. Otherwise returns a negative error value.
-int dvrGetNamedBuffer(const char* name, DvrBuffer** out_buffer);
+int dvrSetupGlobalBuffer(DvrGlobalBufferKey key, size_t size, uint64_t usage,
+                         DvrBuffer** buffer_out);
+
+// Deletes a named buffer. WARNING: This is dangerous because any existing
+// clients of this buffer will not be notified and will remain attached to
+// the old buffer. This is useful for tests, but probably not for production
+// code.
+// @return 0 on success. Otherwise returns a negative error value.
+int dvrDeleteGlobalBuffer(DvrGlobalBufferKey key);
+
+// Get a global buffer from the display service.
+// @return 0 on success. Otherwise returns a negative error value.
+int dvrGetGlobalBuffer(DvrGlobalBufferKey key, DvrBuffer** out_buffer);
+
+// Read the native device display metrics as reported by the hardware composer.
+// This is useful as otherwise the device metrics are only reported as
+// relative to the current device orientation.
+// @param sizeof_metrics the size of the passed in metrics struct. This is used
+//   to ensure we don't break each other during active development.
+// @param metrics on success holds the retrieved device metrics.
+// @return 0 on success. Otherwise returns a negative error value (typically
+//   this means the display service is not available).
+int dvrGetNativeDisplayMetrics(size_t metrics_struct_size,
+                               DvrNativeDisplayMetrics* metrics);
 
 __END_DECLS
 
diff --git a/libs/vr/libdvr/include/dvr/dvr_vsync.h b/libs/vr/libdvr/include/dvr/dvr_vsync.h
index 1eea3d9..87fdf31 100644
--- a/libs/vr/libdvr/include/dvr/dvr_vsync.h
+++ b/libs/vr/libdvr/include/dvr/dvr_vsync.h
@@ -8,6 +8,27 @@
 
 typedef struct DvrVSyncClient DvrVSyncClient;
 
+// Represents a vsync sample. The size of this struct is 32 bytes.
+typedef struct __attribute__((packed, aligned(16))) DvrVsync {
+  // The timestamp for the last vsync in nanoseconds.
+  uint64_t vsync_timestamp_ns;
+
+  // The index of the last vsync.
+  uint32_t vsync_count;
+
+  // Scan out for the left eye = vsync_timestamp_ns + vsync_left_eye_offset_ns.
+  int32_t vsync_left_eye_offset_ns;
+
+  // Scan out for the right eye = vsync_timestamp_ns + vsync_right_eye_offset_ns
+  int32_t vsync_right_eye_offset_ns;
+
+  // The period of a vsync in nanoseconds.
+  uint32_t vsync_period_ns;
+
+  // Padding to 32 bytes so the size is a multiple of 16.
+  uint8_t padding[8];
+} DvrVsync;
+
 // Creates a new client to the system vsync service.
 int dvrVSyncClientCreate(DvrVSyncClient** client_out);
 
diff --git a/libs/vr/libdvr/tests/Android.bp b/libs/vr/libdvr/tests/Android.bp
index ef746e2..ab2ee75 100644
--- a/libs/vr/libdvr/tests/Android.bp
+++ b/libs/vr/libdvr/tests/Android.bp
@@ -32,6 +32,7 @@
     "libdvrcommon",
     "libdisplay",
     "libpdx_default_transport",
+    "libbroadcastring",
 ]
 
 cc_test {
diff --git a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
index 474e968..16da1d9 100644
--- a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
@@ -7,27 +7,41 @@
 #include <gtest/gtest.h>
 
 #include "../dvr_internal.h"
+#include "../dvr_buffer_queue_internal.h"
 
 namespace android {
 namespace dvr {
 
 namespace {
 
-static constexpr int kBufferWidth = 100;
-static constexpr int kBufferHeight = 1;
-static constexpr int kLayerCount = 1;
-static constexpr int kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
-static constexpr int kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY;
+static constexpr uint32_t kBufferWidth = 100;
+static constexpr uint32_t kBufferHeight = 1;
+static constexpr uint32_t kLayerCount = 1;
+static constexpr uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
+static constexpr uint64_t kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY;
 static constexpr size_t kQueueCapacity = 3;
 
 typedef uint64_t TestMeta;
 
 class DvrBufferQueueTest : public ::testing::Test {
+ public:
+  static void BufferAvailableCallback(void* context) {
+    DvrBufferQueueTest* thiz = static_cast<DvrBufferQueueTest*>(context);
+    thiz->HandleBufferAvailable();
+  }
+
+  static void BufferRemovedCallback(DvrReadBuffer* buffer, void* context) {
+    DvrBufferQueueTest* thiz = static_cast<DvrBufferQueueTest*>(context);
+    thiz->HandleBufferRemoved(buffer);
+  }
+
  protected:
   void SetUp() override {
-    write_queue_ = CreateDvrWriteBufferQueueFromProducerQueue(
-        ProducerQueue::Create<TestMeta>(0, 0, 0, 0));
-    ASSERT_NE(nullptr, write_queue_);
+    config_builder_ = ProducerQueueConfigBuilder()
+                          .SetDefaultWidth(kBufferWidth)
+                          .SetDefaultHeight(kBufferHeight)
+                          .SetDefaultFormat(kBufferFormat)
+                          .SetMetadata<TestMeta>();
   }
 
   void TearDown() override {
@@ -37,26 +51,47 @@
     }
   }
 
-  void AllocateBuffers(size_t buffer_count) {
-    size_t out_slot;
-    for (size_t i = 0; i < buffer_count; i++) {
-      int ret = GetProducerQueueFromDvrWriteBufferQueue(write_queue_)
-                    ->AllocateBuffer(kBufferWidth, kBufferHeight, kLayerCount,
-                                     kBufferFormat, kBufferUsage, &out_slot);
-      ASSERT_EQ(0, ret);
-    }
+  void CreateWriteBufferQueue() {
+    write_queue_ = new DvrWriteBufferQueue(
+        ProducerQueue::Create(config_builder_.Build(), UsagePolicy{}));
+    ASSERT_NE(nullptr, write_queue_);
   }
 
+  void AllocateBuffers(size_t buffer_count) {
+    auto status = write_queue_->producer_queue()->AllocateBuffers(
+        kBufferWidth, kBufferHeight, kLayerCount, kBufferFormat, kBufferUsage,
+        buffer_count);
+    ASSERT_TRUE(status.ok());
+  }
+
+  void HandleBufferAvailable() {
+    buffer_available_count_ += 1;
+    ALOGD_IF(TRACE, "Buffer avaiable, count=%d", buffer_available_count_);
+  }
+
+  void HandleBufferRemoved(DvrReadBuffer* buffer) {
+    buffer_removed_count_ += 1;
+    ALOGD_IF(TRACE, "Buffer removed, buffer=%p, count=%d", buffer,
+             buffer_removed_count_);
+  }
+
+  ProducerQueueConfigBuilder config_builder_;
   DvrWriteBufferQueue* write_queue_{nullptr};
+  int buffer_available_count_{0};
+  int buffer_removed_count_{0};
 };
 
-TEST_F(DvrBufferQueueTest, TestWrite_QueueDestroy) {
+TEST_F(DvrBufferQueueTest, TestWrite_QueueCreateDestroy) {
+  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+
   dvrWriteBufferQueueDestroy(write_queue_);
   write_queue_ = nullptr;
 }
 
 TEST_F(DvrBufferQueueTest, TestWrite_QueueGetCapacity) {
-  AllocateBuffers(kQueueCapacity);
+  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+  ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity));
+
   size_t capacity = dvrWriteBufferQueueGetCapacity(write_queue_);
 
   ALOGD_IF(TRACE, "TestWrite_QueueGetCapacity, capacity=%zu", capacity);
@@ -64,6 +99,8 @@
 }
 
 TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromWriteQueue) {
+  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+
   DvrReadBufferQueue* read_queue = nullptr;
   int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
 
@@ -74,6 +111,8 @@
 }
 
 TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromReadQueue) {
+  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+
   DvrReadBufferQueue* read_queue1 = nullptr;
   DvrReadBufferQueue* read_queue2 = nullptr;
   int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue1);
@@ -91,7 +130,8 @@
 }
 
 TEST_F(DvrBufferQueueTest, CreateEmptyBuffer) {
-  AllocateBuffers(3);
+  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+  ASSERT_NO_FATAL_FAILURE(AllocateBuffers(3));
 
   DvrReadBuffer* read_buffer = nullptr;
   DvrWriteBuffer* write_buffer = nullptr;
@@ -124,6 +164,9 @@
 }
 
 TEST_F(DvrBufferQueueTest, TestDequeuePostDequeueRelease) {
+  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+  ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity));
+
   static constexpr int kTimeout = 0;
   DvrReadBufferQueue* read_queue = nullptr;
   DvrReadBuffer* rb = nullptr;
@@ -135,14 +178,15 @@
   ASSERT_EQ(0, ret);
   ASSERT_NE(nullptr, read_queue);
 
+  dvrReadBufferQueueSetBufferAvailableCallback(read_queue,
+                                               &BufferAvailableCallback, this);
+
   dvrWriteBufferCreateEmpty(&wb);
   ASSERT_NE(nullptr, wb);
 
   dvrReadBufferCreateEmpty(&rb);
   ASSERT_NE(nullptr, rb);
 
-  AllocateBuffers(kQueueCapacity);
-
   // Gain buffer for writing.
   ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wb, &fence_fd);
   ASSERT_EQ(0, ret);
@@ -163,6 +207,9 @@
   ret = dvrReadBufferQueueDequeue(read_queue, kTimeout, rb, &fence_fd,
                                   &acquired_seq, sizeof(acquired_seq));
   ASSERT_EQ(0, ret);
+
+  // Dequeue is successfully, BufferAvailableCallback should be fired once.
+  ASSERT_EQ(1, buffer_available_count_);
   ASSERT_TRUE(dvrReadBufferIsValid(rb));
   ASSERT_EQ(seq, acquired_seq);
   ALOGD_IF(TRACE,
@@ -187,6 +234,8 @@
 }
 
 TEST_F(DvrBufferQueueTest, TestGetExternalSurface) {
+  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+
   ANativeWindow* window = nullptr;
 
   // The |write_queue_| doesn't have proper metadata (must be
@@ -196,10 +245,12 @@
   ASSERT_EQ(nullptr, window);
 
   // A write queue with DvrNativeBufferMetadata should work fine.
+  auto config = ProducerQueueConfigBuilder()
+                    .SetMetadata<DvrNativeBufferMetadata>()
+                    .Build();
   std::unique_ptr<DvrWriteBufferQueue, decltype(&dvrWriteBufferQueueDestroy)>
       write_queue(
-          CreateDvrWriteBufferQueueFromProducerQueue(
-              ProducerQueue::Create<DvrNativeBufferMetadata>(0, 0, 0, 0)),
+          new DvrWriteBufferQueue(ProducerQueue::Create(config, UsagePolicy{})),
           dvrWriteBufferQueueDestroy);
   ASSERT_NE(nullptr, write_queue.get());
 
@@ -211,6 +262,208 @@
   ASSERT_TRUE(Surface::isValid(surface));
 }
 
+// Create buffer queue of three buffers and dequeue three buffers out of it.
+// Before each dequeue operation, we resize the buffer queue and expect the
+// queue always return buffer with desired dimension.
+TEST_F(DvrBufferQueueTest, TestResizeBuffer) {
+  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+  ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity));
+
+  static constexpr int kTimeout = 0;
+  int fence_fd = -1;
+
+  DvrReadBufferQueue* read_queue = nullptr;
+  DvrWriteBuffer* wb1 = nullptr;
+  DvrWriteBuffer* wb2 = nullptr;
+  DvrWriteBuffer* wb3 = nullptr;
+  AHardwareBuffer* ahb1 = nullptr;
+  AHardwareBuffer* ahb2 = nullptr;
+  AHardwareBuffer* ahb3 = nullptr;
+  AHardwareBuffer_Desc buffer_desc;
+
+  int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+
+  ASSERT_EQ(0, ret);
+  ASSERT_NE(nullptr, read_queue);
+
+  dvrReadBufferQueueSetBufferRemovedCallback(read_queue, &BufferRemovedCallback,
+                                             this);
+
+  dvrWriteBufferCreateEmpty(&wb1);
+  ASSERT_NE(nullptr, wb1);
+  dvrWriteBufferCreateEmpty(&wb2);
+  ASSERT_NE(nullptr, wb2);
+  dvrWriteBufferCreateEmpty(&wb3);
+  ASSERT_NE(nullptr, wb3);
+
+  // Handle all pending events on the read queue.
+  ret = dvrReadBufferQueueHandleEvents(read_queue);
+  ASSERT_EQ(0, ret);
+
+  size_t capacity = dvrReadBufferQueueGetCapacity(read_queue);
+  ALOGD_IF(TRACE, "TestResizeBuffer, capacity=%zu", capacity);
+  ASSERT_EQ(kQueueCapacity, capacity);
+
+  // Resize before dequeuing.
+  constexpr uint32_t w1 = 10;
+  ret = dvrWriteBufferQueueResizeBuffer(write_queue_, w1, kBufferHeight);
+  ASSERT_EQ(0, ret);
+
+  // Gain first buffer for writing. All buffers will be resized.
+  ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wb1, &fence_fd);
+  ASSERT_EQ(0, ret);
+  ASSERT_TRUE(dvrWriteBufferIsValid(wb1));
+  ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p", wb1);
+  pdx::LocalHandle release_fence1(fence_fd);
+
+  // Check the buffer dimension.
+  ret = dvrWriteBufferGetAHardwareBuffer(wb1, &ahb1);
+  ASSERT_EQ(0, ret);
+  AHardwareBuffer_describe(ahb1, &buffer_desc);
+  ASSERT_EQ(w1, buffer_desc.width);
+  ASSERT_EQ(kBufferHeight, buffer_desc.height);
+  AHardwareBuffer_release(ahb1);
+
+  // For the first resize, all buffers are reallocated.
+  int expected_buffer_removed_count = kQueueCapacity;
+  ret = dvrReadBufferQueueHandleEvents(read_queue);
+  ASSERT_EQ(0, ret);
+  ASSERT_EQ(expected_buffer_removed_count, buffer_removed_count_);
+
+  // Resize the queue. We are testing with blob format, keep height to be 1.
+  constexpr uint32_t w2 = 20;
+  ret = dvrWriteBufferQueueResizeBuffer(write_queue_, w2, kBufferHeight);
+  ASSERT_EQ(0, ret);
+
+  // The next buffer we dequeued should have new width.
+  ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wb2, &fence_fd);
+  ASSERT_EQ(0, ret);
+  ASSERT_TRUE(dvrWriteBufferIsValid(wb2));
+  ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb2,
+           fence_fd);
+  pdx::LocalHandle release_fence2(fence_fd);
+
+  // Check the buffer dimension, should be new width
+  ret = dvrWriteBufferGetAHardwareBuffer(wb2, &ahb2);
+  ASSERT_EQ(0, ret);
+  AHardwareBuffer_describe(ahb2, &buffer_desc);
+  ASSERT_EQ(w2, buffer_desc.width);
+  AHardwareBuffer_release(ahb2);
+
+  // For the second resize, all but one buffers are reallocated.
+  expected_buffer_removed_count += (kQueueCapacity - 1);
+  ret = dvrReadBufferQueueHandleEvents(read_queue);
+  ASSERT_EQ(0, ret);
+  ASSERT_EQ(expected_buffer_removed_count, buffer_removed_count_);
+
+  // Resize the queue for the third time.
+  constexpr uint32_t w3 = 30;
+  ret = dvrWriteBufferQueueResizeBuffer(write_queue_, w3, kBufferHeight);
+  ASSERT_EQ(0, ret);
+
+  // The next buffer we dequeued should have new width.
+  ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wb3, &fence_fd);
+  ASSERT_EQ(0, ret);
+  ASSERT_TRUE(dvrWriteBufferIsValid(wb3));
+  ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb3,
+           fence_fd);
+  pdx::LocalHandle release_fence3(fence_fd);
+
+  // Check the buffer dimension, should be new width
+  ret = dvrWriteBufferGetAHardwareBuffer(wb3, &ahb3);
+  ASSERT_EQ(0, ret);
+  AHardwareBuffer_describe(ahb3, &buffer_desc);
+  ASSERT_EQ(w3, buffer_desc.width);
+  AHardwareBuffer_release(ahb3);
+
+  // For the third resize, all but two buffers are reallocated.
+  expected_buffer_removed_count += (kQueueCapacity - 2);
+  ret = dvrReadBufferQueueHandleEvents(read_queue);
+  ASSERT_EQ(0, ret);
+  ASSERT_EQ(expected_buffer_removed_count, buffer_removed_count_);
+
+  dvrReadBufferQueueDestroy(read_queue);
+}
+
+TEST_F(DvrBufferQueueTest, DequeueEmptyMetadata) {
+  // Overrides default queue parameters: Empty metadata.
+  config_builder_.SetMetadata<void>();
+  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+  ASSERT_NO_FATAL_FAILURE(AllocateBuffers(1));
+
+  DvrReadBuffer* rb = nullptr;
+  DvrWriteBuffer* wb = nullptr;
+  dvrReadBufferCreateEmpty(&rb);
+  dvrWriteBufferCreateEmpty(&wb);
+
+  DvrReadBufferQueue* read_queue = nullptr;
+  EXPECT_EQ(0, dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue));
+
+  const int kTimeoutMs = 0;
+  int fence_fd = -1;
+  EXPECT_EQ(0, dvrWriteBufferQueueDequeue(write_queue_, 0, wb, &fence_fd));
+
+  EXPECT_EQ(0, dvrWriteBufferPost(wb, /*fence=*/-1, nullptr, 0));
+  EXPECT_EQ(0, dvrWriteBufferClear(wb));
+  dvrWriteBufferDestroy(wb);
+  wb = nullptr;
+
+  // When acquire buffer, it's legit to pass nullptr as out_meta iff metadata
+  // size is Zero.
+  EXPECT_EQ(0, dvrReadBufferQueueDequeue(read_queue, kTimeoutMs, rb, &fence_fd,
+                                         nullptr, 0));
+  EXPECT_TRUE(dvrReadBufferIsValid(rb));
+}
+
+TEST_F(DvrBufferQueueTest, DequeueMismatchMetadata) {
+  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+  ASSERT_NO_FATAL_FAILURE(AllocateBuffers(1));
+
+  DvrReadBuffer* rb = nullptr;
+  DvrWriteBuffer* wb = nullptr;
+  dvrReadBufferCreateEmpty(&rb);
+  dvrWriteBufferCreateEmpty(&wb);
+
+  DvrReadBufferQueue* read_queue = nullptr;
+  EXPECT_EQ(0, dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue));
+
+  const int kTimeoutMs = 0;
+  int fence_fd = -1;
+  EXPECT_EQ(0, dvrWriteBufferQueueDequeue(write_queue_, 0, wb, &fence_fd));
+
+  TestMeta seq = 42U;
+  EXPECT_EQ(0, dvrWriteBufferPost(wb, /*fence=*/-1, &seq, sizeof(seq)));
+  EXPECT_EQ(0, dvrWriteBufferClear(wb));
+  dvrWriteBufferDestroy(wb);
+  wb = nullptr;
+
+  // Dequeue with wrong metadata will cause EINVAL.
+  int8_t wrong_metadata;
+  EXPECT_EQ(-EINVAL,
+            dvrReadBufferQueueDequeue(read_queue, kTimeoutMs, rb, &fence_fd,
+                                      &wrong_metadata, sizeof(wrong_metadata)));
+  EXPECT_FALSE(dvrReadBufferIsValid(rb));
+
+  // Dequeue with empty metadata will cause EINVAL.
+  EXPECT_EQ(-EINVAL, dvrReadBufferQueueDequeue(read_queue, kTimeoutMs, rb,
+                                               &fence_fd, nullptr, 0));
+  EXPECT_FALSE(dvrReadBufferIsValid(rb));
+}
+
+TEST_F(DvrBufferQueueTest, TestReadQueueEventFd) {
+  ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+  ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity));
+
+  DvrReadBufferQueue* read_queue = nullptr;
+  int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+
+  ASSERT_EQ(0, ret);
+  ASSERT_NE(nullptr, read_queue);
+
+  int event_fd = dvrReadBufferQueueGetEventFd(read_queue);
+  ASSERT_GT(event_fd, 0);
+}
+
 }  // namespace
 
 }  // namespace dvr
diff --git a/libs/vr/libdvr/tests/dvr_display_manager-test.cpp b/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
index a2414d6..f83b26e 100644
--- a/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
@@ -1,14 +1,18 @@
+#include <android-base/properties.h>
 #include <base/logging.h>
 #include <gtest/gtest.h>
+#include <log/log.h>
 #include <poll.h>
 
 #include <android/hardware_buffer.h>
 
 #include <algorithm>
+#include <array>
 #include <set>
 #include <thread>
 #include <vector>
 
+#include <dvr/dvr_configuration_data.h>
 #include <dvr/dvr_deleter.h>
 #include <dvr/dvr_display_manager.h>
 #include <dvr/dvr_surface.h>
@@ -23,7 +27,30 @@
 
 namespace {
 
-DvrSurfaceAttribute GetAttribute(DvrSurfaceAttributeKey key, bool value) {
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, nullptr_t) {
+  DvrSurfaceAttribute attribute;
+  attribute.key = key;
+  attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_NONE;
+  return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, int32_t value) {
+  DvrSurfaceAttribute attribute;
+  attribute.key = key;
+  attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32;
+  attribute.value.int32_value = value;
+  return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, int64_t value) {
+  DvrSurfaceAttribute attribute;
+  attribute.key = key;
+  attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT64;
+  attribute.value.int64_value = value;
+  return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, bool value) {
   DvrSurfaceAttribute attribute;
   attribute.key = key;
   attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL;
@@ -31,11 +58,56 @@
   return attribute;
 }
 
-DvrSurfaceAttribute GetAttribute(DvrSurfaceAttributeKey key, int32_t value) {
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, float value) {
   DvrSurfaceAttribute attribute;
   attribute.key = key;
-  attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32;
-  attribute.value.bool_value = value;
+  attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT;
+  attribute.value.float_value = value;
+  return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
+                                  const std::array<float, 2>& value) {
+  DvrSurfaceAttribute attribute;
+  attribute.key = key;
+  attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT2;
+  std::copy(value.begin(), value.end(), attribute.value.float2_value);
+  return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
+                                  const std::array<float, 3>& value) {
+  DvrSurfaceAttribute attribute;
+  attribute.key = key;
+  attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT3;
+  std::copy(value.begin(), value.end(), attribute.value.float3_value);
+  return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
+                                  const std::array<float, 4>& value) {
+  DvrSurfaceAttribute attribute;
+  attribute.key = key;
+  attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT4;
+  std::copy(value.begin(), value.end(), attribute.value.float4_value);
+  return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
+                                  const std::array<float, 8>& value) {
+  DvrSurfaceAttribute attribute;
+  attribute.key = key;
+  attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT8;
+  std::copy(value.begin(), value.end(), attribute.value.float8_value);
+  return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
+                                  const std::array<float, 16>& value) {
+  DvrSurfaceAttribute attribute;
+  attribute.key = key;
+  attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT16;
+  std::copy(value.begin(), value.end(), attribute.value.float16_value);
   return attribute;
 }
 
@@ -43,8 +115,8 @@
                                                   int32_t z_order = 0) {
   DvrSurface* surface = nullptr;
   DvrSurfaceAttribute attributes[] = {
-      GetAttribute(DVR_SURFACE_ATTRIBUTE_Z_ORDER, z_order),
-      GetAttribute(DVR_SURFACE_ATTRIBUTE_VISIBLE, visible)};
+      MakeAttribute(DVR_SURFACE_ATTRIBUTE_Z_ORDER, z_order),
+      MakeAttribute(DVR_SURFACE_ATTRIBUTE_VISIBLE, visible)};
 
   const int ret = dvrSurfaceCreate(
       attributes, std::extent<decltype(attributes)>::value, &surface);
@@ -56,11 +128,12 @@
 
 Status<UniqueDvrWriteBufferQueue> CreateSurfaceQueue(
     const UniqueDvrSurface& surface, uint32_t width, uint32_t height,
-    uint32_t format, uint32_t layer_count, uint64_t usage, size_t capacity) {
+    uint32_t format, uint32_t layer_count, uint64_t usage, size_t capacity,
+    size_t metadata_size) {
   DvrWriteBufferQueue* queue;
-  const int ret =
-      dvrSurfaceCreateWriteBufferQueue(surface.get(), width, height, format,
-                                       layer_count, usage, capacity, &queue);
+  const int ret = dvrSurfaceCreateWriteBufferQueue(
+      surface.get(), width, height, format, layer_count, usage, capacity,
+      metadata_size, &queue);
   if (ret < 0)
     return ErrorStatus(-ret);
   else
@@ -98,13 +171,14 @@
       return {};
   }
 
-  Status<void> WaitForUpdate() {
+  enum : int { kTimeoutMs = 10000 };  // 10s
+
+  Status<void> WaitForUpdate(int timeout_ms = kTimeoutMs) {
     if (display_manager_event_fd_ < 0)
       return ErrorStatus(-display_manager_event_fd_);
 
-    const int kTimeoutMs = 10000;  // 10s
     pollfd pfd = {display_manager_event_fd_, POLLIN, 0};
-    const int count = poll(&pfd, 1, kTimeoutMs);
+    const int count = poll(&pfd, 1, timeout_ms);
     if (count < 0)
       return ErrorStatus(errno);
     else if (count == 0)
@@ -200,6 +274,23 @@
     return {std::move(queue_ids)};
   }
 
+  Status<std::vector<uint8_t>> GetConfigData(int config_type) {
+    uint8_t* data = nullptr;
+    size_t data_size = 0;
+    int error = dvrConfigurationDataGet(config_type, &data, &data_size);
+    if (error < 0) {
+      return ErrorStatus(-error);
+    }
+
+    if (!data || data_size == 0) {
+      return ErrorStatus(EINVAL);
+    }
+    std::vector<uint8_t> data_result(data, data + data_size);
+    dvrConfigurationDataDestroy(data);
+    std::string s(data, data + data_size);
+    return {std::move(data_result)};
+  }
+
  private:
   UniqueDvrDisplayManager display_manager_;
   UniqueDvrSurfaceState surface_state_;
@@ -451,20 +542,218 @@
   auto attributes = attribute_status.take();
   EXPECT_GE(attributes.size(), 2u);
 
-  const std::set<int32_t> expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER,
-                                           DVR_SURFACE_ATTRIBUTE_VISIBLE};
+  std::set<int32_t> actual_keys;
+  std::set<int32_t> expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER,
+                                     DVR_SURFACE_ATTRIBUTE_VISIBLE};
 
   // Collect all the keys in attributes that match the expected keys.
-  std::set<int32_t> actual_keys;
-  std::for_each(attributes.begin(), attributes.end(),
-                [&expected_keys, &actual_keys](const auto& attribute) {
-                  if (expected_keys.find(attribute.key) != expected_keys.end())
-                    actual_keys.emplace(attribute.key);
-                });
+  auto compare_keys = [](const auto& attributes, const auto& expected_keys) {
+    std::set<int32_t> keys;
+    for (const auto& attribute : attributes) {
+      if (expected_keys.find(attribute.key) != expected_keys.end())
+        keys.emplace(attribute.key);
+    }
+    return keys;
+  };
 
   // If the sets match then attributes contained at least the expected keys,
   // even if other keys were also present.
+  actual_keys = compare_keys(attributes, expected_keys);
   EXPECT_EQ(expected_keys, actual_keys);
+
+  std::vector<DvrSurfaceAttribute> attributes_to_set = {
+      MakeAttribute(DVR_SURFACE_ATTRIBUTE_Z_ORDER, 0)};
+
+  // Test invalid args.
+  EXPECT_EQ(-EINVAL, dvrSurfaceSetAttributes(nullptr, attributes_to_set.data(),
+                                             attributes_to_set.size()));
+  EXPECT_EQ(-EINVAL, dvrSurfaceSetAttributes(surface.get(), nullptr,
+                                             attributes_to_set.size()));
+
+  // Test attribute change events.
+  ASSERT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
+                                       attributes_to_set.size()));
+  ASSERT_STATUS_OK(manager_->WaitForUpdate());
+
+  // Verify the attributes changed flag is set.
+  auto check_flags = [](const auto& value) {
+    return value & DVR_SURFACE_UPDATE_FLAGS_ATTRIBUTES_CHANGED;
+  };
+  EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0));
+
+  attribute_status = manager_->GetAttributes(0);
+  ASSERT_STATUS_OK(attribute_status);
+  attributes = attribute_status.take();
+  EXPECT_GE(attributes.size(), 2u);
+
+  expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER,
+                   DVR_SURFACE_ATTRIBUTE_VISIBLE};
+
+  actual_keys.clear();
+  actual_keys = compare_keys(attributes, expected_keys);
+  EXPECT_EQ(expected_keys, actual_keys);
+
+  // Test setting and then deleting an attribute.
+  const DvrSurfaceAttributeKey kUserKey = 1;
+  attributes_to_set = {MakeAttribute(kUserKey, 1024)};
+
+  ASSERT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
+                                       attributes_to_set.size()));
+  ASSERT_STATUS_OK(manager_->WaitForUpdate());
+  EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0));
+
+  attribute_status = manager_->GetAttributes(0);
+  ASSERT_STATUS_OK(attribute_status);
+  attributes = attribute_status.take();
+  EXPECT_GE(attributes.size(), 2u);
+
+  expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER, DVR_SURFACE_ATTRIBUTE_VISIBLE,
+                   kUserKey};
+
+  actual_keys.clear();
+  actual_keys = compare_keys(attributes, expected_keys);
+  EXPECT_EQ(expected_keys, actual_keys);
+
+  // Delete the attribute.
+  attributes_to_set = {MakeAttribute(kUserKey, nullptr)};
+
+  ASSERT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
+                                       attributes_to_set.size()));
+  ASSERT_STATUS_OK(manager_->WaitForUpdate());
+  EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0));
+
+  attribute_status = manager_->GetAttributes(0);
+  ASSERT_STATUS_OK(attribute_status);
+  attributes = attribute_status.take();
+  EXPECT_GE(attributes.size(), 2u);
+
+  expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER, DVR_SURFACE_ATTRIBUTE_VISIBLE,
+                   kUserKey};
+
+  actual_keys.clear();
+  actual_keys = compare_keys(attributes, expected_keys);
+  EXPECT_NE(expected_keys, actual_keys);
+
+  // Test deleting a reserved attribute.
+  attributes_to_set = {MakeAttribute(DVR_SURFACE_ATTRIBUTE_VISIBLE, nullptr)};
+
+  EXPECT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
+                                       attributes_to_set.size()));
+
+  // Failed attribute operations should not trigger update events.
+  const int kTimeoutMs = 100;  // 0.1s
+  EXPECT_STATUS_ERROR_VALUE(ETIMEDOUT, manager_->WaitForUpdate(kTimeoutMs));
+
+  attribute_status = manager_->GetAttributes(0);
+  ASSERT_STATUS_OK(attribute_status);
+  attributes = attribute_status.take();
+  EXPECT_GE(attributes.size(), 2u);
+
+  expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER,
+                   DVR_SURFACE_ATTRIBUTE_VISIBLE};
+
+  actual_keys.clear();
+  actual_keys = compare_keys(attributes, expected_keys);
+  EXPECT_EQ(expected_keys, actual_keys);
+}
+
+TEST_F(DvrDisplayManagerTest, SurfaceAttributeTypes) {
+  // Create an application surface.
+  auto surface_status = CreateApplicationSurface();
+  ASSERT_STATUS_OK(surface_status);
+  UniqueDvrSurface surface = surface_status.take();
+  ASSERT_NE(nullptr, surface.get());
+
+  enum : std::int32_t {
+    kInt32Key = 1,
+    kInt64Key,
+    kBoolKey,
+    kFloatKey,
+    kFloat2Key,
+    kFloat3Key,
+    kFloat4Key,
+    kFloat8Key,
+    kFloat16Key,
+  };
+
+  const std::vector<DvrSurfaceAttribute> attributes_to_set = {
+      MakeAttribute(kInt32Key, int32_t{0}),
+      MakeAttribute(kInt64Key, int64_t{0}),
+      MakeAttribute(kBoolKey, false),
+      MakeAttribute(kFloatKey, 0.0f),
+      MakeAttribute(kFloat2Key, std::array<float, 2>{{1.0f, 2.0f}}),
+      MakeAttribute(kFloat3Key, std::array<float, 3>{{3.0f, 4.0f, 5.0f}}),
+      MakeAttribute(kFloat4Key, std::array<float, 4>{{6.0f, 7.0f, 8.0f, 9.0f}}),
+      MakeAttribute(kFloat8Key,
+                    std::array<float, 8>{{10.0f, 11.0f, 12.0f, 13.0f, 14.0f,
+                                          15.0f, 16.0f, 17.0f}}),
+      MakeAttribute(kFloat16Key, std::array<float, 16>{
+                                     {18.0f, 19.0f, 20.0f, 21.0f, 22.0f, 23.0f,
+                                      24.0f, 25.0f, 26.0f, 27.0f, 28.0f, 29.0f,
+                                      30.0f, 31.0f, 32.0f, 33.0f}})};
+
+  EXPECT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
+                                       attributes_to_set.size()));
+
+  ASSERT_STATUS_OK(manager_->WaitForUpdate());
+  auto attribute_status = manager_->GetAttributes(0);
+  ASSERT_STATUS_OK(attribute_status);
+  auto attributes = attribute_status.take();
+  EXPECT_GE(attributes.size(), attributes_to_set.size());
+
+  auto HasAttribute = [](const auto& attributes,
+                         DvrSurfaceAttributeKey key) -> bool {
+    for (const auto& attribute : attributes) {
+      if (attribute.key == key)
+        return true;
+    }
+    return false;
+  };
+  auto AttributeType =
+      [](const auto& attributes,
+         DvrSurfaceAttributeKey key) -> DvrSurfaceAttributeType {
+    for (const auto& attribute : attributes) {
+      if (attribute.key == key)
+        return attribute.value.type;
+    }
+    return DVR_SURFACE_ATTRIBUTE_TYPE_NONE;
+  };
+
+  ASSERT_TRUE(HasAttribute(attributes, kInt32Key));
+  EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
+            AttributeType(attributes, kInt32Key));
+
+  ASSERT_TRUE(HasAttribute(attributes, kInt64Key));
+  EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_INT64,
+            AttributeType(attributes, kInt64Key));
+
+  ASSERT_TRUE(HasAttribute(attributes, kBoolKey));
+  EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+            AttributeType(attributes, kBoolKey));
+
+  ASSERT_TRUE(HasAttribute(attributes, kFloatKey));
+  EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT,
+            AttributeType(attributes, kFloatKey));
+
+  ASSERT_TRUE(HasAttribute(attributes, kFloat2Key));
+  EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT2,
+            AttributeType(attributes, kFloat2Key));
+
+  ASSERT_TRUE(HasAttribute(attributes, kFloat3Key));
+  EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT3,
+            AttributeType(attributes, kFloat3Key));
+
+  ASSERT_TRUE(HasAttribute(attributes, kFloat4Key));
+  EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT4,
+            AttributeType(attributes, kFloat4Key));
+
+  ASSERT_TRUE(HasAttribute(attributes, kFloat8Key));
+  EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT8,
+            AttributeType(attributes, kFloat8Key));
+
+  ASSERT_TRUE(HasAttribute(attributes, kFloat16Key));
+  EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT16,
+            AttributeType(attributes, kFloat16Key));
 }
 
 TEST_F(DvrDisplayManagerTest, SurfaceQueueEvent) {
@@ -480,13 +769,14 @@
   ASSERT_STATUS_OK(manager_->WaitForUpdate());
   ASSERT_STATUS_EQ(1u, manager_->GetSurfaceCount());
 
-  // Verify there are no queues for the surface recorded in the state snapshot.
+  // Verify there are no queues for the surface recorded in the state
+  // snapshot.
   EXPECT_STATUS_EQ(std::vector<int>{}, manager_->GetQueueIds(0));
 
   // Create a new queue in the surface.
   auto write_queue_status = CreateSurfaceQueue(
       surface, 320, 240, AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, 1,
-      AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, 1);
+      AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, 1, 0);
   ASSERT_STATUS_OK(write_queue_status);
   UniqueDvrWriteBufferQueue write_queue = write_queue_status.take();
   ASSERT_NE(nullptr, write_queue.get());
@@ -549,7 +839,7 @@
   const uint32_t kLayerCount = 3;
   auto write_queue_status = CreateSurfaceQueue(
       surface, 320, 240, AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, kLayerCount,
-      AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, 1);
+      AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, 1, 0);
   ASSERT_STATUS_OK(write_queue_status);
   UniqueDvrWriteBufferQueue write_queue = write_queue_status.take();
   ASSERT_NE(nullptr, write_queue.get());
@@ -573,6 +863,24 @@
   dvrWriteBufferDestroy(buffer);
 }
 
+TEST_F(DvrDisplayManagerTest, ConfigurationData) {
+  // TODO(hendrikw): Move this out of the display manager tests.
+  auto data1 = manager_->GetConfigData(-1);
+  ASSERT_STATUS_ERROR(data1);
+
+  const char kDvrLensMetricsProperty[] = "ro.dvr.lens_metrics";
+
+  // This should be run on devices with and without built in metrics.
+  bool has_metric = !base::GetProperty(kDvrLensMetricsProperty, "").empty();
+  auto data2 = manager_->GetConfigData(DVR_CONFIGURATION_DATA_LENS_METRICS);
+  if (has_metric) {
+    ASSERT_STATUS_OK(data2);
+    ASSERT_NE(0u, data2.get().size());
+  } else {
+    ASSERT_STATUS_ERROR(data2);
+  }
+}
+
 }  // namespace
 
 }  // namespace dvr
diff --git a/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp b/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp
index e65f6d5..c21deb0 100644
--- a/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp
@@ -1,6 +1,7 @@
 #include <android/hardware_buffer.h>
 #include <dvr/dvr_buffer.h>
-#include <dvr/dvr_display_manager.h>
+#include <dvr/dvr_config.h>
+#include <dvr/dvr_shared_buffers.h>
 #include <dvr/dvr_surface.h>
 #include <system/graphics.h>
 
@@ -12,33 +13,15 @@
 
 namespace {
 
-class DvrNamedBufferTest : public ::testing::Test {
- protected:
-  void SetUp() override {
-    const int ret = dvrDisplayManagerCreate(&client_);
-    ASSERT_EQ(0, ret);
-    ASSERT_NE(nullptr, client_);
-  }
-
-  void TearDown() override {
-    dvrDisplayManagerDestroy(client_);
-    client_ = nullptr;
-  }
-
-  DvrDisplayManager* client_ = nullptr;
-};
-
-TEST_F(DvrNamedBufferTest, TestNamedBuffersSameName) {
-  const char* buffer_name = "same_name";
+TEST(DvrGlobalBufferTest, TestGlobalBuffersSameName) {
+  const DvrGlobalBufferKey buffer_key = 101;
   DvrBuffer* buffer1 = nullptr;
-  int ret1 =
-      dvrDisplayManagerSetupNamedBuffer(client_, buffer_name, 10, 0, &buffer1);
+  int ret1 = dvrSetupGlobalBuffer(buffer_key, 10, 0, &buffer1);
   ASSERT_EQ(0, ret1);
   ASSERT_NE(nullptr, buffer1);
 
   DvrBuffer* buffer2 = nullptr;
-  int ret2 =
-      dvrDisplayManagerSetupNamedBuffer(client_, buffer_name, 10, 0, &buffer2);
+  int ret2 = dvrSetupGlobalBuffer(buffer_key, 10, 0, &buffer2);
   ASSERT_EQ(0, ret1);
   ASSERT_NE(nullptr, buffer2);
 
@@ -71,7 +54,7 @@
   dvrBufferDestroy(buffer2);
 
   DvrBuffer* buffer3 = nullptr;
-  int e3 = dvrGetNamedBuffer(buffer_name, &buffer3);
+  int e3 = dvrGetGlobalBuffer(buffer_key, &buffer3);
   ASSERT_NE(nullptr, buffer3);
   ASSERT_EQ(0, e3);
 
@@ -95,38 +78,36 @@
   AHardwareBuffer_release(hardware_buffer3);
 }
 
-TEST_F(DvrNamedBufferTest, TestMultipleNamedBuffers) {
-  const char* buffer_name1 = "test1";
-  const char* buffer_name2 = "test2";
+TEST(DvrGlobalBufferTest, TestMultipleGlobalBuffers) {
+  const DvrGlobalBufferKey buffer_key1 = 102;
+  const DvrGlobalBufferKey buffer_key2 = 103;
   DvrBuffer* setup_buffer1 = nullptr;
-  int ret1 = dvrDisplayManagerSetupNamedBuffer(client_, buffer_name1, 10, 0,
-                                               &setup_buffer1);
+  int ret1 = dvrSetupGlobalBuffer(buffer_key1, 10, 0, &setup_buffer1);
   ASSERT_EQ(0, ret1);
   ASSERT_NE(nullptr, setup_buffer1);
   dvrBufferDestroy(setup_buffer1);
 
   DvrBuffer* setup_buffer2 = nullptr;
-  int ret2 = dvrDisplayManagerSetupNamedBuffer(client_, buffer_name2, 10, 0,
-                                               &setup_buffer2);
+  int ret2 = dvrSetupGlobalBuffer(buffer_key2, 10, 0, &setup_buffer2);
   ASSERT_EQ(0, ret2);
   ASSERT_NE(nullptr, setup_buffer2);
   dvrBufferDestroy(setup_buffer2);
 
   DvrBuffer* buffer1 = nullptr;
-  int e1 = dvrGetNamedBuffer(buffer_name1, &buffer1);
+  int e1 = dvrGetGlobalBuffer(buffer_key1, &buffer1);
   ASSERT_NE(nullptr, buffer1);
   ASSERT_EQ(0, e1);
   dvrBufferDestroy(buffer1);
 
   DvrBuffer* buffer2 = nullptr;
-  int e2 = dvrGetNamedBuffer(buffer_name2, &buffer2);
+  int e2 = dvrGetGlobalBuffer(buffer_key2, &buffer2);
   ASSERT_NE(nullptr, buffer2);
   ASSERT_EQ(0, e2);
   dvrBufferDestroy(buffer2);
 }
 
-TEST_F(DvrNamedBufferTest, TestNamedBufferUsage) {
-  const char* buffer_name = "buffer_usage";
+TEST(DvrGlobalBufferTest, TestGlobalBufferUsage) {
+  const DvrGlobalBufferKey buffer_key = 100;
 
   // Set usage to AHARDWAREBUFFER_USAGE_VIDEO_ENCODE. We use this because
   // internally AHARDWAREBUFFER_USAGE_VIDEO_ENCODE is converted to
@@ -136,8 +117,7 @@
   const uint64_t usage = AHARDWAREBUFFER_USAGE_VIDEO_ENCODE;
 
   DvrBuffer* setup_buffer = nullptr;
-  int e1 = dvrDisplayManagerSetupNamedBuffer(client_, buffer_name, 10, usage,
-                                             &setup_buffer);
+  int e1 = dvrSetupGlobalBuffer(buffer_key, 10, usage, &setup_buffer);
   ASSERT_NE(nullptr, setup_buffer);
   ASSERT_EQ(0, e1);
 
@@ -154,6 +134,151 @@
   AHardwareBuffer_release(hardware_buffer);
 }
 
+TEST(DvrGlobalBufferTest, TestGlobalBufferCarriesData) {
+  const DvrGlobalBufferKey buffer_name = 110;
+
+  uint64_t usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
+                   AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
+  constexpr size_t size = 1024 * sizeof(uint64_t);
+  constexpr uint64_t value = 0x123456787654321;
+
+  {
+    // Allocate some data and set it to something.
+    DvrBuffer* setup_buffer = nullptr;
+    int e1 = dvrSetupGlobalBuffer(buffer_name, size, usage, &setup_buffer);
+    ASSERT_NE(nullptr, setup_buffer);
+    ASSERT_EQ(0, e1);
+
+    AHardwareBuffer* hardware_buffer = nullptr;
+    int e2 = dvrBufferGetAHardwareBuffer(setup_buffer, &hardware_buffer);
+    ASSERT_EQ(0, e2);
+    ASSERT_NE(nullptr, hardware_buffer);
+
+    void* buffer;
+    int e3 = AHardwareBuffer_lock(hardware_buffer, usage, -1, nullptr, &buffer);
+    ASSERT_EQ(0, e3);
+    ASSERT_NE(nullptr, buffer);
+    // Verify that the buffer pointer is at least 16 byte aligned.
+    ASSERT_EQ(0, reinterpret_cast<uintptr_t>(buffer) & (16 - 1));
+
+    uint64_t* data = static_cast<uint64_t*>(buffer);
+    constexpr size_t num_values = size / sizeof(uint64_t);
+    for (size_t i = 0; i < num_values; ++i) {
+      data[i] = value;
+    }
+
+    int32_t fence = -1;
+    int e4 = AHardwareBuffer_unlock(hardware_buffer, &fence);
+    ASSERT_EQ(0, e4);
+
+    dvrBufferDestroy(setup_buffer);
+    AHardwareBuffer_release(hardware_buffer);
+  }
+
+  {
+    // Get the buffer and check that all the data is still present.
+    DvrBuffer* setup_buffer = nullptr;
+    int e1 = dvrGetGlobalBuffer(buffer_name, &setup_buffer);
+    ASSERT_NE(nullptr, setup_buffer);
+    ASSERT_EQ(0, e1);
+
+    AHardwareBuffer* hardware_buffer = nullptr;
+    int e2 = dvrBufferGetAHardwareBuffer(setup_buffer, &hardware_buffer);
+    ASSERT_EQ(0, e2);
+    ASSERT_NE(nullptr, hardware_buffer);
+
+    void* buffer;
+    int e3 = AHardwareBuffer_lock(hardware_buffer, usage, -1, nullptr, &buffer);
+    ASSERT_EQ(0, e3);
+    ASSERT_NE(nullptr, buffer);
+    // Verify that the buffer pointer is at least 16 byte aligned.
+    ASSERT_EQ(0, reinterpret_cast<uintptr_t>(buffer) & (16 - 1));
+
+    uint64_t* data = static_cast<uint64_t*>(buffer);
+    constexpr size_t num_values = size / sizeof(uint64_t);
+    bool is_equal = true;
+    for (size_t i = 0; i < num_values; ++i) {
+      is_equal &= (data[i] == value);
+    }
+    ASSERT_TRUE(is_equal);
+
+    int32_t fence = -1;
+    int e4 = AHardwareBuffer_unlock(hardware_buffer, &fence);
+    ASSERT_EQ(0, e4);
+
+    dvrBufferDestroy(setup_buffer);
+    AHardwareBuffer_release(hardware_buffer);
+  }
+}
+
+TEST(DvrGlobalBufferTest, TestGlobalBufferZeroed) {
+  const DvrGlobalBufferKey buffer_name = 120;
+
+  // Allocate 1MB and check that it is all zeros.
+  uint64_t usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
+                   AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
+  constexpr size_t size = 1024 * 1024;
+  DvrBuffer* setup_buffer = nullptr;
+  int e1 = dvrSetupGlobalBuffer(buffer_name, size, usage, &setup_buffer);
+  ASSERT_NE(nullptr, setup_buffer);
+  ASSERT_EQ(0, e1);
+
+  AHardwareBuffer* hardware_buffer = nullptr;
+  int e2 = dvrBufferGetAHardwareBuffer(setup_buffer, &hardware_buffer);
+  ASSERT_EQ(0, e2);
+  ASSERT_NE(nullptr, hardware_buffer);
+
+  void* buffer;
+  int e3 = AHardwareBuffer_lock(hardware_buffer, usage, -1, nullptr, &buffer);
+  ASSERT_EQ(0, e3);
+  ASSERT_NE(nullptr, buffer);
+  // Verify that the buffer pointer is at least 16 byte aligned.
+  ASSERT_EQ(0, reinterpret_cast<uintptr_t>(buffer) & (16 - 1));
+
+  uint64_t* data = static_cast<uint64_t*>(buffer);
+  constexpr size_t num_values = size / sizeof(uint64_t);
+  uint64_t zero = 0;
+  for (size_t i = 0; i < num_values; ++i) {
+    zero |= data[i];
+  }
+  ASSERT_EQ(0, zero);
+
+  int32_t fence = -1;
+  int e4 = AHardwareBuffer_unlock(hardware_buffer, &fence);
+  ASSERT_EQ(0, e4);
+
+  dvrBufferDestroy(setup_buffer);
+  AHardwareBuffer_release(hardware_buffer);
+}
+
+TEST(DvrGlobalBufferTest, TestVrflingerConfigBuffer) {
+  const DvrGlobalBufferKey buffer_name =
+      DvrGlobalBuffers::kVrFlingerConfigBufferKey;
+
+  // First delete any existing buffer so we can test the failure case.
+  dvrDeleteGlobalBuffer(buffer_name);
+
+  const uint64_t usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
+                         AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY;
+
+  size_t correct_size = DvrConfigRing::MemorySize();
+  size_t wrong_size = DvrConfigRing::MemorySize(0);
+
+  // Setup an invalid config buffer (too small) and assert that it fails.
+  DvrBuffer* setup_buffer = nullptr;
+  int e1 = dvrSetupGlobalBuffer(buffer_name, wrong_size, usage, &setup_buffer);
+  ASSERT_EQ(nullptr, setup_buffer);
+  ASSERT_GT(0, e1);
+
+  // Setup a correct config buffer.
+  int e2 =
+      dvrSetupGlobalBuffer(buffer_name, correct_size, usage, &setup_buffer);
+  ASSERT_NE(nullptr, setup_buffer);
+  ASSERT_EQ(0, e2);
+
+  dvrBufferDestroy(setup_buffer);
+}
+
 }  // namespace
 
 }  // namespace dvr
diff --git a/libs/vr/libdvrcommon/Android.bp b/libs/vr/libdvrcommon/Android.bp
index 527cdbd..62aeb79 100644
--- a/libs/vr/libdvrcommon/Android.bp
+++ b/libs/vr/libdvrcommon/Android.bp
@@ -28,7 +28,7 @@
     "libhardware",
 ]
 
-staticLibraries = ["libpdx_default_transport"]
+staticLibraries = ["libpdx_default_transport", "libbroadcastring"]
 
 headerLibraries = [
     "libeigen",
diff --git a/libs/vr/libpdx/private/pdx/rpc/variant.h b/libs/vr/libpdx/private/pdx/rpc/variant.h
index cb44a51..80b1769 100644
--- a/libs/vr/libpdx/private/pdx/rpc/variant.h
+++ b/libs/vr/libpdx/private/pdx/rpc/variant.h
@@ -26,14 +26,35 @@
 template <std::size_t I, typename... Types>
 using TypeTagForIndex = TypeTag<TypeForIndex<I, Types...>>;
 
+// Similar to std::is_constructible except that it evaluates to false for bool
+// construction from pointer types: this helps prevent subtle to bugs caused by
+// assigning values that decay to pointers to Variants with bool elements.
+//
+// Here is an example of the problematic situation this trait avoids:
+//
+//  Variant<int, bool> v;
+//  const int array[3] = {1, 2, 3};
+//  v = array; // This is allowed by regular std::is_constructible.
+//
+template <typename...>
+struct IsConstructible;
+template <typename T, typename U>
+struct IsConstructible<T, U>
+    : std::integral_constant<bool,
+                             std::is_constructible<T, U>::value &&
+                                 !(std::is_same<std::decay_t<T>, bool>::value &&
+                                   std::is_pointer<std::decay_t<U>>::value)> {};
+template <typename T, typename... Args>
+struct IsConstructible<T, Args...> : std::is_constructible<T, Args...> {};
+
 // Enable if T(Args...) is well formed.
 template <typename R, typename T, typename... Args>
 using EnableIfConstructible =
-    typename std::enable_if<std::is_constructible<T, Args...>::value, R>::type;
+    typename std::enable_if<IsConstructible<T, Args...>::value, R>::type;
 // Enable if T(Args...) is not well formed.
 template <typename R, typename T, typename... Args>
 using EnableIfNotConstructible =
-    typename std::enable_if<!std::is_constructible<T, Args...>::value, R>::type;
+    typename std::enable_if<!IsConstructible<T, Args...>::value, R>::type;
 
 // Determines whether T is an element of Types...;
 template <typename... Types>
@@ -65,12 +86,11 @@
 struct ConstructibleCount;
 template <typename From, typename To>
 struct ConstructibleCount<From, To>
-    : std::integral_constant<std::size_t,
-                             std::is_constructible<To, From>::value> {};
+    : std::integral_constant<std::size_t, IsConstructible<To, From>::value> {};
 template <typename From, typename First, typename... Rest>
 struct ConstructibleCount<From, First, Rest...>
     : std::integral_constant<std::size_t,
-                             std::is_constructible<First, From>::value +
+                             IsConstructible<First, From>::value +
                                  ConstructibleCount<From, Rest...>::value> {};
 
 // Enable if T is an element of Types...
@@ -126,6 +146,18 @@
       : first_(std::forward<T>(value)) {
     *index_out = index;
   }
+  Union(const Union& other, std::int32_t index) {
+    if (index == 0)
+      new (&first_) Type(other.first_);
+  }
+  Union(Union&& other, std::int32_t index) {
+    if (index == 0)
+      new (&first_) Type(std::move(other.first_));
+  }
+  Union(const Union&) = delete;
+  Union(Union&&) = delete;
+  void operator=(const Union&) = delete;
+  void operator=(Union&&) = delete;
 
   Type& get(TypeTag<Type>) { return first_; }
   const Type& get(TypeTag<Type>) const { return first_; }
@@ -217,6 +249,22 @@
   template <typename T, typename U>
   Union(std::int32_t index, std::int32_t* index_out, TypeTag<T>, U&& value)
       : rest_(index + 1, index_out, TypeTag<T>{}, std::forward<U>(value)) {}
+  Union(const Union& other, std::int32_t index) {
+    if (index == 0)
+      new (&first_) First(other.first_);
+    else
+      new (&rest_) Union<Rest...>(other.rest_, index - 1);
+  }
+  Union(Union&& other, std::int32_t index) {
+    if (index == 0)
+      new (&first_) First(std::move(other.first_));
+    else
+      new (&rest_) Union<Rest...>(std::move(other.rest_), index - 1);
+  }
+  Union(const Union&) = delete;
+  Union(Union&&) = delete;
+  void operator=(const Union&) = delete;
+  void operator=(Union&&) = delete;
 
   struct FirstType {};
   struct RestType {};
@@ -351,6 +399,10 @@
 
 }  // namespace detail
 
+// Variant is a type safe union that can store values of any of its element
+// types. A Variant is different than std::tuple in that it only stores one type
+// at a time or a special empty type. Variants are always default constructible
+// to empty, even when none of the element types are default constructible.
 template <typename... Types>
 class Variant {
  private:
@@ -393,6 +445,11 @@
   explicit Variant(EmptyVariant) {}
   ~Variant() { Destruct(); }
 
+  Variant(const Variant& other)
+      : index_{other.index_}, value_{other.value_, other.index_} {}
+  Variant(Variant&& other)
+      : index_{other.index_}, value_{std::move(other.value_), other.index_} {}
+
   // Copy and move construction from Variant types. Each element of OtherTypes
   // must be convertible to an element of Types.
   template <typename... OtherTypes>
@@ -404,6 +461,15 @@
     other.Visit([this](auto&& value) { Construct(std::move(value)); });
   }
 
+  Variant& operator=(const Variant& other) {
+    other.Visit([this](const auto& value) { *this = value; });
+    return *this;
+  }
+  Variant& operator=(Variant&& other) {
+    other.Visit([this](auto&& value) { *this = std::move(value); });
+    return *this;
+  }
+
   // Construction from non-Variant types.
   template <typename T, typename = EnableIfAssignable<void, T>>
   explicit Variant(T&& value)
@@ -429,7 +495,7 @@
   // Handles assignment from the empty type. This overload supports assignment
   // in visitors using generic lambdas.
   Variant& operator=(EmptyVariant) {
-    Assign(EmptyVariant{});
+    Destruct();
     return *this;
   }
 
@@ -541,7 +607,10 @@
   void Construct(EmptyVariant) {}
 
   // Destroys the active element of the Variant.
-  void Destruct() { value_.Destruct(index_); }
+  void Destruct() {
+    value_.Destruct(index_);
+    index_ = kEmptyIndex;
+  }
 
   // Assigns the Variant when non-empty and the current type matches the target
   // type, otherwise destroys the current value and constructs a element of the
@@ -562,8 +631,6 @@
       Construct(std::forward<T>(value));
     }
   }
-  // Handles assignment from an empty Variant.
-  void Assign(EmptyVariant) { Destruct(); }
 };
 
 // Utility type to extract/convert values from a variant. This class simplifies
diff --git a/libs/vr/libpdx/private/pdx/utility.h b/libs/vr/libpdx/private/pdx/utility.h
index 305c3b8..08fcaea 100644
--- a/libs/vr/libpdx/private/pdx/utility.h
+++ b/libs/vr/libpdx/private/pdx/utility.h
@@ -2,6 +2,7 @@
 #define ANDROID_PDX_UTILITY_H_
 
 #include <cstdint>
+#include <cstdlib>
 #include <iterator>
 
 #include <pdx/rpc/sequence.h>
@@ -23,6 +24,7 @@
     if (other.size())
       memcpy(data_, other.data(), other.size());
   }
+  ~ByteBuffer() { std::free(data_); }
 
   ByteBuffer& operator=(const ByteBuffer& other) {
     resize(other.size());
@@ -69,7 +71,7 @@
     size |= size >> 8;
     size |= size >> 16;
     size++;
-    void* new_data = data_ ? realloc(data_, size) : malloc(size);
+    void* new_data = data_ ? std::realloc(data_, size) : std::malloc(size);
     // TODO(avakulenko): Check for allocation failures.
     data_ = static_cast<uint8_t*>(new_data);
     capacity_ = size;
diff --git a/libs/vr/libpdx/variant_tests.cpp b/libs/vr/libpdx/variant_tests.cpp
index 325f33f..e3520f5 100644
--- a/libs/vr/libpdx/variant_tests.cpp
+++ b/libs/vr/libpdx/variant_tests.cpp
@@ -1,3 +1,4 @@
+#include <array>
 #include <cstdint>
 #include <functional>
 #include <memory>
@@ -584,6 +585,25 @@
     EXPECT_EQ(0u, InstrumentType<int>::move_assignment_count());
     EXPECT_EQ(1u, InstrumentType<int>::copy_assignment_count());
   }
+
+  {
+    InstrumentType<int>::clear();
+
+    // Construct from temporary, temporary ctor/dtor.
+    Variant<int, InstrumentType<int>> v(InstrumentType<int>(25));
+
+    // Assign EmptyVariant.
+    v = EmptyVariant{};
+
+    EXPECT_EQ(2u, InstrumentType<int>::constructor_count());
+    EXPECT_EQ(2u, InstrumentType<int>::destructor_count());
+    EXPECT_EQ(0u, InstrumentType<int>::move_assignment_count());
+    EXPECT_EQ(0u, InstrumentType<int>::copy_assignment_count());
+  }
+  EXPECT_EQ(2u, InstrumentType<int>::constructor_count());
+  EXPECT_EQ(2u, InstrumentType<int>::destructor_count());
+  EXPECT_EQ(0u, InstrumentType<int>::move_assignment_count());
+  EXPECT_EQ(0u, InstrumentType<int>::copy_assignment_count());
 }
 
 TEST(Variant, MoveConstructor) {
@@ -758,7 +778,7 @@
     Variant<std::string> b;
 
     std::swap(a, b);
-    EXPECT_TRUE(!a.empty());
+    EXPECT_TRUE(a.empty());
     EXPECT_TRUE(!b.empty());
     ASSERT_TRUE(b.is<std::string>());
     EXPECT_EQ("1", std::get<std::string>(b));
@@ -770,7 +790,7 @@
 
     std::swap(a, b);
     EXPECT_TRUE(!a.empty());
-    EXPECT_TRUE(!b.empty());
+    EXPECT_TRUE(b.empty());
     ASSERT_TRUE(a.is<std::string>());
     EXPECT_EQ("1", std::get<std::string>(a));
   }
@@ -1078,6 +1098,29 @@
   EXPECT_FALSE((detail::HasType<char&, int, float, bool>::value));
 }
 
+TEST(Variant, IsConstructible) {
+  using ArrayType = const float[3];
+  struct ImplicitBool {
+    operator bool() const { return true; }
+  };
+  struct ExplicitBool {
+    explicit operator bool() const { return true; }
+  };
+  struct NonBool {};
+  struct TwoArgs {
+    TwoArgs(int, bool) {}
+  };
+
+  EXPECT_FALSE((detail::IsConstructible<bool, ArrayType>::value));
+  EXPECT_TRUE((detail::IsConstructible<bool, int>::value));
+  EXPECT_TRUE((detail::IsConstructible<bool, ImplicitBool>::value));
+  EXPECT_TRUE((detail::IsConstructible<bool, ExplicitBool>::value));
+  EXPECT_FALSE((detail::IsConstructible<bool, NonBool>::value));
+  EXPECT_TRUE((detail::IsConstructible<TwoArgs, int, bool>::value));
+  EXPECT_FALSE((detail::IsConstructible<TwoArgs, int, std::string>::value));
+  EXPECT_FALSE((detail::IsConstructible<TwoArgs, int>::value));
+}
+
 TEST(Variant, Set) {
   EXPECT_TRUE((detail::Set<int, bool, float>::template IsSubset<int, bool,
                                                                 float>::value));
diff --git a/libs/vr/libpdx_uds/channel_event_set.cpp b/libs/vr/libpdx_uds/channel_event_set.cpp
index ac4dea9..ebe7cea 100644
--- a/libs/vr/libpdx_uds/channel_event_set.cpp
+++ b/libs/vr/libpdx_uds/channel_event_set.cpp
@@ -100,6 +100,9 @@
     ALOGE("ChannelEventReceiver::GetPendingEvents: Failed to get events: %s",
           status.GetErrorMessage().c_str());
     return status;
+  } else if (count == 0) {
+    status.SetError(ETIMEDOUT);
+    return status;
   }
 
   const int mask_out = event.data.u32;
diff --git a/libs/vr/libperformance/include/dvr/performance_client_api.h b/libs/vr/libperformance/include/dvr/performance_client_api.h
index 2216e38..9d617cb 100644
--- a/libs/vr/libperformance/include/dvr/performance_client_api.h
+++ b/libs/vr/libperformance/include/dvr/performance_client_api.h
@@ -8,6 +8,20 @@
 extern "C" {
 #endif
 
+/// Sets the scheduler policy for a task.
+///
+/// Sets the scheduler policy for a task to the class described by a semantic
+/// string.
+///
+/// Supported policies are device-specific.
+///
+/// @param task_id The task id of task to set the policy for. When task_id is 0
+/// the current task id is substituted.
+/// @param scheduler_policy NULL-terminated ASCII string containing the desired
+/// scheduler policy.
+/// @returns Returns 0 on success or a negative errno error code on error.
+int dvrSetSchedulerPolicy(pid_t task_id, const char* scheduler_policy);
+
 /// Sets the CPU partition for a task.
 ///
 /// Sets the CPU partition for a task to the partition described by a CPU
diff --git a/libs/vr/libperformance/include/private/dvr/performance_client.h b/libs/vr/libperformance/include/private/dvr/performance_client.h
index a61c6b2..3bd90dc 100644
--- a/libs/vr/libperformance/include/private/dvr/performance_client.h
+++ b/libs/vr/libperformance/include/private/dvr/performance_client.h
@@ -14,6 +14,10 @@
 
 class PerformanceClient : public pdx::ClientBase<PerformanceClient> {
  public:
+  int SetSchedulerPolicy(pid_t task_id, const std::string& scheduler_policy);
+  int SetSchedulerPolicy(pid_t task_id, const char* scheduler_policy);
+
+  // TODO(eieio): Consider deprecating this API.
   int SetCpuPartition(pid_t task_id, const std::string& partition);
   int SetCpuPartition(pid_t task_id, const char* partition);
   int SetSchedulerClass(pid_t task_id, const std::string& scheduler_class);
diff --git a/libs/vr/libperformance/include/private/dvr/performance_rpc.h b/libs/vr/libperformance/include/private/dvr/performance_rpc.h
index 73bdaa7..d57bbe8 100644
--- a/libs/vr/libperformance/include/private/dvr/performance_rpc.h
+++ b/libs/vr/libperformance/include/private/dvr/performance_rpc.h
@@ -21,14 +21,17 @@
     kOpSetCpuPartition = 0,
     kOpSetSchedulerClass,
     kOpGetCpuPartition,
+    kOpSetSchedulerPolicy,
   };
 
   // Methods.
   PDX_REMOTE_METHOD(SetCpuPartition, kOpSetCpuPartition,
-                    int(pid_t, const std::string&));
+                    void(pid_t, const std::string&));
   PDX_REMOTE_METHOD(SetSchedulerClass, kOpSetSchedulerClass,
-                    int(pid_t, const std::string&));
+                    void(pid_t, const std::string&));
   PDX_REMOTE_METHOD(GetCpuPartition, kOpGetCpuPartition, std::string(pid_t));
+  PDX_REMOTE_METHOD(SetSchedulerPolicy, kOpSetSchedulerPolicy,
+                    void(pid_t, const std::string&));
 };
 
 }  // namespace dvr
diff --git a/libs/vr/libperformance/performance_client.cpp b/libs/vr/libperformance/performance_client.cpp
index 2124162..bf3726e 100644
--- a/libs/vr/libperformance/performance_client.cpp
+++ b/libs/vr/libperformance/performance_client.cpp
@@ -37,6 +37,26 @@
           task_id, WrapString(partition)));
 }
 
+int PerformanceClient::SetSchedulerPolicy(pid_t task_id,
+                                          const std::string& scheduler_policy) {
+  if (task_id == 0)
+    task_id = gettid();
+
+  return ReturnStatusOrError(
+      InvokeRemoteMethod<PerformanceRPC::SetSchedulerPolicy>(task_id,
+                                                             scheduler_policy));
+}
+
+int PerformanceClient::SetSchedulerPolicy(pid_t task_id,
+                                          const char* scheduler_policy) {
+  if (task_id == 0)
+    task_id = gettid();
+
+  return ReturnStatusOrError(
+      InvokeRemoteMethod<PerformanceRPC::SetSchedulerPolicy>(
+          task_id, WrapString(scheduler_policy)));
+}
+
 int PerformanceClient::SetSchedulerClass(pid_t task_id,
                                          const std::string& scheduler_class) {
   if (task_id == 0)
@@ -101,6 +121,15 @@
     return error;
 }
 
+extern "C" int dvrSetSchedulerPolicy(pid_t task_id,
+                                     const char* scheduler_policy) {
+  int error;
+  if (auto client = android::dvr::PerformanceClient::Create(&error))
+    return client->SetSchedulerPolicy(task_id, scheduler_policy);
+  else
+    return error;
+}
+
 extern "C" int dvrSetSchedulerClass(pid_t task_id,
                                     const char* scheduler_class) {
   int error;
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index de26a74..0fb2d84 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -34,8 +34,10 @@
     "libdvrcommon",
     "libperformance",
     "libvrsensor",
+    "libbroadcastring",
     "libpdx_default_transport",
     "libvr_manager",
+    "libbroadcastring",
 ]
 
 sharedLibraries = [
@@ -61,6 +63,10 @@
     "libfmq",
 ]
 
+headerLibraries = [
+    "libdvr_headers"
+]
+
 cc_library_static {
     srcs: sourceFiles,
     export_include_dirs: includeFiles,
@@ -74,5 +80,6 @@
     ],
     shared_libs: sharedLibraries,
     whole_static_libs: staticLibraries,
+    header_libs: headerLibraries,
     name: "libvrflinger",
 }
diff --git a/libs/vr/libvrflinger/acquired_buffer.cpp b/libs/vr/libvrflinger/acquired_buffer.cpp
index 7932a9c..fda9585 100644
--- a/libs/vr/libvrflinger/acquired_buffer.cpp
+++ b/libs/vr/libvrflinger/acquired_buffer.cpp
@@ -55,9 +55,9 @@
   if (acquire_fence_) {
     const int ret = sync_wait(acquire_fence_.Get(), 0);
     ALOGD_IF(TRACE || (ret < 0 && errno != ETIME),
-             "AcquiredBuffer::IsAvailable: acquire_fence_=%d sync_wait()=%d "
-             "errno=%d.",
-             acquire_fence_.Get(), ret, ret < 0 ? errno : 0);
+             "AcquiredBuffer::IsAvailable: buffer_id=%d acquire_fence=%d "
+             "sync_wait()=%d errno=%d.",
+             buffer_->id(), acquire_fence_.Get(), ret, ret < 0 ? errno : 0);
     if (ret == 0) {
       // The fence is completed, so to avoid further calls to sync_wait we close
       // it here.
@@ -78,6 +78,8 @@
 }
 
 int AcquiredBuffer::Release(LocalHandle release_fence) {
+  ALOGD_IF(TRACE, "AcquiredBuffer::Release: buffer_id=%d release_fence=%d",
+           buffer_ ? buffer_->id() : -1, release_fence.Get());
   if (buffer_) {
     // Close the release fence since we can't transfer it with an async release.
     release_fence.Close();
diff --git a/libs/vr/libvrflinger/acquired_buffer.h b/libs/vr/libvrflinger/acquired_buffer.h
index dd4fcc5..e0dc9f2 100644
--- a/libs/vr/libvrflinger/acquired_buffer.h
+++ b/libs/vr/libvrflinger/acquired_buffer.h
@@ -67,13 +67,13 @@
   int Release(pdx::LocalHandle release_fence);
 
  private:
-  AcquiredBuffer(const AcquiredBuffer&) = delete;
-  void operator=(const AcquiredBuffer&) = delete;
-
   std::shared_ptr<BufferConsumer> buffer_;
   // Mutable so that the fence can be closed when it is determined to be
   // signaled during IsAvailable().
   mutable pdx::LocalHandle acquire_fence_;
+
+  AcquiredBuffer(const AcquiredBuffer&) = delete;
+  void operator=(const AcquiredBuffer&) = delete;
 };
 
 }  // namespace dvr
diff --git a/libs/vr/libvrflinger/display_manager_service.cpp b/libs/vr/libvrflinger/display_manager_service.cpp
index a0b3efe..40396b9 100644
--- a/libs/vr/libvrflinger/display_manager_service.cpp
+++ b/libs/vr/libvrflinger/display_manager_service.cpp
@@ -78,11 +78,6 @@
           *this, &DisplayManagerService::OnGetSurfaceQueue, message);
       return {};
 
-    case DisplayManagerProtocol::SetupNamedBuffer::Opcode:
-      DispatchRemoteMethod<DisplayManagerProtocol::SetupNamedBuffer>(
-          *this, &DisplayManagerService::OnSetupNamedBuffer, message);
-      return {};
-
     default:
       return Service::DefaultHandleMessage(message);
   }
@@ -129,23 +124,6 @@
   return status;
 }
 
-pdx::Status<BorrowedNativeBufferHandle>
-DisplayManagerService::OnSetupNamedBuffer(pdx::Message& message,
-                                          const std::string& name, size_t size,
-                                          uint64_t usage) {
-  const int user_id = message.GetEffectiveUserId();
-  const bool trusted = user_id == AID_ROOT || IsTrustedUid(user_id);
-
-  if (!trusted) {
-    ALOGE(
-        "DisplayService::SetupNamedBuffer: Named buffers may only be created "
-        "by trusted UIDs: user_id=%d",
-        user_id);
-    return ErrorStatus(EPERM);
-  }
-  return display_service_->SetupNamedBuffer(name, size, usage);
-}
-
 void DisplayManagerService::OnDisplaySurfaceChange() {
   if (display_manager_)
     display_manager_->SetNotificationsPending(true);
diff --git a/libs/vr/libvrflinger/display_manager_service.h b/libs/vr/libvrflinger/display_manager_service.h
index 0857eb5..3133fe1 100644
--- a/libs/vr/libvrflinger/display_manager_service.h
+++ b/libs/vr/libvrflinger/display_manager_service.h
@@ -56,9 +56,6 @@
   pdx::Status<pdx::LocalChannelHandle> OnGetSurfaceQueue(pdx::Message& message,
                                                          int surface_id,
                                                          int queue_id);
-  pdx::Status<BorrowedNativeBufferHandle> OnSetupNamedBuffer(
-      pdx::Message& message, const std::string& name, size_t size,
-      uint64_t usage);
 
   // Called by the display service to indicate changes to display surfaces that
   // the display manager should evaluate.
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index 47efa76..733edc6 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -1,13 +1,21 @@
 #include "display_service.h"
 
 #include <unistd.h>
+
+#include <algorithm>
+#include <sstream>
+#include <string>
 #include <vector>
 
+#include <android-base/file.h>
+#include <android-base/properties.h>
 #include <dvr/dvr_display_types.h>
 #include <pdx/default_transport/service_endpoint.h>
 #include <pdx/rpc/remote_method.h>
+#include <private/android_filesystem_config.h>
 #include <private/dvr/display_protocol.h>
 #include <private/dvr/numeric.h>
+#include <private/dvr/trusted_uids.h>
 #include <private/dvr/types.h>
 
 using android::dvr::display::DisplayProtocol;
@@ -18,6 +26,14 @@
 using android::pdx::default_transport::Endpoint;
 using android::pdx::rpc::DispatchRemoteMethod;
 
+namespace {
+
+const char kDvrLensMetricsProperty[] = "ro.dvr.lens_metrics";
+const char kDvrDeviceMetricsProperty[] = "ro.dvr.device_metrics";
+const char kDvrDeviceConfigProperty[] = "ro.dvr.device_configuration";
+
+}  // namespace
+
 namespace android {
 namespace dvr {
 
@@ -35,7 +51,65 @@
 }
 
 std::string DisplayService::DumpState(size_t /*max_length*/) {
-  return hardware_composer_.Dump();
+  std::ostringstream stream;
+
+  auto surfaces = GetDisplaySurfaces();
+  std::sort(surfaces.begin(), surfaces.end(), [](const auto& a, const auto& b) {
+    return a->surface_id() < b->surface_id();
+  });
+
+  stream << "Application Surfaces:" << std::endl;
+
+  size_t count = 0;
+  for (const auto& surface : surfaces) {
+    if (surface->surface_type() == SurfaceType::Application) {
+      stream << "Surface " << count++ << ":";
+      stream << " surface_id=" << surface->surface_id()
+             << " process_id=" << surface->process_id()
+             << " user_id=" << surface->user_id()
+             << " visible=" << surface->visible()
+             << " z_order=" << surface->z_order();
+
+      stream << " queue_ids=";
+      auto queue_ids = surface->GetQueueIds();
+      std::sort(queue_ids.begin(), queue_ids.end());
+      for (int32_t id : queue_ids) {
+        if (id != queue_ids[0])
+          stream << ",";
+        stream << id;
+      }
+      stream << std::endl;
+    }
+  }
+  stream << std::endl;
+
+  stream << "Direct Surfaces:" << std::endl;
+
+  count = 0;
+  for (const auto& surface : surfaces) {
+    if (surface->surface_type() == SurfaceType::Direct) {
+      stream << "Surface " << count++ << ":";
+      stream << " surface_id=" << surface->surface_id()
+             << " process_id=" << surface->process_id()
+             << " user_id=" << surface->user_id()
+             << " visible=" << surface->visible()
+             << " z_order=" << surface->z_order();
+
+      stream << " queue_ids=";
+      auto queue_ids = surface->GetQueueIds();
+      std::sort(queue_ids.begin(), queue_ids.end());
+      for (int32_t id : queue_ids) {
+        if (id != queue_ids[0])
+          stream << ",";
+        stream << id;
+      }
+      stream << std::endl;
+    }
+  }
+  stream << std::endl;
+
+  stream << hardware_composer_.Dump();
+  return stream.str();
 }
 
 void DisplayService::OnChannelClose(pdx::Message& message,
@@ -44,8 +118,6 @@
     surface->OnSetAttributes(message,
                              {{display::SurfaceAttribute::Visible,
                                display::SurfaceAttributeValue{false}}});
-    SurfaceUpdated(surface->surface_type(),
-                   display::SurfaceUpdateFlags::VisibilityChanged);
   }
 }
 
@@ -60,14 +132,29 @@
           *this, &DisplayService::OnGetMetrics, message);
       return {};
 
+    case DisplayProtocol::GetConfigurationData::Opcode:
+      DispatchRemoteMethod<DisplayProtocol::GetConfigurationData>(
+          *this, &DisplayService::OnGetConfigurationData, message);
+      return {};
+
     case DisplayProtocol::CreateSurface::Opcode:
       DispatchRemoteMethod<DisplayProtocol::CreateSurface>(
           *this, &DisplayService::OnCreateSurface, message);
       return {};
 
-    case DisplayProtocol::GetNamedBuffer::Opcode:
-      DispatchRemoteMethod<DisplayProtocol::GetNamedBuffer>(
-          *this, &DisplayService::OnGetNamedBuffer, message);
+    case DisplayProtocol::SetupGlobalBuffer::Opcode:
+      DispatchRemoteMethod<DisplayProtocol::SetupGlobalBuffer>(
+          *this, &DisplayService::OnSetupGlobalBuffer, message);
+      return {};
+
+    case DisplayProtocol::DeleteGlobalBuffer::Opcode:
+      DispatchRemoteMethod<DisplayProtocol::DeleteGlobalBuffer>(
+          *this, &DisplayService::OnDeleteGlobalBuffer, message);
+      return {};
+
+    case DisplayProtocol::GetGlobalBuffer::Opcode:
+      DispatchRemoteMethod<DisplayProtocol::GetGlobalBuffer>(
+          *this, &DisplayService::OnGetGlobalBuffer, message);
       return {};
 
     case DisplayProtocol::IsVrAppRunning::Opcode:
@@ -102,6 +189,35 @@
            {}}};
 }
 
+pdx::Status<std::string> DisplayService::OnGetConfigurationData(
+    pdx::Message& /*message*/, display::ConfigFileType config_type) {
+  std::string property_name;
+  switch (config_type) {
+    case display::ConfigFileType::kLensMetrics:
+      property_name = kDvrLensMetricsProperty;
+      break;
+    case display::ConfigFileType::kDeviceMetrics:
+      property_name = kDvrDeviceMetricsProperty;
+      break;
+    case display::ConfigFileType::kDeviceConfiguration:
+      property_name = kDvrDeviceConfigProperty;
+      break;
+    default:
+      return ErrorStatus(EINVAL);
+  }
+  std::string file_path = base::GetProperty(property_name, "");
+  if (file_path.empty()) {
+    return ErrorStatus(ENOENT);
+  }
+
+  std::string data;
+  if (!base::ReadFileToString(file_path, &data)) {
+    return ErrorStatus(errno);
+  }
+
+  return std::move(data);
+}
+
 // Creates a new DisplaySurface and associates it with this channel. This may
 // only be done once per channel.
 Status<display::SurfaceInfo> DisplayService::OnCreateSurface(
@@ -155,12 +271,42 @@
   }
 }
 
-pdx::Status<BorrowedNativeBufferHandle> DisplayService::OnGetNamedBuffer(
-    pdx::Message& /* message */, const std::string& name) {
-  ALOGD_IF(TRACE, "displayService::OnGetNamedBuffer: name=%s", name.c_str());
-  auto named_buffer = named_buffers_.find(name);
-  if (named_buffer != named_buffers_.end())
-    return {BorrowedNativeBufferHandle(*named_buffer->second, 0)};
+pdx::Status<BorrowedNativeBufferHandle> DisplayService::OnSetupGlobalBuffer(
+    pdx::Message& message, DvrGlobalBufferKey key, size_t size,
+    uint64_t usage) {
+  const int user_id = message.GetEffectiveUserId();
+  const bool trusted = user_id == AID_ROOT || IsTrustedUid(user_id);
+
+  if (!trusted) {
+    ALOGE(
+        "DisplayService::OnSetupGlobalBuffer: Permission denied for user_id=%d",
+        user_id);
+    return ErrorStatus(EPERM);
+  }
+  return SetupGlobalBuffer(key, size, usage);
+}
+
+pdx::Status<void> DisplayService::OnDeleteGlobalBuffer(pdx::Message& message,
+                                                       DvrGlobalBufferKey key) {
+  const int user_id = message.GetEffectiveUserId();
+  const bool trusted = (user_id == AID_ROOT) || IsTrustedUid(user_id);
+
+  if (!trusted) {
+    ALOGE(
+        "DisplayService::OnDeleteGlobalBuffer: Permission denied for "
+        "user_id=%d",
+        user_id);
+    return ErrorStatus(EPERM);
+  }
+  return DeleteGlobalBuffer(key);
+}
+
+pdx::Status<BorrowedNativeBufferHandle> DisplayService::OnGetGlobalBuffer(
+    pdx::Message& /* message */, DvrGlobalBufferKey key) {
+  ALOGD_IF(TRACE, "DisplayService::OnGetGlobalBuffer: key=%d", key);
+  auto global_buffer = global_buffers_.find(key);
+  if (global_buffer != global_buffers_.end())
+    return {BorrowedNativeBufferHandle(*global_buffer->second, 0)};
   else
     return pdx::ErrorStatus(EINVAL);
 }
@@ -221,18 +367,35 @@
   hardware_composer_.SetDisplaySurfaces(std::move(visible_surfaces));
 }
 
-pdx::Status<BorrowedNativeBufferHandle> DisplayService::SetupNamedBuffer(
-    const std::string& name, size_t size, uint64_t usage) {
-  auto named_buffer = named_buffers_.find(name);
-  if (named_buffer == named_buffers_.end()) {
+pdx::Status<BorrowedNativeBufferHandle> DisplayService::SetupGlobalBuffer(
+    DvrGlobalBufferKey key, size_t size, uint64_t usage) {
+  auto global_buffer = global_buffers_.find(key);
+  if (global_buffer == global_buffers_.end()) {
     auto ion_buffer = std::make_unique<IonBuffer>(static_cast<int>(size), 1,
                                                   HAL_PIXEL_FORMAT_BLOB, usage);
-    named_buffer =
-        named_buffers_.insert(std::make_pair(name, std::move(ion_buffer)))
+
+    // Some buffers are used internally. If they were configured with an
+    // invalid size or format, this will fail.
+    int result = hardware_composer_.OnNewGlobalBuffer(key, *ion_buffer.get());
+    if (result < 0)
+      return ErrorStatus(result);
+    global_buffer =
+        global_buffers_.insert(std::make_pair(key, std::move(ion_buffer)))
             .first;
   }
 
-  return {BorrowedNativeBufferHandle(*named_buffer->second, 0)};
+  return {BorrowedNativeBufferHandle(*global_buffer->second, 0)};
+}
+
+pdx::Status<void> DisplayService::DeleteGlobalBuffer(DvrGlobalBufferKey key) {
+  auto global_buffer = global_buffers_.find(key);
+  if (global_buffer != global_buffers_.end()) {
+    // Some buffers are used internally.
+    hardware_composer_.OnDeletedGlobalBuffer(key);
+    global_buffers_.erase(global_buffer);
+  }
+
+  return {0};
 }
 
 void DisplayService::OnHardwareComposerRefresh() {
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
index bb4eeef..6efe264 100644
--- a/libs/vr/libvrflinger/display_service.h
+++ b/libs/vr/libvrflinger/display_service.h
@@ -1,6 +1,7 @@
 #ifndef ANDROID_DVR_SERVICES_DISPLAYD_DISPLAY_SERVICE_H_
 #define ANDROID_DVR_SERVICES_DISPLAYD_DISPLAY_SERVICE_H_
 
+#include <dvr/dvr_api.h>
 #include <pdx/service.h>
 #include <pdx/status.h>
 #include <private/dvr/buffer_hub_client.h>
@@ -40,8 +41,10 @@
   // any change to client/manager attributes that affect visibility or z order.
   void UpdateActiveDisplaySurfaces();
 
-  pdx::Status<BorrowedNativeBufferHandle> SetupNamedBuffer(
-      const std::string& name, size_t size, uint64_t usage);
+  pdx::Status<BorrowedNativeBufferHandle> SetupGlobalBuffer(
+      DvrGlobalBufferKey key, size_t size, uint64_t usage);
+
+  pdx::Status<void> DeleteGlobalBuffer(DvrGlobalBufferKey key);
 
   template <class A>
   void ForEachDisplaySurface(SurfaceType surface_type, A action) const {
@@ -82,11 +85,18 @@
   DisplayService(android::Hwc2::Composer* hidl,
                  RequestDisplayCallback request_display_callback);
 
-  pdx::Status<BorrowedNativeBufferHandle> OnGetNamedBuffer(
-      pdx::Message& message, const std::string& name);
+  pdx::Status<BorrowedNativeBufferHandle> OnGetGlobalBuffer(
+      pdx::Message& message, DvrGlobalBufferKey key);
   pdx::Status<display::Metrics> OnGetMetrics(pdx::Message& message);
+  pdx::Status<std::string> OnGetConfigurationData(
+      pdx::Message& message, display::ConfigFileType config_type);
   pdx::Status<display::SurfaceInfo> OnCreateSurface(
       pdx::Message& message, const display::SurfaceAttributes& attributes);
+  pdx::Status<BorrowedNativeBufferHandle> OnSetupGlobalBuffer(
+      pdx::Message& message, DvrGlobalBufferKey key, size_t size,
+      uint64_t usage);
+  pdx::Status<void> OnDeleteGlobalBuffer(pdx::Message& message,
+                                         DvrGlobalBufferKey key);
 
   // Temporary query for current VR status. Will be removed later.
   pdx::Status<bool> IsVrAppRunning(pdx::Message& message);
@@ -113,7 +123,8 @@
   EpollEventDispatcher dispatcher_;
   DisplayConfigurationUpdateNotifier update_notifier_;
 
-  std::unordered_map<std::string, std::unique_ptr<IonBuffer>> named_buffers_;
+  std::unordered_map<DvrGlobalBufferKey, std::unique_ptr<IonBuffer>>
+      global_buffers_;
 
   DisplayService(const DisplayService&) = delete;
   void operator=(const DisplayService&) = delete;
diff --git a/libs/vr/libvrflinger/display_surface.cpp b/libs/vr/libvrflinger/display_surface.cpp
index fb2751b..0d6a732 100644
--- a/libs/vr/libvrflinger/display_surface.cpp
+++ b/libs/vr/libvrflinger/display_surface.cpp
@@ -68,7 +68,7 @@
   display::SurfaceUpdateFlags update_flags;
 
   for (const auto& attribute : attributes) {
-    const auto& key = attribute.first;
+    const auto key = attribute.first;
     const auto* variant = &attribute.second;
     bool invalid_value = false;
     bool visibility_changed = false;
@@ -95,14 +95,23 @@
         break;
     }
 
+    // Only update the attribute map with valid values. This check also has the
+    // effect of preventing special attributes handled above from being deleted
+    // by an empty value.
     if (invalid_value) {
       ALOGW(
           "DisplaySurface::OnClientSetAttributes: Failed to set display "
           "surface attribute '%d' because of incompatible type: %d",
           key, variant->index());
     } else {
-      // Only update the attribute map with valid values.
-      attributes_[attribute.first] = attribute.second;
+      // An empty value indicates the attribute should be deleted.
+      if (variant->empty()) {
+        auto search = attributes_.find(key);
+        if (search != attributes_.end())
+          attributes_.erase(search);
+      } else {
+        attributes_[key] = *variant;
+      }
 
       // All attribute changes generate a notification, even if the value
       // doesn't change. Visibility attributes set a flag only if the value
@@ -127,7 +136,8 @@
 }
 
 void DisplaySurface::ClearUpdate() {
-  ALOGD_IF(TRACE, "DisplaySurface::ClearUpdate: surface_id=%d", surface_id());
+  ALOGD_IF(TRACE > 1, "DisplaySurface::ClearUpdate: surface_id=%d",
+           surface_id());
   update_flags_ = display::SurfaceUpdateFlags::None;
 }
 
@@ -184,6 +194,7 @@
            "ApplicationDisplaySurface::GetQueue: surface_id=%d queue_id=%d",
            surface_id(), queue_id);
 
+  std::lock_guard<std::mutex> autolock(lock_);
   auto search = consumer_queues_.find(queue_id);
   if (search != consumer_queues_.end())
     return search->second;
@@ -192,6 +203,7 @@
 }
 
 std::vector<int32_t> ApplicationDisplaySurface::GetQueueIds() const {
+  std::lock_guard<std::mutex> autolock(lock_);
   std::vector<int32_t> queue_ids;
   for (const auto& entry : consumer_queues_)
     queue_ids.push_back(entry.first);
@@ -199,15 +211,15 @@
 }
 
 Status<LocalChannelHandle> ApplicationDisplaySurface::OnCreateQueue(
-    Message& /*message*/, size_t meta_size_bytes) {
+    Message& /*message*/, const ProducerQueueConfig& config) {
   ATRACE_NAME("ApplicationDisplaySurface::OnCreateQueue");
   ALOGD_IF(TRACE,
            "ApplicationDisplaySurface::OnCreateQueue: surface_id=%d, "
            "meta_size_bytes=%zu",
-           surface_id(), meta_size_bytes);
+           surface_id(), config.meta_size_bytes);
 
   std::lock_guard<std::mutex> autolock(lock_);
-  auto producer = ProducerQueue::Create(meta_size_bytes);
+  auto producer = ProducerQueue::Create(config, UsagePolicy{});
   if (!producer) {
     ALOGE(
         "ApplicationDisplaySurface::OnCreateQueue: Failed to create producer "
@@ -238,11 +250,12 @@
            "ApplicationDisplaySurface::OnQueueEvent: queue_id=%d events=%x",
            consumer_queue->id(), events);
 
+  std::lock_guard<std::mutex> autolock(lock_);
+
   // Always give the queue a chance to handle its internal bookkeeping.
   consumer_queue->HandleQueueEvents();
 
   // Check for hangup and remove a queue that is no longer needed.
-  std::lock_guard<std::mutex> autolock(lock_);
   if (consumer_queue->hung_up()) {
     ALOGD_IF(TRACE, "ApplicationDisplaySurface::OnQueueEvent: Removing queue.");
     UnregisterQueue(consumer_queue);
@@ -258,17 +271,28 @@
   }
 }
 
+std::vector<int32_t> DirectDisplaySurface::GetQueueIds() const {
+  std::lock_guard<std::mutex> autolock(lock_);
+  std::vector<int32_t> queue_ids;
+  if (direct_queue_)
+    queue_ids.push_back(direct_queue_->id());
+  return queue_ids;
+}
+
 Status<LocalChannelHandle> DirectDisplaySurface::OnCreateQueue(
-    Message& /*message*/, size_t meta_size_bytes) {
+    Message& /*message*/, const ProducerQueueConfig& config) {
   ATRACE_NAME("DirectDisplaySurface::OnCreateQueue");
   ALOGD_IF(
       TRACE,
       "DirectDisplaySurface::OnCreateQueue: surface_id=%d meta_size_bytes=%zu",
-      surface_id(), meta_size_bytes);
+      surface_id(), config.meta_size_bytes);
 
   std::lock_guard<std::mutex> autolock(lock_);
   if (!direct_queue_) {
-    auto producer = ProducerQueue::Create(meta_size_bytes);
+    // Inject the hw composer usage flag to enable the display to read the
+    // buffers.
+    auto producer = ProducerQueue::Create(
+        config, UsagePolicy{GraphicBuffer::USAGE_HW_COMPOSER, 0, 0, 0});
     if (!producer) {
       ALOGE(
           "DirectDisplaySurface::OnCreateQueue: Failed to create producer "
@@ -297,11 +321,12 @@
   ALOGD_IF(TRACE, "DirectDisplaySurface::OnQueueEvent: queue_id=%d events=%x",
            consumer_queue->id(), events);
 
+  std::lock_guard<std::mutex> autolock(lock_);
+
   // Always give the queue a chance to handle its internal bookkeeping.
   consumer_queue->HandleQueueEvents();
 
   // Check for hangup and remove a queue that is no longer needed.
-  std::lock_guard<std::mutex> autolock(lock_);
   if (consumer_queue->hung_up()) {
     ALOGD_IF(TRACE, "DirectDisplaySurface::OnQueueEvent: Removing queue.");
     UnregisterQueue(consumer_queue);
@@ -323,7 +348,7 @@
     auto buffer_status = direct_queue_->Dequeue(0, &slot, &acquire_fence);
     if (!buffer_status) {
       ALOGD_IF(
-          TRACE && buffer_status.error() == ETIMEDOUT,
+          TRACE > 1 && buffer_status.error() == ETIMEDOUT,
           "DirectDisplaySurface::DequeueBuffersLocked: All buffers dequeued.");
       ALOGE_IF(buffer_status.error() != ETIMEDOUT,
                "DirectDisplaySurface::DequeueBuffersLocked: Failed to dequeue "
@@ -367,8 +392,8 @@
   }
   AcquiredBuffer buffer = std::move(acquired_buffers_.Front());
   acquired_buffers_.PopFront();
-  ALOGD_IF(TRACE, "DirectDisplaySurface::AcquireCurrentBuffer: buffer: %p",
-           buffer.buffer().get());
+  ALOGD_IF(TRACE, "DirectDisplaySurface::AcquireCurrentBuffer: buffer_id=%d",
+           buffer.buffer()->id());
   return buffer;
 }
 
@@ -396,8 +421,8 @@
       break;
   }
   ALOGD_IF(TRACE,
-           "DirectDisplaySurface::AcquireNewestAvailableBuffer: buffer: %p",
-           buffer.buffer().get());
+           "DirectDisplaySurface::AcquireNewestAvailableBuffer: buffer_id=%d",
+           buffer.buffer()->id());
   return buffer;
 }
 
diff --git a/libs/vr/libvrflinger/display_surface.h b/libs/vr/libvrflinger/display_surface.h
index c456b10..5cbee57 100644
--- a/libs/vr/libvrflinger/display_surface.h
+++ b/libs/vr/libvrflinger/display_surface.h
@@ -66,7 +66,7 @@
   }
 
   virtual pdx::Status<pdx::LocalChannelHandle> OnCreateQueue(
-      pdx::Message& message, size_t meta_size_bytes) = 0;
+      pdx::Message& message, const ProducerQueueConfig& config) = 0;
 
   // Registers a consumer queue with the event dispatcher in DisplayService. The
   // OnQueueEvent callback below is called to handle queue events.
@@ -129,10 +129,11 @@
 
  private:
   pdx::Status<pdx::LocalChannelHandle> OnCreateQueue(
-      pdx::Message& message, size_t meta_size_bytes) override;
+      pdx::Message& message, const ProducerQueueConfig& config) override;
   void OnQueueEvent(const std::shared_ptr<ConsumerQueue>& consumer_queue,
                     int events) override;
 
+  // Accessed by both message dispatch thread and epoll event thread.
   std::unordered_map<int32_t, std::shared_ptr<ConsumerQueue>> consumer_queues_;
 };
 
@@ -144,6 +145,7 @@
       : DisplaySurface(service, SurfaceType::Direct, surface_id, process_id,
                        user_id, attributes),
         acquired_buffers_(kMaxPostedBuffers) {}
+  std::vector<int32_t> GetQueueIds() const override;
   bool IsBufferAvailable();
   bool IsBufferPosted();
   AcquiredBuffer AcquireCurrentBuffer();
@@ -154,7 +156,7 @@
 
  private:
   pdx::Status<pdx::LocalChannelHandle> OnCreateQueue(
-      pdx::Message& message, size_t meta_size_bytes) override;
+      pdx::Message& message, const ProducerQueueConfig& config) override;
   void OnQueueEvent(const std::shared_ptr<ConsumerQueue>& consumer_queue,
                     int events) override;
 
diff --git a/libs/vr/libvrflinger/epoll_event_dispatcher.cpp b/libs/vr/libvrflinger/epoll_event_dispatcher.cpp
index 06b69bb..962c745 100644
--- a/libs/vr/libvrflinger/epoll_event_dispatcher.cpp
+++ b/libs/vr/libvrflinger/epoll_event_dispatcher.cpp
@@ -101,12 +101,12 @@
     if (num_events < 0 && errno != EINTR)
       break;
 
-    ALOGD_IF(TRACE, "EpollEventDispatcher::EventThread: num_events=%d",
+    ALOGD_IF(TRACE > 1, "EpollEventDispatcher::EventThread: num_events=%d",
              num_events);
 
     for (int i = 0; i < num_events; i++) {
       ALOGD_IF(
-          TRACE,
+          TRACE > 1,
           "EpollEventDispatcher::EventThread: event %d: handler=%p events=0x%x",
           i, events[i].data.ptr, events[i].events);
 
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index 34474d9..def9b7d 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -19,12 +19,14 @@
 #include <chrono>
 #include <functional>
 #include <map>
+#include <sstream>
+#include <string>
+#include <tuple>
 
 #include <dvr/dvr_display_types.h>
 #include <dvr/performance_client_api.h>
 #include <private/dvr/clock_ns.h>
 #include <private/dvr/ion_buffer.h>
-#include <private/dvr/pose_client_internal.h>
 
 using android::pdx::LocalHandle;
 using android::pdx::rpc::EmptyVariant;
@@ -37,17 +39,6 @@
 
 namespace {
 
-// If the number of pending fences goes over this count at the point when we
-// are about to submit a new frame to HWC, we will drop the frame. This should
-// be a signal that the display driver has begun queuing frames. Note that with
-// smart displays (with RAM), the fence is signaled earlier than the next vsync,
-// at the point when the DMA to the display completes. Currently we use a smart
-// display and the EDS timing coincides with zero pending fences, so this is 0.
-constexpr int kAllowedPendingFenceCount = 0;
-
-// Offset before vsync to submit frames to hardware composer.
-constexpr int64_t kFramePostOffsetNs = 4000000;  // 4ms
-
 const char kBacklightBrightnessSysFile[] =
     "/sys/class/leds/lcd-backlight/brightness";
 
@@ -221,10 +212,6 @@
 void HardwareComposer::OnPostThreadResumed() {
   hwc2_hidl_->resetCommands();
 
-  // Connect to pose service.
-  pose_client_ = dvrPoseCreate();
-  ALOGE_IF(!pose_client_, "HardwareComposer: Failed to create pose client");
-
   // HIDL HWC seems to have an internal race condition. If we submit a frame too
   // soon after turning on VSync we don't get any VSync signals. Give poor HWC
   // implementations a chance to enable VSync before we continue.
@@ -253,11 +240,6 @@
   }
   active_layer_count_ = 0;
 
-  if (pose_client_) {
-    dvrPoseDestroy(pose_client_);
-    pose_client_ = nullptr;
-  }
-
   EnableVsync(false);
 
   hwc2_hidl_->resetCommands();
@@ -367,7 +349,36 @@
   return HWC::Error::None;
 }
 
-std::string HardwareComposer::Dump() { return hwc2_hidl_->dumpDebugInfo(); }
+std::string HardwareComposer::Dump() {
+  std::unique_lock<std::mutex> lock(post_thread_mutex_);
+  std::ostringstream stream;
+
+  stream << "Display metrics:     " << display_metrics_.width << "x"
+         << display_metrics_.height << " " << (display_metrics_.dpi.x / 1000.0)
+         << "x" << (display_metrics_.dpi.y / 1000.0) << " dpi @ "
+         << (1000000000.0 / display_metrics_.vsync_period_ns) << " Hz"
+         << std::endl;
+
+  stream << "Post thread resumed: " << post_thread_resumed_ << std::endl;
+  stream << "Active layers:       " << active_layer_count_ << std::endl;
+  stream << std::endl;
+
+  for (size_t i = 0; i < active_layer_count_; i++) {
+    stream << "Layer " << i << ":";
+    stream << " type=" << layers_[i].GetCompositionType().to_string();
+    stream << " surface_id=" << layers_[i].GetSurfaceId();
+    stream << " buffer_id=" << layers_[i].GetBufferId();
+    stream << std::endl;
+  }
+  stream << std::endl;
+
+  if (post_thread_resumed_) {
+    stream << "Hardware Composer Debug Info:" << std::endl;
+    stream << hwc2_hidl_->dumpDebugInfo();
+  }
+
+  return stream.str();
+}
 
 void HardwareComposer::PostLayers() {
   ATRACE_NAME("HardwareComposer::PostLayers");
@@ -397,8 +408,8 @@
   }
 
   const bool is_frame_pending = IsFramePendingInDriver();
-  const bool is_fence_pending =
-      retire_fence_fds_.size() > kAllowedPendingFenceCount;
+  const bool is_fence_pending = retire_fence_fds_.size() >
+                                post_thread_config_.allowed_pending_fence_count;
 
   if (is_fence_pending || is_frame_pending) {
     ATRACE_INT("frame_skip_count", ++frame_skip_count_);
@@ -418,10 +429,12 @@
     ATRACE_INT("frame_skip_count", 0);
   }
 
-#if TRACE
-  for (size_t i = 0; i < active_layer_count_; i++)
-    ALOGI("HardwareComposer::PostLayers: layer=%zu composition=%s", i,
+#if TRACE > 1
+  for (size_t i = 0; i < active_layer_count_; i++) {
+    ALOGI("HardwareComposer::PostLayers: layer=%zu buffer_id=%d composition=%s",
+          i, layers_[i].GetBufferId(),
           layers_[i].GetCompositionType().to_string().c_str());
+  }
 #endif
 
   error = Present(HWC_DISPLAY_PRIMARY);
@@ -460,19 +473,76 @@
     pending_surfaces_ = std::move(surfaces);
   }
 
-  // Set idle state based on whether there are any surfaces to handle.
-  UpdatePostThreadState(PostThreadState::Idle, display_idle);
-
-  // XXX: TEMPORARY
-  // Request control of the display based on whether there are any surfaces to
-  // handle. This callback sets the post thread active state once the transition
-  // is complete in SurfaceFlinger.
-  // TODO(eieio): Unify the control signal used to move SurfaceFlinger into VR
-  // mode. Currently this is hooked up to persistent VR mode, but perhaps this
-  // makes more sense to control it from VrCore, which could in turn base its
-  // decision on persistent VR mode.
   if (request_display_callback_)
     request_display_callback_(!display_idle);
+
+  // Set idle state based on whether there are any surfaces to handle.
+  UpdatePostThreadState(PostThreadState::Idle, display_idle);
+}
+
+int HardwareComposer::OnNewGlobalBuffer(DvrGlobalBufferKey key,
+                                        IonBuffer& ion_buffer) {
+  if (key == DvrGlobalBuffers::kVsyncBuffer) {
+    vsync_ring_ = std::make_unique<CPUMappedBroadcastRing<DvrVsyncRing>>(
+        &ion_buffer, CPUUsageMode::WRITE_OFTEN);
+
+    if (vsync_ring_->IsMapped() == false) {
+      return -EPERM;
+    }
+  }
+
+  if (key == DvrGlobalBuffers::kVrFlingerConfigBufferKey) {
+    return MapConfigBuffer(ion_buffer);
+  }
+
+  return 0;
+}
+
+void HardwareComposer::OnDeletedGlobalBuffer(DvrGlobalBufferKey key) {
+  if (key == DvrGlobalBuffers::kVrFlingerConfigBufferKey) {
+    ConfigBufferDeleted();
+  }
+}
+
+int HardwareComposer::MapConfigBuffer(IonBuffer& ion_buffer) {
+  std::lock_guard<std::mutex> lock(shared_config_mutex_);
+  shared_config_ring_ = DvrConfigRing();
+
+  if (ion_buffer.width() < DvrConfigRing::MemorySize()) {
+    ALOGE("HardwareComposer::MapConfigBuffer: invalid buffer size.");
+    return -EINVAL;
+  }
+
+  void* buffer_base = 0;
+  int result = ion_buffer.Lock(ion_buffer.usage(), 0, 0, ion_buffer.width(),
+                               ion_buffer.height(), &buffer_base);
+  if (result != 0) {
+    ALOGE(
+        "HardwareComposer::MapConfigBuffer: Failed to map vrflinger config "
+        "buffer.");
+    return -EPERM;
+  }
+
+  shared_config_ring_ = DvrConfigRing::Create(buffer_base, ion_buffer.width());
+  ion_buffer.Unlock();
+
+  return 0;
+}
+
+void HardwareComposer::ConfigBufferDeleted() {
+  std::lock_guard<std::mutex> lock(shared_config_mutex_);
+  shared_config_ring_ = DvrConfigRing();
+}
+
+void HardwareComposer::UpdateConfigBuffer() {
+  std::lock_guard<std::mutex> lock(shared_config_mutex_);
+  if (!shared_config_ring_.is_valid())
+    return;
+  // Copy from latest record in shared_config_ring_ to local copy.
+  DvrConfig record;
+  if (shared_config_ring_.GetNewest(&shared_config_ring_sequence_, &record)) {
+    post_thread_config_ = record;
+  }
 }
 
 int HardwareComposer::PostThreadPollInterruptible(
@@ -744,12 +814,16 @@
   while (1) {
     ATRACE_NAME("HardwareComposer::PostThread");
 
+    // Check for updated config once per vsync.
+    UpdateConfigBuffer();
+
     while (post_thread_quiescent_) {
       std::unique_lock<std::mutex> lock(post_thread_mutex_);
       ALOGI("HardwareComposer::PostThread: Entering quiescent state.");
 
-      // Tear down resources.
-      OnPostThreadPaused();
+      // Tear down resources if necessary.
+      if (was_running)
+        OnPostThreadPaused();
 
       was_running = false;
       post_thread_resumed_ = false;
@@ -801,16 +875,20 @@
 
     ++vsync_count_;
 
-    if (pose_client_) {
-      // Signal the pose service with vsync info.
-      // Display timestamp is in the middle of scanout.
-      privateDvrPoseNotifyVsync(pose_client_, vsync_count_,
-                                vsync_timestamp + photon_offset_ns,
-                                ns_per_frame, right_eye_photon_offset_ns);
-    }
-
     const bool layer_config_changed = UpdateLayerConfig();
 
+    // Publish the vsync event.
+    if (vsync_ring_) {
+      DvrVsync vsync;
+      vsync.vsync_count = vsync_count_;
+      vsync.vsync_timestamp_ns = vsync_timestamp;
+      vsync.vsync_left_eye_offset_ns = photon_offset_ns;
+      vsync.vsync_right_eye_offset_ns = right_eye_photon_offset_ns;
+      vsync.vsync_period_ns = ns_per_frame;
+
+      vsync_ring_->Publish(vsync);
+    }
+
     // Signal all of the vsync clients. Because absolute time is used for the
     // wakeup time below, this can take a little time if necessary.
     if (vsync_callback_)
@@ -823,9 +901,10 @@
 
       const int64_t display_time_est_ns = vsync_timestamp + ns_per_frame;
       const int64_t now_ns = GetSystemClockNs();
-      const int64_t sleep_time_ns =
-          display_time_est_ns - now_ns - kFramePostOffsetNs;
-      const int64_t wakeup_time_ns = display_time_est_ns - kFramePostOffsetNs;
+      const int64_t sleep_time_ns = display_time_est_ns - now_ns -
+                                    post_thread_config_.frame_post_offset_ns;
+      const int64_t wakeup_time_ns =
+          display_time_est_ns - post_thread_config_.frame_post_offset_ns;
 
       ATRACE_INT64("sleep_time_ns", sleep_time_ns);
       if (sleep_time_ns > 0) {
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index 8ba72ab..a0c50e1 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -5,6 +5,7 @@
 #include "DisplayHardware/ComposerHal.h"
 #include "hwc_types.h"
 
+#include <dvr/dvr_shared_buffers.h>
 #include <hardware/gralloc.h>
 #include <log/log.h>
 
@@ -16,10 +17,12 @@
 #include <tuple>
 #include <vector>
 
-#include <dvr/pose_client.h>
+#include <dvr/dvr_config.h>
+#include <dvr/dvr_vsync.h>
 #include <pdx/file_handle.h>
 #include <pdx/rpc/variant.h>
 #include <private/dvr/buffer_hub_client.h>
+#include <private/dvr/shared_buffer_helpers.h>
 
 #include "acquired_buffer.h"
 #include "display_surface.h"
@@ -124,11 +127,20 @@
     int surface_id = -1;
     pdx::rpc::IfAnyOf<SourceSurface>::Call(
         &source_, [&surface_id](const SourceSurface& surface_source) {
-          surface_id = surface_source.surface->surface_id();
+          surface_id = surface_source.GetSurfaceId();
         });
     return surface_id;
   }
 
+  int GetBufferId() const {
+    int buffer_id = -1;
+    pdx::rpc::IfAnyOf<SourceSurface>::Call(
+        &source_, [&buffer_id](const SourceSurface& surface_source) {
+          buffer_id = surface_source.GetBufferId();
+        });
+    return buffer_id;
+  }
+
  private:
   void CommonLayerSetup();
 
@@ -189,7 +201,15 @@
     }
 
     // Returns the surface id of the surface.
-    int GetSurfaceId() { return surface->surface_id(); }
+    int GetSurfaceId() const { return surface->surface_id(); }
+
+    // Returns the buffer id for the current buffer.
+    int GetBufferId() const {
+      if (acquired_buffer.IsAvailable())
+        return acquired_buffer.buffer()->id();
+      else
+        return -1;
+    }
   };
 
   // State when the layer is connected to a buffer. Provides the same interface
@@ -210,6 +230,7 @@
     IonBuffer* GetBuffer() { return buffer.get(); }
 
     int GetSurfaceId() const { return -1; }
+    int GetBufferId() const { return -1; }
   };
 
   // The underlying hardware composer layer is supplied buffers either from a
@@ -284,6 +305,9 @@
   void SetDisplaySurfaces(
       std::vector<std::shared_ptr<DirectDisplaySurface>> surfaces);
 
+  int OnNewGlobalBuffer(DvrGlobalBufferKey key, IonBuffer& ion_buffer);
+  void OnDeletedGlobalBuffer(DvrGlobalBufferKey key);
+
   void OnHardwareComposerRefresh();
 
  private:
@@ -365,6 +389,13 @@
   // Called on the post thread when the post thread is paused or quits.
   void OnPostThreadPaused();
 
+  // Map the given shared memory buffer to our broadcast ring to track updates
+  // to the config parameters.
+  int MapConfigBuffer(IonBuffer& ion_buffer);
+  void ConfigBufferDeleted();
+  // Poll for config udpates.
+  void UpdateConfigBuffer();
+
   bool initialized_;
 
   // Hardware composer HAL device from SurfaceFlinger. VrFlinger does not own
@@ -435,9 +466,15 @@
   // us to detect when the display driver begins queuing frames.
   std::vector<pdx::LocalHandle> retire_fence_fds_;
 
-  // Pose client for frame count notifications. Pose client predicts poses
-  // out to display frame boundaries, so we need to tell it about vsyncs.
-  DvrPose* pose_client_ = nullptr;
+  // If we are publishing vsync data, we will put it here.
+  std::unique_ptr<CPUMappedBroadcastRing<DvrVsyncRing>> vsync_ring_;
+
+  // Broadcast ring for receiving config data from the DisplayManager.
+  DvrConfigRing shared_config_ring_;
+  uint32_t shared_config_ring_sequence_{0};
+  // Config buffer for reading from the post thread.
+  DvrConfig post_thread_config_;
+  std::mutex shared_config_mutex_;
 
   static constexpr int kPostThreadInterrupted = 1;
 
diff --git a/libs/vr/libvrflinger/include/dvr/vr_flinger.h b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
index 145852e..f41da87 100644
--- a/libs/vr/libvrflinger/include/dvr/vr_flinger.h
+++ b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
@@ -32,6 +32,9 @@
   // Called on a binder thread.
   void OnHardwareComposerRefresh();
 
+  // dump all vr flinger state.
+  std::string Dump();
+
  private:
   VrFlinger();
   bool Init(Hwc2::Composer* hidl,
diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp
index b2dc1d8..3a0ca4a 100644
--- a/libs/vr/libvrflinger/vr_flinger.cpp
+++ b/libs/vr/libvrflinger/vr_flinger.cpp
@@ -139,6 +139,11 @@
   display_service_->OnHardwareComposerRefresh();
 }
 
+std::string VrFlinger::Dump() {
+  // TODO(karthikrs): Add more state information here.
+  return display_service_->DumpState(0/*unused*/);
+}
+
 void VrFlinger::PersistentVrStateCallback::onPersistentVrStateChanged(
     bool enabled) {
   ALOGV("Notified persistent vr mode is %s", enabled ? "on" : "off");
@@ -146,6 +151,5 @@
   // Persistent VR mode is not enough.
   // request_display_callback_(enabled);
 }
-
 }  // namespace dvr
 }  // namespace android
diff --git a/libs/vr/libvrflinger/vsync_service.cpp b/libs/vr/libvrflinger/vsync_service.cpp
index 2a83933..3098b43 100644
--- a/libs/vr/libvrflinger/vsync_service.cpp
+++ b/libs/vr/libvrflinger/vsync_service.cpp
@@ -200,12 +200,12 @@
 }
 
 void VSyncChannel::Ack() {
-  ALOGD_IF(TRACE, "VSyncChannel::Ack: pid=%d cid=%d\n", pid_, cid_);
+  ALOGD_IF(TRACE > 1, "VSyncChannel::Ack: pid=%d cid=%d\n", pid_, cid_);
   service_.ModifyChannelEvents(cid_, POLLPRI, 0);
 }
 
 void VSyncChannel::Signal() {
-  ALOGD_IF(TRACE, "VSyncChannel::Signal: pid=%d cid=%d\n", pid_, cid_);
+  ALOGD_IF(TRACE > 1, "VSyncChannel::Signal: pid=%d cid=%d\n", pid_, cid_);
   service_.ModifyChannelEvents(cid_, 0, POLLPRI);
 }
 
diff --git a/libs/vr/libvrsensor/Android.bp b/libs/vr/libvrsensor/Android.bp
index abad78b..d022adf 100644
--- a/libs/vr/libvrsensor/Android.bp
+++ b/libs/vr/libvrsensor/Android.bp
@@ -23,9 +23,11 @@
 ]
 
 staticLibraries = [
+    "libdisplay",
     "libbufferhub",
     "libbufferhubqueue",
     "libdvrcommon",
+    "libbroadcastring",
     "libpdx_default_transport",
 ]
 
@@ -43,6 +45,7 @@
     export_include_dirs: includeFiles,
     static_libs: staticLibraries,
     shared_libs: sharedLibraries,
+    header_libs: ["libdvr_headers"],
     name: "libvrsensor",
 }
 
diff --git a/libs/vr/libvrsensor/include/dvr/pose_client.h b/libs/vr/libvrsensor/include/dvr/pose_client.h
index ed75f84..d684ddc 100644
--- a/libs/vr/libvrsensor/include/dvr/pose_client.h
+++ b/libs/vr/libvrsensor/include/dvr/pose_client.h
@@ -14,63 +14,13 @@
 #include <stdbool.h>
 #include <stdint.h>
 
+#include <dvr/dvr_pose.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-typedef struct DvrPose DvrPose;
-
-// Represents the current state provided by the pose service, containing a
-// rotation and translation.
-typedef struct __attribute__((packed, aligned(8))) DvrPoseState {
-  // A quaternion representing the rotation of the HMD in Start Space.
-  struct __attribute__((packed)) {
-    float x, y, z, w;
-  } head_from_start_rotation;
-  // The position of the HMD in Start Space.
-  struct __attribute__((packed)) {
-    float x, y, z;
-  } head_from_start_translation;
-  // Time in nanoseconds for the current pose.
-  uint64_t timestamp_ns;
-  // The rotational velocity of the HMD.
-  struct __attribute__((packed)) {
-    float x, y, z;
-  } sensor_from_start_rotation_velocity;
-} DvrPoseState;
-
-enum {
-  DVR_POSE_FLAG_VALID = (1UL << 0),       // This pose is valid.
-  DVR_POSE_FLAG_HEAD = (1UL << 1),        // This pose is the head.
-  DVR_POSE_FLAG_CONTROLLER = (1UL << 2),  // This pose is a controller.
-};
-
-// Represents an estimated pose, accessed asynchronously through a shared ring
-// buffer. No assumptions should be made about the data in padding space.
-// The size of this struct is 128 bytes.
-typedef struct __attribute__((packed, aligned(16))) DvrPoseAsync {
-  // Left eye head-from-start orientation quaternion x,y,z,w.
-  float32x4_t orientation;
-  // Left eye head-from-start translation x,y,z,pad in meters.
-  float32x4_t translation;
-  // Right eye head-from-start orientation quaternion x,y,z,w.
-  float32x4_t right_orientation;
-  // Right eye head-from-start translation x,y,z,pad in meters.
-  float32x4_t right_translation;
-  // Start-space angular velocity x,y,z,pad in radians per second.
-  float32x4_t angular_velocity;
-  // Start-space positional velocity x,y,z,pad in meters per second.
-  float32x4_t velocity;
-  // Timestamp of when this pose is predicted for, typically halfway through
-  // scanout.
-  int64_t timestamp_ns;
-  // Bitmask of DVR_POSE_FLAG_* constants that apply to this pose.
-  //
-  // If DVR_POSE_FLAG_VALID is not set, the pose is indeterminate.
-  uint64_t flags;
-  // Reserved padding to 128 bytes.
-  uint8_t pad[16];
-} DvrPoseAsync;
+typedef struct DvrPoseClient DvrPoseClient;
 
 // Returned by the async pose ring buffer access API.
 typedef struct DvrPoseRingBufferInfo {
@@ -105,6 +55,8 @@
   DVR_POSE_MODE_MOCK_ROTATE_MEDIUM,
   DVR_POSE_MODE_MOCK_ROTATE_FAST,
   DVR_POSE_MODE_MOCK_CIRCLE_STRAFE,
+  DVR_POSE_MODE_FLOAT,
+  DVR_POSE_MODE_MOCK_MOTION_SICKNESS,
 
   // Always last.
   DVR_POSE_MODE_COUNT,
@@ -118,12 +70,12 @@
 // Creates a new pose client.
 //
 // @return Pointer to the created pose client, nullptr on failure.
-DvrPose* dvrPoseCreate();
+DvrPoseClient* dvrPoseClientCreate();
 
 // Destroys a pose client.
 //
 // @param client Pointer to the pose client to be destroyed.
-void dvrPoseDestroy(DvrPose* client);
+void dvrPoseClientDestroy(DvrPoseClient* client);
 
 // Gets the pose for the given vsync count.
 //
@@ -132,10 +84,11 @@
 //     Typically this is the count returned by dvrGetNextVsyncCount.
 // @param out_pose Struct to store pose state.
 // @return Zero on success, negative error code on failure.
-int dvrPoseGet(DvrPose* client, uint32_t vsync_count, DvrPoseAsync* out_pose);
+int dvrPoseClientGet(DvrPoseClient* client, uint32_t vsync_count,
+                     DvrPoseAsync* out_pose);
 
 // Gets the current vsync count.
-uint32_t dvrPoseGetVsyncCount(DvrPose* client);
+uint32_t dvrPoseClientGetVsyncCount(DvrPoseClient* client);
 
 // Gets the pose for the given controller at the given vsync count.
 //
@@ -145,15 +98,15 @@
 //     Typically this is the count returned by dvrGetNextVsyncCount.
 // @param out_pose Struct to store pose state.
 // @return Zero on success, negative error code on failure.
-int dvrPoseGetController(DvrPose* client, int32_t controller_id,
-                         uint32_t vsync_count, DvrPoseAsync* out_pose);
+int dvrPoseClientGetController(DvrPoseClient* client, int32_t controller_id,
+                               uint32_t vsync_count, DvrPoseAsync* out_pose);
 
 // Enables/disables logging for the controller fusion.
 //
 // @param client Pointer to the pose client.
 // @param enable True starts logging, False stops.
 // @return Zero on success, negative error code on failure.
-int dvrPoseLogController(DvrPose* client, bool enable);
+int dvrPoseClientLogController(DvrPoseClient* client, bool enable);
 
 // DEPRECATED
 // Polls current pose state.
@@ -161,30 +114,30 @@
 // @param client Pointer to the pose client.
 // @param state Struct to store polled state.
 // @return Zero on success, negative error code on failure.
-int dvrPosePoll(DvrPose* client, DvrPoseState* state);
+int dvrPoseClientPoll(DvrPoseClient* client, DvrPose* state);
 
 // Freezes the pose to the provided state.
 //
 // Future poll operations will return this state until a different state is
-// frozen or dvrPoseSetMode() is called with a different mode. The timestamp is
+// frozen or dvrPoseClientModeSet() is called with a different mode. The timestamp is
 // not frozen.
 //
 // @param client Pointer to the pose client.
 // @param frozen_state State pose to be frozen to.
 // @return Zero on success, negative error code on failure.
-int dvrPoseFreeze(DvrPose* client, const DvrPoseState* frozen_state);
+int dvrPoseClientFreeze(DvrPoseClient* client, const DvrPose* frozen_state);
 
 // Sets the pose service mode.
 //
 // @param mode The requested pose mode.
 // @return Zero on success, negative error code on failure.
-int dvrPoseSetMode(DvrPose* client, DvrPoseMode mode);
+int dvrPoseClientModeSet(DvrPoseClient* client, DvrPoseMode mode);
 
 // Gets the pose service mode.
 //
 // @param mode Return value for the current pose mode.
 // @return Zero on success, negative error code on failure.
-int dvrPoseGetMode(DvrPose* client, DvrPoseMode* mode);
+int dvrPoseClientModeGet(DvrPoseClient* client, DvrPoseMode* mode);
 
 // Get access to the shared memory pose ring buffer.
 // A future pose at vsync <current> + <offset> is accessed at index:
@@ -195,8 +148,14 @@
 // |out_fd| will be set to the gralloc buffer file descriptor, which is
 //   required for binding this buffer for GPU use.
 // Returns 0 on success.
-int dvrPoseGetRingBuffer(DvrPose* client, DvrPoseRingBufferInfo* out_info);
+int dvrPoseClientGetRingBuffer(DvrPoseClient* client,
+                               DvrPoseRingBufferInfo* out_info);
 
+// Sets enabled state for sensors pose processing.
+//
+// @param enabled Whether sensors are enabled or disabled.
+// @return Zero on success
+int dvrPoseClientSensorsEnable(DvrPoseClient* client, bool enabled);
 
 #ifdef __cplusplus
 }  // extern "C"
diff --git a/libs/vr/libvrsensor/include/private/dvr/pose-ipc.h b/libs/vr/libvrsensor/include/private/dvr/pose-ipc.h
index 0616d46..e4455f1 100644
--- a/libs/vr/libvrsensor/include/private/dvr/pose-ipc.h
+++ b/libs/vr/libvrsensor/include/private/dvr/pose-ipc.h
@@ -11,14 +11,12 @@
 #define DVR_POSE_SERVICE_CLIENT (DVR_POSE_SERVICE_BASE "/client")
 
 enum {
-  DVR_POSE_POLL = 0,
-  DVR_POSE_FREEZE,
+  DVR_POSE_FREEZE = 0,
   DVR_POSE_SET_MODE,
-  DVR_POSE_GET_RING_BUFFER,
-  DVR_POSE_NOTIFY_VSYNC,
   DVR_POSE_GET_MODE,
   DVR_POSE_GET_CONTROLLER_RING_BUFFER,
   DVR_POSE_LOG_CONTROLLER,
+  DVR_POSE_SENSORS_ENABLE,
 };
 
 #ifdef __cplusplus
diff --git a/libs/vr/libvrsensor/include/private/dvr/pose_client_internal.h b/libs/vr/libvrsensor/include/private/dvr/pose_client_internal.h
deleted file mode 100644
index 66c4c7c..0000000
--- a/libs/vr/libvrsensor/include/private/dvr/pose_client_internal.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef ANDROID_DVR_POSE_CLIENT_INTERNAL_H_
-#define ANDROID_DVR_POSE_CLIENT_INTERNAL_H_
-
-#include <stdint.h>
-
-#include <dvr/pose_client.h>
-#include <pdx/file_handle.h>
-#include <private/dvr/sensor_constants.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Sensord head pose ring buffer.
-typedef struct __attribute__((packed, aligned(16))) DvrPoseRingBuffer {
-  // Ring buffer always at the beginning of the structure, as consumers may
-  // not have access to this parent structure definition.
-  DvrPoseAsync ring[kPoseAsyncBufferTotalCount];
-  // Current vsync_count (where sensord is writing poses from).
-  uint32_t vsync_count;
-} DvrPoseMetadata;
-
-// Called by displayd to give vsync count info to the pose service.
-// |display_timestamp| Display timestamp is in the middle of scanout.
-// |display_period_ns| Nanos between vsyncs.
-// |right_eye_photon_offset_ns| Nanos to shift the prediction timestamp for
-//    the right eye head pose (relative to the left eye prediction).
-int privateDvrPoseNotifyVsync(DvrPose* client, uint32_t vsync_count,
-                              int64_t display_timestamp,
-                              int64_t display_period_ns,
-                              int64_t right_eye_photon_offset_ns);
-
-// Get file descriptor for access to the shared memory pose buffer. This can be
-// used with GL extensions that support shared memory buffer objects. The caller
-// takes ownership of the returned fd and must close it or pass on ownership.
-int privateDvrPoseGetRingBufferFd(DvrPose* client,
-                                  android::pdx::LocalHandle* fd);
-
-#ifdef __cplusplus
-}  // extern "C"
-#endif
-
-#endif  // ANDROID_DVR_POSE_CLIENT_INTERNAL_H_
diff --git a/libs/vr/libvrsensor/include/private/dvr/sensor_constants.h b/libs/vr/libvrsensor/include/private/dvr/sensor_constants.h
deleted file mode 100644
index 8fa87b3..0000000
--- a/libs/vr/libvrsensor/include/private/dvr/sensor_constants.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef ANDROID_DVR_SENSOR_CONSTANTS_H_
-#define ANDROID_DVR_SENSOR_CONSTANTS_H_
-
-namespace android {
-namespace dvr {
-
-// Number of elements in the async pose buffer.
-// Must be power of two.
-// Macro so that shader code can easily include this value.
-#define kPoseAsyncBufferTotalCount 8
-
-// Mask for accessing the current ring buffer array element:
-// index = vsync_count & kPoseAsyncBufferIndexMask
-constexpr uint32_t kPoseAsyncBufferIndexMask = kPoseAsyncBufferTotalCount - 1;
-
-// Number of pose frames including the current frame that are kept updated with
-// pose forecast data. The other poses are left their last known estimates.
-constexpr uint32_t kPoseAsyncBufferMinFutureCount = 4;
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_SENSOR_CONSTANTS_H_
diff --git a/libs/vr/libvrsensor/pose_client.cpp b/libs/vr/libvrsensor/pose_client.cpp
index 9eae3aa..4ddf1f3 100644
--- a/libs/vr/libvrsensor/pose_client.cpp
+++ b/libs/vr/libvrsensor/pose_client.cpp
@@ -1,4 +1,5 @@
 #define LOG_TAG "PoseClient"
+#include <dvr/dvr_shared_buffers.h>
 #include <dvr/pose_client.h>
 
 #include <stdint.h>
@@ -8,9 +9,9 @@
 #include <pdx/default_transport/client_channel_factory.h>
 #include <pdx/file_handle.h>
 #include <private/dvr/buffer_hub_client.h>
+#include <private/dvr/display_client.h>
 #include <private/dvr/pose-ipc.h>
-#include <private/dvr/pose_client_internal.h>
-#include <private/dvr/sensor_constants.h>
+#include <private/dvr/shared_buffer_helpers.h>
 
 using android::pdx::LocalHandle;
 using android::pdx::LocalChannelHandle;
@@ -21,6 +22,11 @@
 
 namespace android {
 namespace dvr {
+namespace {
+
+typedef CPUMappedBroadcastRing<DvrPoseRing> SensorPoseRing;
+
+}  // namespace
 
 // PoseClient is a remote interface to the pose service in sensord.
 class PoseClient : public pdx::ClientBase<PoseClient> {
@@ -28,39 +34,49 @@
   ~PoseClient() override {}
 
   // Casts C handle into an instance of this class.
-  static PoseClient* FromC(DvrPose* client) {
+  static PoseClient* FromC(DvrPoseClient* client) {
     return reinterpret_cast<PoseClient*>(client);
   }
 
   // Polls the pose service for the current state and stores it in *state.
   // Returns zero on success, a negative error code otherwise.
-  int Poll(DvrPoseState* state) {
-    Transaction trans{*this};
-    Status<int> status =
-        trans.Send<int>(DVR_POSE_POLL, nullptr, 0, state, sizeof(*state));
-    ALOGE_IF(!status, "Pose poll() failed because: %s\n",
-             status.GetErrorMessage().c_str());
-    return ReturnStatusOrError(status);
+  int Poll(DvrPose* state) {
+    // Allocate the helper class to access the sensor pose buffer.
+    if (sensor_pose_buffer_ == nullptr) {
+      sensor_pose_buffer_ = std::make_unique<SensorPoseRing>(
+          DvrGlobalBuffers::kSensorPoseBuffer, CPUUsageMode::READ_RARELY);
+    }
+
+    if (state) {
+      if (sensor_pose_buffer_->GetNewest(state)) {
+        return 0;
+      } else {
+        return -EAGAIN;
+      }
+    }
+
+    return -EINVAL;
   }
 
   int GetPose(uint32_t vsync_count, DvrPoseAsync* out_pose) {
-    if (!mapped_pose_buffer_) {
-      int ret = GetRingBuffer(nullptr);
-      if (ret < 0)
-        return ret;
+    const auto vsync_buffer = GetVsyncBuffer();
+    if (vsync_buffer) {
+      *out_pose =
+          vsync_buffer
+              ->vsync_poses[vsync_count & DvrVsyncPoseBuffer::kIndexMask];
+      return 0;
+    } else {
+      return -EAGAIN;
     }
-    *out_pose =
-        mapped_pose_buffer_->ring[vsync_count & kPoseAsyncBufferIndexMask];
-    return 0;
   }
 
   uint32_t GetVsyncCount() {
-    if (!mapped_pose_buffer_) {
-      int ret = GetRingBuffer(nullptr);
-      if (ret < 0)
-        return 0;
+    const auto vsync_buffer = GetVsyncBuffer();
+    if (vsync_buffer) {
+      return vsync_buffer->vsync_count;
     }
-    return mapped_pose_buffer_->vsync_count;
+
+    return 0;
   }
 
   int GetControllerPose(int32_t controller_id, uint32_t vsync_count,
@@ -75,7 +91,7 @@
     }
     *out_pose =
         controllers_[controller_id]
-            .mapped_pose_buffer[vsync_count & kPoseAsyncBufferIndexMask];
+            .mapped_pose_buffer[vsync_count & DvrVsyncPoseBuffer::kIndexMask];
     return 0;
   }
 
@@ -92,7 +108,7 @@
   // this state until a different state is frozen or SetMode() is called with a
   // different mode.
   // Returns zero on success, a negative error code otherwise.
-  int Freeze(const DvrPoseState& frozen_state) {
+  int Freeze(const DvrPose& frozen_state) {
     Transaction trans{*this};
     Status<int> status = trans.Send<int>(DVR_POSE_FREEZE, &frozen_state,
                                          sizeof(frozen_state), nullptr, 0);
@@ -124,48 +140,29 @@
     return ReturnStatusOrError(status);
   }
 
-  int GetRingBuffer(DvrPoseRingBufferInfo* out_info) {
-    if (pose_buffer_.get()) {
-      if (out_info) {
-        GetPoseRingBufferInfo(out_info);
-      }
-      return 0;
-    }
-
+  // Enables or disables all pose processing from sensors
+  int EnableSensors(bool enabled) {
     Transaction trans{*this};
-    Status<LocalChannelHandle> status =
-        trans.Send<LocalChannelHandle>(DVR_POSE_GET_RING_BUFFER);
-    if (!status) {
-      ALOGE("Pose GetRingBuffer() failed because: %s",
-            status.GetErrorMessage().c_str());
-      return -status.error();
+    Status<int> status = trans.Send<int>(DVR_POSE_SENSORS_ENABLE, &enabled,
+                                         sizeof(enabled), nullptr, 0);
+    ALOGE_IF(!status, "Pose EnableSensors() failed because: %s\n",
+             status.GetErrorMessage().c_str());
+    return ReturnStatusOrError(status);
+  }
+
+  int GetRingBuffer(DvrPoseRingBufferInfo* out_info) {
+    // First time mapping the buffer?
+    const auto vsync_buffer = GetVsyncBuffer();
+    if (vsync_buffer) {
+      if (out_info) {
+        out_info->min_future_count = DvrVsyncPoseBuffer::kMinFutureCount;
+        out_info->total_count = DvrVsyncPoseBuffer::kSize;
+        out_info->buffer = vsync_buffer->vsync_poses;
+      }
+      return -EINVAL;
     }
 
-    auto buffer = BufferConsumer::Import(status.take());
-    if (!buffer) {
-      ALOGE("Pose failed to import ring buffer");
-      return -EIO;
-    }
-    void* addr = nullptr;
-    int ret = buffer->GetBlobReadOnlyPointer(sizeof(DvrPoseRingBuffer), &addr);
-    if (ret < 0 || !addr) {
-      ALOGE("Pose failed to map ring buffer: ret:%d, addr:%p", ret, addr);
-      return -EIO;
-    }
-    pose_buffer_.swap(buffer);
-    mapped_pose_buffer_ = static_cast<const DvrPoseRingBuffer*>(addr);
-    ALOGI("Mapped pose data translation %f,%f,%f quat %f,%f,%f,%f",
-          mapped_pose_buffer_->ring[0].translation[0],
-          mapped_pose_buffer_->ring[0].translation[1],
-          mapped_pose_buffer_->ring[0].translation[2],
-          mapped_pose_buffer_->ring[0].orientation[0],
-          mapped_pose_buffer_->ring[0].orientation[1],
-          mapped_pose_buffer_->ring[0].orientation[2],
-          mapped_pose_buffer_->ring[0].orientation[3]);
-    if (out_info) {
-      GetPoseRingBufferInfo(out_info);
-    }
-    return 0;
+    return -EAGAIN;
   }
 
   int GetControllerRingBuffer(int32_t controller_id) {
@@ -190,7 +187,7 @@
       ALOGE("Pose failed to import ring buffer");
       return -EIO;
     }
-    constexpr size_t size = kPoseAsyncBufferTotalCount * sizeof(DvrPoseAsync);
+    constexpr size_t size = DvrVsyncPoseBuffer::kSize * sizeof(DvrPoseAsync);
     void* addr = nullptr;
     int ret = buffer->GetBlobReadOnlyPointer(size, &addr);
     if (ret < 0 || !addr) {
@@ -201,9 +198,9 @@
     client_state.mapped_pose_buffer = static_cast<const DvrPoseAsync*>(addr);
     ALOGI(
         "Mapped controller %d pose data translation %f,%f,%f quat %f,%f,%f,%f",
-        controller_id, client_state.mapped_pose_buffer[0].translation[0],
-        client_state.mapped_pose_buffer[0].translation[1],
-        client_state.mapped_pose_buffer[0].translation[2],
+        controller_id, client_state.mapped_pose_buffer[0].position[0],
+        client_state.mapped_pose_buffer[0].position[1],
+        client_state.mapped_pose_buffer[0].position[2],
         client_state.mapped_pose_buffer[0].orientation[0],
         client_state.mapped_pose_buffer[0].orientation[1],
         client_state.mapped_pose_buffer[0].orientation[2],
@@ -211,32 +208,6 @@
     return 0;
   }
 
-  int NotifyVsync(uint32_t vsync_count, int64_t display_timestamp,
-                  int64_t display_period_ns,
-                  int64_t right_eye_photon_offset_ns) {
-    const struct iovec data[] = {
-        {.iov_base = &vsync_count, .iov_len = sizeof(vsync_count)},
-        {.iov_base = &display_timestamp, .iov_len = sizeof(display_timestamp)},
-        {.iov_base = &display_period_ns, .iov_len = sizeof(display_period_ns)},
-        {.iov_base = &right_eye_photon_offset_ns,
-         .iov_len = sizeof(right_eye_photon_offset_ns)},
-    };
-    Transaction trans{*this};
-    Status<int> status =
-        trans.SendVector<int>(DVR_POSE_NOTIFY_VSYNC, data, nullptr);
-    ALOGE_IF(!status, "Pose NotifyVsync() failed because: %s\n",
-             status.GetErrorMessage().c_str());
-    return ReturnStatusOrError(status);
-  }
-
-  int GetRingBufferFd(LocalHandle* fd) {
-    int ret = GetRingBuffer(nullptr);
-    if (ret < 0)
-      return ret;
-    *fd = pose_buffer_->GetBlobFd();
-    return 0;
-  }
-
  private:
   friend BASE;
 
@@ -252,14 +223,32 @@
   PoseClient(const PoseClient&) = delete;
   PoseClient& operator=(const PoseClient&) = delete;
 
-  void GetPoseRingBufferInfo(DvrPoseRingBufferInfo* out_info) const {
-    out_info->min_future_count = kPoseAsyncBufferMinFutureCount;
-    out_info->total_count = kPoseAsyncBufferTotalCount;
-    out_info->buffer = mapped_pose_buffer_->ring;
+  const DvrVsyncPoseBuffer* GetVsyncBuffer() {
+    if (mapped_vsync_pose_buffer_ == nullptr) {
+      if (vsync_pose_buffer_ == nullptr) {
+        // The constructor tries mapping it so we do not need TryMapping after.
+        vsync_pose_buffer_ = std::make_unique<CPUMappedBuffer>(
+            DvrGlobalBuffers::kVsyncPoseBuffer, CPUUsageMode::READ_OFTEN);
+      } else if (vsync_pose_buffer_->IsMapped() == false) {
+        vsync_pose_buffer_->TryMapping();
+      }
+
+      if (vsync_pose_buffer_->IsMapped()) {
+        mapped_vsync_pose_buffer_ =
+            static_cast<DvrVsyncPoseBuffer*>(vsync_pose_buffer_->Address());
+      }
+    }
+
+    return mapped_vsync_pose_buffer_;
   }
 
-  std::unique_ptr<BufferConsumer> pose_buffer_;
-  const DvrPoseRingBuffer* mapped_pose_buffer_ = nullptr;
+  // The vsync pose buffer if already mapped.
+  std::unique_ptr<CPUMappedBuffer> vsync_pose_buffer_;
+
+  // The direct sensor pose buffer.
+  std::unique_ptr<SensorPoseRing> sensor_pose_buffer_;
+
+  const DvrVsyncPoseBuffer* mapped_vsync_pose_buffer_ = nullptr;
 
   struct ControllerClientState {
     std::unique_ptr<BufferConsumer> pose_buffer;
@@ -273,66 +262,55 @@
 
 using android::dvr::PoseClient;
 
-struct DvrPose {};
-
 extern "C" {
 
-DvrPose* dvrPoseCreate() {
-  PoseClient* client = PoseClient::Create().release();
-  return reinterpret_cast<DvrPose*>(client);
+DvrPoseClient* dvrPoseClientCreate() {
+  auto* client = PoseClient::Create().release();
+  return reinterpret_cast<DvrPoseClient*>(client);
 }
 
-void dvrPoseDestroy(DvrPose* client) { delete PoseClient::FromC(client); }
+void dvrPoseClientDestroy(DvrPoseClient* client) {
+  delete PoseClient::FromC(client);
+}
 
-int dvrPoseGet(DvrPose* client, uint32_t vsync_count, DvrPoseAsync* out_pose) {
+int dvrPoseClientGet(DvrPoseClient* client, uint32_t vsync_count,
+                     DvrPoseAsync* out_pose) {
   return PoseClient::FromC(client)->GetPose(vsync_count, out_pose);
 }
 
-uint32_t dvrPoseGetVsyncCount(DvrPose* client) {
+uint32_t dvrPoseClientGetVsyncCount(DvrPoseClient* client) {
   return PoseClient::FromC(client)->GetVsyncCount();
 }
 
-int dvrPoseGetController(DvrPose* client, int32_t controller_id,
-                         uint32_t vsync_count, DvrPoseAsync* out_pose) {
+int dvrPoseClientGetController(DvrPoseClient* client, int32_t controller_id,
+                               uint32_t vsync_count, DvrPoseAsync* out_pose) {
   return PoseClient::FromC(client)->GetControllerPose(controller_id,
                                                       vsync_count, out_pose);
 }
 
-int dvrPoseLogController(DvrPose* client, bool enable) {
+int dvrPoseClientLogController(DvrPoseClient* client, bool enable) {
   return PoseClient::FromC(client)->LogController(enable);
 }
 
-int dvrPosePoll(DvrPose* client, DvrPoseState* state) {
+int dvrPoseClientPoll(DvrPoseClient* client, DvrPose* state) {
   return PoseClient::FromC(client)->Poll(state);
 }
 
-int dvrPoseFreeze(DvrPose* client, const DvrPoseState* frozen_state) {
+int dvrPoseClientFreeze(DvrPoseClient* client, const DvrPose* frozen_state) {
   return PoseClient::FromC(client)->Freeze(*frozen_state);
 }
 
-int dvrPoseSetMode(DvrPose* client, DvrPoseMode mode) {
+int dvrPoseClientModeSet(DvrPoseClient* client, DvrPoseMode mode) {
   return PoseClient::FromC(client)->SetMode(mode);
 }
 
-int dvrPoseGetMode(DvrPose* client, DvrPoseMode* mode) {
+int dvrPoseClientModeGet(DvrPoseClient* client, DvrPoseMode* mode) {
   return PoseClient::FromC(client)->GetMode(mode);
 }
 
-int dvrPoseGetRingBuffer(DvrPose* client, DvrPoseRingBufferInfo* out_info) {
-  return PoseClient::FromC(client)->GetRingBuffer(out_info);
-}
 
-int privateDvrPoseNotifyVsync(DvrPose* client, uint32_t vsync_count,
-                              int64_t display_timestamp,
-                              int64_t display_period_ns,
-                              int64_t right_eye_photon_offset_ns) {
-  return PoseClient::FromC(client)->NotifyVsync(vsync_count, display_timestamp,
-                                                display_period_ns,
-                                                right_eye_photon_offset_ns);
-}
-
-int privateDvrPoseGetRingBufferFd(DvrPose* client, LocalHandle* fd) {
-  return PoseClient::FromC(client)->GetRingBufferFd(fd);
+int dvrPoseClientSensorsEnable(DvrPoseClient* client, bool enabled) {
+  return PoseClient::FromC(client)->EnableSensors(enabled);
 }
 
 }  // extern "C"
diff --git a/opengl/Android.bp b/opengl/Android.bp
index c520bda..aec5a95 100644
--- a/opengl/Android.bp
+++ b/opengl/Android.bp
@@ -52,6 +52,12 @@
     license: "include/KHR/NOTICE",
 }
 
+cc_library_headers {
+    name: "gl_headers",
+    vendor_available: true,
+    export_include_dirs: ["include"],
+}
+
 subdirs = [
     "*",
 ]
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index d0996f0..bb28600 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -625,6 +625,11 @@
 #define EGL_MUTABLE_RENDER_BUFFER_BIT_KHR 0x1000
 #endif
 
+#ifndef EGL_KHR_no_config_context
+#define EGL_KHR_no_config_context 1
+#define EGL_NO_CONFIG_KHR                 EGL_CAST(EGLConfig,0)
+#endif /* EGL_KHR_no_config_context */
+
 #ifndef EGL_ANDROID_get_frame_timestamps
 #define EGL_ANDROID_get_frame_timestamps 1
 #define EGL_TIMESTAMPS_ANDROID 0x3430
@@ -667,6 +672,21 @@
 #define EGL_GL_COLORSPACE_BT2020_PQ_EXT   0x3340
 #endif /* EGL_EXT_gl_colorspace_bt2020_pq */
 
+#ifndef EGL_EXT_gl_colorspace_display_p3
+#define EGL_EXT_gl_colorspace_display_p3 1
+#define EGL_GL_COLORSPACE_DISPLAY_P3_EXT 0x3363
+#endif /* EGL_EXT_gl_colorspace_display_p3 */
+
+#ifndef EGL_EXT_gl_colorspace_display_p3_linear
+#define EGL_EXT_gl_colorspace_display_p3_linear 1
+#define EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT 0x3362
+#endif /* EGL_EXT_gl_colorspace_display_p3_linear */
+
+#ifndef EGL_EXT_gl_colorspace_scrgb
+#define EGL_EXT_gl_colorspace_scrgb 1
+#define EGL_GL_COLORSPACE_SCRGB_EXT       0x3351
+#endif /* EGL_EXT_gl_colorspace_scrgb */
+
 #ifndef EGL_EXT_gl_colorspace_scrgb_linear
 #define EGL_EXT_gl_colorspace_scrgb_linear 1
 #define EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT 0x3350
diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk
index 4b08749..c7635e2 100644
--- a/opengl/libagl/Android.mk
+++ b/opengl/libagl/Android.mk
@@ -26,7 +26,7 @@
 LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
 LOCAL_CFLAGS += -fvisibility=hidden
 
-LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils liblog libpixelflinger libETC1 libui
+LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils liblog libpixelflinger libETC1 libui libnativewindow
 
 LOCAL_SRC_FILES_arm += fixed_asm.S iterators.S
 LOCAL_CFLAGS_arm += -fstrict-aliasing
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 04f6d6d..b79051c 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -56,6 +56,24 @@
 EGLBoolean EGLAPI eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
         EGLint left, EGLint top, EGLint width, EGLint height);
 
+
+typedef struct egl_native_pixmap_t
+{
+    int32_t     version;    /* must be 32 */
+    int32_t     width;
+    int32_t     height;
+    int32_t     stride;
+    uint8_t*    data;
+    uint8_t     format;
+    uint8_t     rfu[3];
+    union {
+        uint32_t    compressedFormat;
+        int32_t     vstride;
+    };
+    int32_t     reserved;
+} egl_native_pixmap_t;
+
+
 // ----------------------------------------------------------------------------
 namespace android {
 
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index d6bdc81..b4cc211 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -64,6 +64,16 @@
         "liblog",
         "libdl",
     ],
+    static_libs: [
+        "libarect",
+    ],
+    header_libs: [
+        "gl_headers",
+        "libsystem_headers",
+        "libhardware_headers",
+        "libnativebase_headers",
+    ],
+    export_header_lib_headers: ["gl_headers"],
 
     // we need to access the private Bionic header <bionic_tls.h>
     include_dirs: ["bionic/libc/private"],
@@ -75,16 +85,22 @@
 cc_defaults {
     name: "egl_libs_defaults",
     defaults: ["gl_libs_defaults"],
+    vendor_available: true,
     cflags: [
         "-DLOG_TAG=\"libEGL\"",
     ],
     shared_libs: [
         // ***** DO NOT ADD NEW DEPENDENCIES HERE *****
         // In particular, DO NOT add libutils nor anything "above" libui
-        "libui",
+        "libgraphicsenv",
         "libnativewindow",
         "libbacktrace",
     ],
+    target: {
+        vendor: {
+            exclude_shared_libs: ["libgraphicsenv"],
+        },
+    },
 }
 
 cc_library_static {
@@ -111,7 +127,14 @@
         "EGL/Loader.cpp",
         "EGL/BlobCache.cpp",
     ],
-    shared_libs: ["libvndksupport"],
+    shared_libs: [
+        "libvndksupport",
+        "android.hardware.configstore@1.0",
+        "android.hardware.configstore-utils",
+        "libhidlbase",
+        "libhidltransport",
+        "libutils",
+    ],
     static_libs: ["libEGL_getProcAddress"],
     ldflags: ["-Wl,--exclude-libs=ALL"],
     export_include_dirs: ["EGL/include"],
@@ -129,6 +152,7 @@
 cc_defaults {
     name: "gles_libs_defaults",
     defaults: ["gl_libs_defaults"],
+    vendor_available: true,
     arch: {
         arm: {
             instruction_set: "arm",
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 823b502..32f8caa 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -28,7 +28,9 @@
 #include <cutils/properties.h>
 #include <log/log.h>
 
-#include <ui/GraphicsEnv.h>
+#ifndef __ANDROID_VNDK__
+#include <graphicsenv/GraphicsEnv.h>
+#endif
 #include <vndksupport/linker.h>
 
 #include "egl_trace.h"
@@ -477,10 +479,12 @@
     ATRACE_CALL();
 
     void* dso = nullptr;
+#ifndef __ANDROID_VNDK__
     android_namespace_t* ns = android_getDriverNamespace();
     if (ns) {
         dso = load_updated_driver(kind, ns);
     }
+#endif
     if (!dso) {
         dso = load_system_driver(kind);
         if (!dso)
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index ba3a5f9..0214b0e 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -79,6 +79,7 @@
 extern char const * const gBuiltinExtensionString;
 extern char const * const gExtensionString;
 
+// clang-format off
 char const * const gBuiltinExtensionString =
         "EGL_KHR_get_all_proc_addresses "
         "EGL_ANDROID_presentation_time "
@@ -123,6 +124,7 @@
         "EGL_IMG_context_priority "
         "EGL_KHR_no_config_context "
         ;
+// clang-format on
 
 // extensions not exposed to applications but used by the ANDROID system
 //      "EGL_ANDROID_blob_cache "               // strongly recommended
@@ -452,16 +454,216 @@
 // EGL_GL_COLORSPACE_SRGB_KHR, or turn sRGB formats into corresponding linear
 // formats when colorspace is EGL_GL_COLORSPACE_LINEAR_KHR. In any cases where
 // the modification isn't possible, the original dataSpace is returned.
-static android_dataspace modifyBufferDataspace( android_dataspace dataSpace,
-                                                EGLint colorspace) {
+static android_dataspace modifyBufferDataspace(android_dataspace dataSpace,
+                                               EGLint colorspace) {
     if (colorspace == EGL_GL_COLORSPACE_LINEAR_KHR) {
         return HAL_DATASPACE_SRGB_LINEAR;
     } else if (colorspace == EGL_GL_COLORSPACE_SRGB_KHR) {
         return HAL_DATASPACE_SRGB;
+    } else if (colorspace == EGL_GL_COLORSPACE_DISPLAY_P3_EXT) {
+        return HAL_DATASPACE_DISPLAY_P3;
+    } else if (colorspace == EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT) {
+        return HAL_DATASPACE_DISPLAY_P3_LINEAR;
+    } else if (colorspace == EGL_GL_COLORSPACE_SCRGB_EXT) {
+        return HAL_DATASPACE_V0_SCRGB;
+    } else if (colorspace == EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT) {
+        return HAL_DATASPACE_V0_SCRGB_LINEAR;
     }
     return dataSpace;
 }
 
+// Return true if we stripped any EGL_GL_COLORSPACE_KHR attributes.
+static EGLBoolean stripColorSpaceAttribute(egl_display_ptr dp, const EGLint* attrib_list,
+                                           EGLint format,
+                                           std::vector<EGLint>& stripped_attrib_list) {
+    std::vector<EGLint> allowedColorSpaces;
+    switch (format) {
+        case HAL_PIXEL_FORMAT_RGBA_8888:
+        case HAL_PIXEL_FORMAT_RGB_565:
+            // driver okay with linear & sRGB for 8888, but can't handle
+            // Display-P3 or other spaces.
+            allowedColorSpaces.push_back(EGL_GL_COLORSPACE_SRGB_KHR);
+            allowedColorSpaces.push_back(EGL_GL_COLORSPACE_LINEAR_KHR);
+            break;
+
+        case HAL_PIXEL_FORMAT_RGBA_FP16:
+        case HAL_PIXEL_FORMAT_RGBA_1010102:
+        default:
+            // driver does not want to see colorspace attributes for 1010102 or fp16.
+            // Future: if driver supports XXXX extension, we can pass down that colorspace
+            break;
+    }
+
+    bool stripped = false;
+    if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) {
+        for (const EGLint* attr = attrib_list; attr[0] != EGL_NONE; attr += 2) {
+            if (attr[0] == EGL_GL_COLORSPACE_KHR) {
+                EGLint colorSpace = attr[1];
+                bool found = false;
+                // Verify that color space is allowed
+                for (auto it : allowedColorSpaces) {
+                    if (colorSpace == it) {
+                        found = true;
+                    }
+                }
+                if (!found) {
+                    stripped = true;
+                } else {
+                    stripped_attrib_list.push_back(attr[0]);
+                    stripped_attrib_list.push_back(attr[1]);
+                }
+            } else {
+                stripped_attrib_list.push_back(attr[0]);
+                stripped_attrib_list.push_back(attr[1]);
+            }
+        }
+    }
+    if (stripped) {
+        stripped_attrib_list.push_back(EGL_NONE);
+        stripped_attrib_list.push_back(EGL_NONE);
+    }
+    return stripped;
+}
+
+static EGLBoolean getColorSpaceAttribute(egl_display_ptr dp, NativeWindowType window,
+                                         const EGLint* attrib_list, EGLint& colorSpace,
+                                         android_dataspace& dataSpace) {
+    colorSpace = EGL_GL_COLORSPACE_LINEAR_KHR;
+    dataSpace = HAL_DATASPACE_UNKNOWN;
+
+    if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) {
+        for (const EGLint* attr = attrib_list; *attr != EGL_NONE; attr += 2) {
+            if (*attr == EGL_GL_COLORSPACE_KHR) {
+                colorSpace = attr[1];
+                bool found = false;
+                bool verify = true;
+                // Verify that color space is allowed
+                if (colorSpace == EGL_GL_COLORSPACE_SRGB_KHR ||
+                    colorSpace == EGL_GL_COLORSPACE_LINEAR_KHR) {
+                    // SRGB and LINEAR are always supported when EGL_KHR_gl_colorspace
+                    // is available, so no need to verify.
+                    found = true;
+                    verify = false;
+                } else if (colorSpace == EGL_EXT_gl_colorspace_bt2020_linear &&
+                           dp->haveExtension("EGL_EXT_gl_colorspace_bt2020_linear")) {
+                    found = true;
+                } else if (colorSpace == EGL_EXT_gl_colorspace_bt2020_pq &&
+                           dp->haveExtension("EGL_EXT_gl_colorspace_bt2020_pq")) {
+                    found = true;
+                } else if (colorSpace == EGL_GL_COLORSPACE_SCRGB_EXT &&
+                           dp->haveExtension("EGL_EXT_gl_colorspace_scrgb")) {
+                    found = true;
+                } else if (colorSpace == EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT &&
+                           dp->haveExtension("EGL_EXT_gl_colorspace_scrgb_linear")) {
+                    found = true;
+                } else if (colorSpace == EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT &&
+                           dp->haveExtension("EGL_EXT_gl_colorspace_display_p3_linear")) {
+                    found = true;
+                } else if (colorSpace == EGL_GL_COLORSPACE_DISPLAY_P3_EXT &&
+                           dp->haveExtension("EGL_EXT_gl_colorspace_display_p3")) {
+                    found = true;
+                }
+                if (!found) {
+                    return false;
+                }
+                if (verify && window) {
+                    bool wide_color_support = true;
+                    // Ordinarily we'd put a call to native_window_get_wide_color_support
+                    // at the beginning of the function so that we'll have the
+                    // result when needed elsewhere in the function.
+                    // However, because eglCreateWindowSurface is called by SurfaceFlinger and
+                    // SurfaceFlinger is required to answer the call below we would
+                    // end up in a deadlock situation. By moving the call to only happen
+                    // if the application has specifically asked for wide-color we avoid
+                    // the deadlock with SurfaceFlinger since it will not ask for a
+                    // wide-color surface.
+                    int err = native_window_get_wide_color_support(window, &wide_color_support);
+
+                    if (err) {
+                        ALOGE("getColorSpaceAttribute: invalid window (win=%p) "
+                              "failed (%#x) (already connected to another API?)",
+                              window, err);
+                        return false;
+                    }
+                    if (!wide_color_support) {
+                        // Application has asked for a wide-color colorspace but
+                        // wide-color support isn't available on the display the window is on.
+                        return false;
+                    }
+                }
+                // Only change the dataSpace from default if the application
+                // has explicitly set the color space with a EGL_GL_COLORSPACE_KHR attribute.
+                dataSpace = modifyBufferDataspace(dataSpace, colorSpace);
+            }
+        }
+    }
+    return true;
+}
+
+static EGLBoolean getColorSpaceAttribute(egl_display_ptr dp, const EGLint* attrib_list,
+                                         EGLint& colorSpace, android_dataspace& dataSpace) {
+    return getColorSpaceAttribute(dp, NULL, attrib_list, colorSpace, dataSpace);
+}
+
+void getNativePixelFormat(EGLDisplay dpy, egl_connection_t* cnx, EGLConfig config, EGLint& format) {
+    // Set the native window's buffers format to match what this config requests.
+    // Whether to use sRGB gamma is not part of the EGLconfig, but is part
+    // of our native format. So if sRGB gamma is requested, we have to
+    // modify the EGLconfig's format before setting the native window's
+    // format.
+
+    EGLint componentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
+    cnx->egl.eglGetConfigAttrib(dpy, config, EGL_COLOR_COMPONENT_TYPE_EXT, &componentType);
+
+    EGLint a = 0;
+    EGLint r, g, b;
+    r = g = b = 0;
+    cnx->egl.eglGetConfigAttrib(dpy, config, EGL_RED_SIZE, &r);
+    cnx->egl.eglGetConfigAttrib(dpy, config, EGL_GREEN_SIZE, &g);
+    cnx->egl.eglGetConfigAttrib(dpy, config, EGL_BLUE_SIZE, &b);
+    cnx->egl.eglGetConfigAttrib(dpy, config, EGL_ALPHA_SIZE, &a);
+    EGLint colorDepth = r + g + b;
+
+    // Today, the driver only understands sRGB and linear on 888X
+    // formats. Strip other colorspaces from the attribute list and
+    // only use them to set the dataspace via
+    // native_window_set_buffers_dataspace
+    // if pixel format is RGBX 8888
+    //    TBD: Can test for future extensions that indicate that driver
+    //    handles requested color space and we can let it through.
+    //    allow SRGB and LINEAR. All others need to be stripped.
+    // else if 565, 4444
+    //    TBD: Can we assume these are supported if 8888 is?
+    // else if FP16 or 1010102
+    //    strip colorspace from attribs.
+    // endif
+    if (a == 0) {
+        if (colorDepth <= 16) {
+            format = HAL_PIXEL_FORMAT_RGB_565;
+        } else {
+            if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
+                if (colorDepth > 24) {
+                    format = HAL_PIXEL_FORMAT_RGBA_1010102;
+                } else {
+                    format = HAL_PIXEL_FORMAT_RGBX_8888;
+                }
+            } else {
+                format = HAL_PIXEL_FORMAT_RGBA_FP16;
+            }
+        }
+    } else {
+        if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
+            if (colorDepth > 24) {
+                format = HAL_PIXEL_FORMAT_RGBA_1010102;
+            } else {
+                format = HAL_PIXEL_FORMAT_RGBA_8888;
+            }
+        } else {
+            format = HAL_PIXEL_FORMAT_RGBA_FP16;
+        }
+    }
+}
+
 EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
                                     NativeWindowType window,
                                     const EGLint *attrib_list)
@@ -491,60 +693,22 @@
             return setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
         }
 
-        // Set the native window's buffers format to match what this config requests.
-        // Whether to use sRGB gamma is not part of the EGLconfig, but is part
-        // of our native format. So if sRGB gamma is requested, we have to
-        // modify the EGLconfig's format before setting the native window's
-        // format.
-
-        EGLint componentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
-        cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_COLOR_COMPONENT_TYPE_EXT,
-                                    &componentType);
-
         EGLint format;
-        android_dataspace dataSpace = HAL_DATASPACE_UNKNOWN;
-        EGLint a = 0;
-        EGLint r, g, b;
-        r = g = b = 0;
-        cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_RED_SIZE,   &r);
-        cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_GREEN_SIZE, &g);
-        cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_BLUE_SIZE,  &b);
-        cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_ALPHA_SIZE, &a);
-        EGLint colorDepth = r + g + b;
+        getNativePixelFormat(iDpy, cnx, config, format);
 
-        if (a == 0) {
-            if (colorDepth <= 16) {
-                format = HAL_PIXEL_FORMAT_RGB_565;
-            } else {
-                if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
-                    if (colorDepth > 24) {
-                        format = HAL_PIXEL_FORMAT_RGBA_1010102;
-                    } else {
-                        format = HAL_PIXEL_FORMAT_RGBX_8888;
-                    }
-                } else {
-                    format = HAL_PIXEL_FORMAT_RGBA_FP16;
-                }
-            }
-        } else {
-            if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
-                if (colorDepth > 24) {
-                    format = HAL_PIXEL_FORMAT_RGBA_1010102;
-                } else {
-                    format = HAL_PIXEL_FORMAT_RGBA_8888;
-                }
-            } else {
-                format = HAL_PIXEL_FORMAT_RGBA_FP16;
-            }
+        // now select correct colorspace and dataspace based on user's attribute list
+        EGLint colorSpace;
+        android_dataspace dataSpace;
+        if (!getColorSpaceAttribute(dp, window, attrib_list, colorSpace, dataSpace)) {
+            ALOGE("error invalid colorspace: %d", colorSpace);
+            return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
         }
 
-        // now select a corresponding sRGB format if needed
-        if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) {
-            for (const EGLint* attr = attrib_list; *attr != EGL_NONE; attr += 2) {
-                if (*attr == EGL_GL_COLORSPACE_KHR) {
-                    dataSpace = modifyBufferDataspace(dataSpace, *(attr+1));
-                }
-            }
+        std::vector<EGLint> strippedAttribList;
+        if (stripColorSpaceAttribute(dp, attrib_list, format, strippedAttribList)) {
+            // Had to modify the attribute list due to use of color space.
+            // Use modified list from here on.
+            attrib_list = strippedAttribList.data();
         }
 
         if (format != 0) {
@@ -575,8 +739,8 @@
         EGLSurface surface = cnx->egl.eglCreateWindowSurface(
                 iDpy, config, window, attrib_list);
         if (surface != EGL_NO_SURFACE) {
-            egl_surface_t* s = new egl_surface_t(dp.get(), config, window,
-                    surface, cnx);
+            egl_surface_t* s =
+                    new egl_surface_t(dp.get(), config, window, surface, colorSpace, cnx);
             return s;
         }
 
@@ -595,12 +759,19 @@
 
     egl_connection_t* cnx = NULL;
     egl_display_ptr dp = validate_display_connection(dpy, cnx);
+    EGLint colorSpace;
+    android_dataspace dataSpace;
     if (dp) {
+        // now select a corresponding sRGB format if needed
+        if (!getColorSpaceAttribute(dp, attrib_list, colorSpace, dataSpace)) {
+            ALOGE("error invalid colorspace: %d", colorSpace);
+            return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+        }
+
         EGLSurface surface = cnx->egl.eglCreatePixmapSurface(
                 dp->disp.dpy, config, pixmap, attrib_list);
         if (surface != EGL_NO_SURFACE) {
-            egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL,
-                    surface, cnx);
+            egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, surface, colorSpace, cnx);
             return s;
         }
     }
@@ -615,11 +786,32 @@
     egl_connection_t* cnx = NULL;
     egl_display_ptr dp = validate_display_connection(dpy, cnx);
     if (dp) {
+        EGLDisplay iDpy = dp->disp.dpy;
+        EGLint format;
+        getNativePixelFormat(iDpy, cnx, config, format);
+
+        // now select correct colorspace and dataspace based on user's attribute list
+        EGLint colorSpace;
+        android_dataspace dataSpace;
+        if (!getColorSpaceAttribute(dp, attrib_list, colorSpace, dataSpace)) {
+            ALOGE("error invalid colorspace: %d", colorSpace);
+            return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+        }
+
+        // Pbuffers are not displayed so we don't need to store the
+        // colorspace. We do need to filter out color spaces the
+        // driver doesn't know how to process.
+        std::vector<EGLint> strippedAttribList;
+        if (stripColorSpaceAttribute(dp, attrib_list, format, strippedAttribList)) {
+            // Had to modify the attribute list due to use of color space.
+            // Use modified list from here on.
+            attrib_list = strippedAttribList.data();
+        }
+
         EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
                 dp->disp.dpy, config, attrib_list);
         if (surface != EGL_NO_SURFACE) {
-            egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL,
-                    surface, cnx);
+            egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, surface, colorSpace, cnx);
             return s;
         }
     }
@@ -658,6 +850,10 @@
         return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
 
     egl_surface_t const * const s = get_surface(surface);
+    if (attribute == EGL_GL_COLORSPACE_KHR) {
+        *value = s->getColorSpace();
+        return EGL_TRUE;
+    }
     return s->cnx->egl.eglQuerySurface(
             dp->disp.dpy, s->surface, attribute, value);
 }
@@ -1729,13 +1925,22 @@
     egl_display_ptr dp = validate_display(dpy);
     if (!dp) return EGL_NO_SURFACE;
 
+    EGLint colorSpace = EGL_GL_COLORSPACE_LINEAR_KHR;
+    android_dataspace dataSpace = HAL_DATASPACE_UNKNOWN;
+    // TODO: Probably need to update EGL_KHR_stream_producer_eglsurface to
+    // indicate support for EGL_GL_COLORSPACE_KHR.
+    // now select a corresponding sRGB format if needed
+    if (!getColorSpaceAttribute(dp, attrib_list, colorSpace, dataSpace)) {
+        ALOGE("error invalid colorspace: %d", colorSpace);
+        return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+    }
+
     egl_connection_t* const cnx = &gEGLImpl;
     if (cnx->dso && cnx->egl.eglCreateStreamProducerSurfaceKHR) {
         EGLSurface surface = cnx->egl.eglCreateStreamProducerSurfaceKHR(
                 dp->disp.dpy, config, stream, attrib_list);
         if (surface != EGL_NO_SURFACE) {
-            egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL,
-                    surface, cnx);
+            egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, surface, colorSpace, cnx);
             return s;
         }
     }
@@ -1886,8 +2091,15 @@
 
 EGLClientBuffer eglGetNativeClientBufferANDROID(const AHardwareBuffer *buffer) {
     clearError();
+    // AHardwareBuffer_to_ANativeWindowBuffer is a platform-only symbol and thus
+    // this function cannot be implemented when this libEGL is built for
+    // vendors.
+#ifndef __ANDROID_VNDK__
     if (!buffer) return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0);
     return const_cast<ANativeWindowBuffer *>(AHardwareBuffer_to_ANativeWindowBuffer(buffer));
+#else
+    return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0);
+#endif
 }
 
 // ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp
index dc1a4af..579e422 100644
--- a/opengl/libs/EGL/egl_cache.cpp
+++ b/opengl/libs/EGL/egl_cache.cpp
@@ -26,6 +26,7 @@
 #include <inttypes.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
+#include <unistd.h>
 
 #include <thread>
 
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index b696920..4e5833a 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -30,6 +30,12 @@
 #include "Loader.h"
 #include <cutils/properties.h>
 
+#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <configstore/Utils.h>
+
+using namespace android::hardware::configstore;
+using namespace android::hardware::configstore::V1_0;
+
 // ----------------------------------------------------------------------------
 namespace android {
 // ----------------------------------------------------------------------------
@@ -192,6 +198,18 @@
         mClientApiString = sClientApiString;
 
         mExtensionString = gBuiltinExtensionString;
+
+        bool wideColorBoardConfig =
+                getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(
+                        false);
+
+        // Add wide-color extensions if device can support wide-color
+        if (wideColorBoardConfig) {
+            mExtensionString.append(
+                    "EGL_EXT_gl_colorspace_scrgb EGL_EXT_gl_colorspace_scrgb_linear "
+                    "EGL_EXT_gl_colorspace_display_p3_linear EGL_EXT_gl_colorspace_display_p3 ");
+        }
+
         char const* start = gExtensionString;
         do {
             // length of the extension name
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index 6238780..837cfa9 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -55,12 +55,15 @@
 
 // ----------------------------------------------------------------------------
 
-egl_surface_t::egl_surface_t(egl_display_t* dpy, EGLConfig config,
-        EGLNativeWindowType win, EGLSurface surface,
-        egl_connection_t const* cnx) :
-    egl_object_t(dpy), surface(surface), config(config), win(win), cnx(cnx),
-    connected(true)
-{
+egl_surface_t::egl_surface_t(egl_display_t* dpy, EGLConfig config, EGLNativeWindowType win,
+                             EGLSurface surface, EGLint colorSpace, egl_connection_t const* cnx)
+      : egl_object_t(dpy),
+        surface(surface),
+        config(config),
+        win(win),
+        cnx(cnx),
+        connected(true),
+        colorSpace(colorSpace) {
     if (win) {
         win->incStrong(this);
     }
diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h
index 8988905..7c3075c 100644
--- a/opengl/libs/EGL/egl_object.h
+++ b/opengl/libs/EGL/egl_object.h
@@ -131,12 +131,12 @@
 public:
     typedef egl_object_t::LocalRef<egl_surface_t, EGLSurface> Ref;
 
-    egl_surface_t(egl_display_t* dpy, EGLConfig config,
-            EGLNativeWindowType win, EGLSurface surface,
-            egl_connection_t const* cnx);
+    egl_surface_t(egl_display_t* dpy, EGLConfig config, EGLNativeWindowType win, EGLSurface surface,
+                  EGLint colorSpace, egl_connection_t const* cnx);
 
     ANativeWindow* getNativeWindow() { return win; }
     ANativeWindow* getNativeWindow() const { return win; }
+    EGLint getColorSpace() const { return colorSpace; }
 
     // Try to keep the order of these fields and size unchanged. It's not public API, but
     // it's not hard to imagine native games accessing them.
@@ -149,6 +149,7 @@
 private:
     bool connected;
     void disconnect();
+    EGLint colorSpace;
 };
 
 class egl_context_t: public egl_object_t {
diff --git a/opengl/tests/Android.bp b/opengl/tests/Android.bp
new file mode 100644
index 0000000..bf7aeb1
--- /dev/null
+++ b/opengl/tests/Android.bp
@@ -0,0 +1,4 @@
+subdirs = [
+    "hwc",
+    "lib",
+]
diff --git a/opengl/tests/Android.mk b/opengl/tests/Android.mk
index 3ae3b4e..92d223c 100644
--- a/opengl/tests/Android.mk
+++ b/opengl/tests/Android.mk
@@ -12,7 +12,6 @@
 	gl_perf \
 	gl_yuvtex \
 	gralloc \
-	hwc \
 	include \
 	lib \
 	linetex \
diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp
index 24b1315..62e6bd3 100644
--- a/opengl/tests/EGLTest/EGL_test.cpp
+++ b/opengl/tests/EGLTest/EGL_test.cpp
@@ -28,18 +28,17 @@
 #include <gui/IGraphicBufferConsumer.h>
 #include <gui/BufferQueue.h>
 
-#define PIXEL_FORMAT_FLOAT "EGL_EXT_pixel_format_float"
-
-bool hasEglPixelFormatFloat() {
-    EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+bool hasEglExtension(EGLDisplay dpy, const char* extensionName) {
     const char* exts = eglQueryString(dpy, EGL_EXTENSIONS);
-    size_t cropExtLen = strlen(PIXEL_FORMAT_FLOAT);
+    size_t cropExtLen = strlen(extensionName);
     size_t extsLen = strlen(exts);
-    bool equal = !strcmp(PIXEL_FORMAT_FLOAT, exts);
-    bool atStart = !strncmp(PIXEL_FORMAT_FLOAT " ", exts, cropExtLen + 1);
+    bool equal = !strcmp(extensionName, exts);
+    android::String8 extString(extensionName);
+    android::String8 space(" ");
+    bool atStart = !strncmp(extString + space, exts, cropExtLen + 1);
     bool atEnd = (cropExtLen + 1) < extsLen &&
-            !strcmp(" " PIXEL_FORMAT_FLOAT, exts + extsLen - (cropExtLen + 1));
-    bool inMiddle = strstr(exts, " " PIXEL_FORMAT_FLOAT " ");
+            !strcmp(space + extString, exts + extsLen - (cropExtLen + 1));
+    bool inMiddle = strstr(exts, space + extString + space);
     return equal || atStart || atEnd || inMiddle;
 }
 
@@ -194,6 +193,176 @@
     EXPECT_GE(components[3], 8);
 }
 
+TEST_F(EGLTest, EGLDisplayP3) {
+    EGLint numConfigs;
+    EGLConfig config;
+    EGLBoolean success;
+
+    if (!hasWideColorDisplay) {
+        // skip this test if device does not have wide-color display
+        return;
+    }
+
+    // Test that display-p3 extensions exist
+    ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_gl_colorspace_display_p3"));
+    ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_gl_colorspace_display_p3_linear"));
+
+    // Use 8-bit to keep forcus on Display-P3 aspect
+    EGLint attrs[] = {
+            // clang-format off
+            EGL_SURFACE_TYPE,             EGL_WINDOW_BIT,
+            EGL_RENDERABLE_TYPE,          EGL_OPENGL_ES2_BIT,
+            EGL_SURFACE_TYPE,             EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
+            EGL_RED_SIZE,                 8,
+            EGL_GREEN_SIZE,               8,
+            EGL_BLUE_SIZE,                8,
+            EGL_ALPHA_SIZE,               8,
+            EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FIXED_EXT,
+            EGL_NONE,                     EGL_NONE
+            // clang-format on
+    };
+    success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(1, numConfigs);
+
+    EGLint components[4];
+    EGLint value;
+    eglGetConfigAttrib(mEglDisplay, config, EGL_CONFIG_ID, &value);
+
+    success = eglGetConfigAttrib(mEglDisplay, config, EGL_RED_SIZE, &components[0]);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    success = eglGetConfigAttrib(mEglDisplay, config, EGL_GREEN_SIZE, &components[1]);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    success = eglGetConfigAttrib(mEglDisplay, config, EGL_BLUE_SIZE, &components[2]);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    success = eglGetConfigAttrib(mEglDisplay, config, EGL_ALPHA_SIZE, &components[3]);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+    EXPECT_EQ(components[0], 8);
+    EXPECT_EQ(components[1], 8);
+    EXPECT_EQ(components[2], 8);
+    EXPECT_EQ(components[3], 8);
+
+    struct DummyConsumer : public BnConsumerListener {
+        void onFrameAvailable(const BufferItem& /* item */) override {}
+        void onBuffersReleased() override {}
+        void onSidebandStreamChanged() override {}
+    };
+
+    // Create a EGLSurface
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    consumer->consumerConnect(new DummyConsumer, false);
+    sp<Surface> mSTC = new Surface(producer);
+    sp<ANativeWindow> mANW = mSTC;
+    EGLint winAttrs[] = {
+            // clang-format off
+            EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_DISPLAY_P3_EXT,
+            EGL_NONE,              EGL_NONE
+            // clang-format on
+    };
+
+    EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs);
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    ASSERT_NE(EGL_NO_SURFACE, eglSurface);
+
+    success = eglQuerySurface(mEglDisplay, eglSurface, EGL_GL_COLORSPACE_KHR, &value);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(EGL_GL_COLORSPACE_DISPLAY_P3_EXT, value);
+
+    EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
+}
+
+TEST_F(EGLTest, EGLDisplayP31010102) {
+    EGLint numConfigs;
+    EGLConfig config;
+    EGLBoolean success;
+
+    if (!hasWideColorDisplay) {
+        // skip this test if device does not have wide-color display
+        return;
+    }
+
+    // Test that display-p3 extensions exist
+    ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_gl_colorspace_display_p3"));
+    ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_gl_colorspace_display_p3_linear"));
+
+    // Use 8-bit to keep forcus on Display-P3 aspect
+    EGLint attrs[] = {
+            // clang-format off
+            EGL_SURFACE_TYPE,             EGL_WINDOW_BIT,
+            EGL_RENDERABLE_TYPE,          EGL_OPENGL_ES2_BIT,
+            EGL_SURFACE_TYPE,             EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
+            EGL_RED_SIZE,                 10,
+            EGL_GREEN_SIZE,               10,
+            EGL_BLUE_SIZE,                10,
+            EGL_ALPHA_SIZE,               2,
+            EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FIXED_EXT,
+            EGL_NONE,                     EGL_NONE
+            // clang-format on
+    };
+    success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(1, numConfigs);
+
+    EGLint components[4];
+    EGLint value;
+    eglGetConfigAttrib(mEglDisplay, config, EGL_CONFIG_ID, &value);
+
+    success = eglGetConfigAttrib(mEglDisplay, config, EGL_RED_SIZE, &components[0]);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    success = eglGetConfigAttrib(mEglDisplay, config, EGL_GREEN_SIZE, &components[1]);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    success = eglGetConfigAttrib(mEglDisplay, config, EGL_BLUE_SIZE, &components[2]);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    success = eglGetConfigAttrib(mEglDisplay, config, EGL_ALPHA_SIZE, &components[3]);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+    EXPECT_EQ(components[0], 10);
+    EXPECT_EQ(components[1], 10);
+    EXPECT_EQ(components[2], 10);
+    EXPECT_EQ(components[3], 2);
+
+    struct DummyConsumer : public BnConsumerListener {
+        void onFrameAvailable(const BufferItem& /* item */) override {}
+        void onBuffersReleased() override {}
+        void onSidebandStreamChanged() override {}
+    };
+
+    // Create a EGLSurface
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    consumer->consumerConnect(new DummyConsumer, false);
+    sp<Surface> mSTC = new Surface(producer);
+    sp<ANativeWindow> mANW = mSTC;
+    EGLint winAttrs[] = {
+            // clang-format off
+            EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_DISPLAY_P3_EXT,
+            EGL_NONE,              EGL_NONE
+            // clang-format on
+    };
+
+    EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs);
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    ASSERT_NE(EGL_NO_SURFACE, eglSurface);
+
+    success = eglQuerySurface(mEglDisplay, eglSurface, EGL_GL_COLORSPACE_KHR, &value);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(EGL_GL_COLORSPACE_DISPLAY_P3_EXT, value);
+
+    EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
+}
+
 TEST_F(EGLTest, EGLConfigFP16) {
     EGLint numConfigs;
     EGLConfig config;
@@ -204,23 +373,20 @@
         return;
     }
 
-    ASSERT_TRUE(hasEglPixelFormatFloat());
+    ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_EXT_pixel_format_float"));
 
-    EGLint attrs[] = {EGL_SURFACE_TYPE,
-                      EGL_WINDOW_BIT,
-                      EGL_RENDERABLE_TYPE,
-                      EGL_OPENGL_ES2_BIT,
-                      EGL_RED_SIZE,
-                      16,
-                      EGL_GREEN_SIZE,
-                      16,
-                      EGL_BLUE_SIZE,
-                      16,
-                      EGL_ALPHA_SIZE,
-                      16,
-                      EGL_COLOR_COMPONENT_TYPE_EXT,
-                      EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT,
-                      EGL_NONE};
+    EGLint attrs[] = {
+            // clang-format off
+            EGL_SURFACE_TYPE,             EGL_WINDOW_BIT,
+            EGL_RENDERABLE_TYPE,          EGL_OPENGL_ES2_BIT,
+            EGL_RED_SIZE,                 16,
+            EGL_GREEN_SIZE,               16,
+            EGL_BLUE_SIZE,                16,
+            EGL_ALPHA_SIZE,               16,
+            EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT,
+            EGL_NONE,                     EGL_NONE
+            // clang-format on
+    };
     success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs);
     ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
     ASSERT_EQ(1, numConfigs);
@@ -251,6 +417,108 @@
         void onSidebandStreamChanged() override {}
     };
 
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    consumer->consumerConnect(new DummyConsumer, false);
+    sp<Surface> mSTC = new Surface(producer);
+    sp<ANativeWindow> mANW = mSTC;
+
+    EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), NULL);
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    ASSERT_NE(EGL_NO_SURFACE, eglSurface);
+
+    EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface));
+}
+
+TEST_F(EGLTest, EGL_KHR_no_config_context) {
+    if (!hasWideColorDisplay) {
+        // skip this test if device does not have wide-color display
+        return;
+    }
+
+    ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_KHR_no_config_context"));
+
+    struct DummyConsumer : public BnConsumerListener {
+        void onFrameAvailable(const BufferItem& /* item */) override {}
+        void onBuffersReleased() override {}
+        void onSidebandStreamChanged() override {}
+    };
+
+    std::vector<EGLint> contextAttributes;
+    contextAttributes.reserve(4);
+    contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
+    contextAttributes.push_back(2);
+    contextAttributes.push_back(EGL_NONE);
+    contextAttributes.push_back(EGL_NONE);
+
+    EGLContext eglContext = eglCreateContext(mEglDisplay, EGL_NO_CONFIG_KHR, EGL_NO_CONTEXT,
+                                             contextAttributes.data());
+    EXPECT_NE(EGL_NO_CONTEXT, eglContext);
+    EXPECT_EQ(EGL_SUCCESS, eglGetError());
+
+    if (eglContext != EGL_NO_CONTEXT) {
+        eglDestroyContext(mEglDisplay, eglContext);
+    }
+}
+
+// Emulate what a native application would do to create a
+// 10:10:10:2 surface.
+TEST_F(EGLTest, EGLConfig1010102) {
+    EGLint numConfigs;
+    EGLConfig config;
+    EGLBoolean success;
+
+    if (!hasWideColorDisplay) {
+        // skip this test if device does not have wide-color display
+        return;
+    }
+
+    EGLint attrs[] = {
+            // clang-format off
+            EGL_SURFACE_TYPE,             EGL_WINDOW_BIT,
+            EGL_RENDERABLE_TYPE,          EGL_OPENGL_ES2_BIT,
+            EGL_SURFACE_TYPE,             EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
+            EGL_RED_SIZE,                 10,
+            EGL_GREEN_SIZE,               10,
+            EGL_BLUE_SIZE,                10,
+            EGL_ALPHA_SIZE,               2,
+            EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FIXED_EXT,
+            EGL_NONE,                     EGL_NONE
+            // clang-format on
+    };
+    success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(1, numConfigs);
+
+    EGLint components[4];
+    EGLint value;
+    eglGetConfigAttrib(mEglDisplay, config, EGL_CONFIG_ID, &value);
+
+    success = eglGetConfigAttrib(mEglDisplay, config, EGL_RED_SIZE, &components[0]);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    success = eglGetConfigAttrib(mEglDisplay, config, EGL_GREEN_SIZE, &components[1]);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    success = eglGetConfigAttrib(mEglDisplay, config, EGL_BLUE_SIZE, &components[2]);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    success = eglGetConfigAttrib(mEglDisplay, config, EGL_ALPHA_SIZE, &components[3]);
+    ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+    EXPECT_EQ(components[0], 10);
+    EXPECT_EQ(components[1], 10);
+    EXPECT_EQ(components[2], 10);
+    EXPECT_EQ(components[3], 2);
+
+    struct DummyConsumer : public BnConsumerListener {
+        void onFrameAvailable(const BufferItem& /* item */) override {}
+        void onBuffersReleased() override {}
+        void onSidebandStreamChanged() override {}
+    };
+
     // Create a EGLSurface
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
diff --git a/opengl/tests/configdump/configdump.cpp b/opengl/tests/configdump/configdump.cpp
index 2a94598..c423105 100644
--- a/opengl/tests/configdump/configdump.cpp
+++ b/opengl/tests/configdump/configdump.cpp
@@ -66,8 +66,7 @@
 };
 // clang-format on
 
-int main(int argc, char** argv)
-{
+int main(int /*argc*/, char** /*argv*/) {
     EGLConfig* configs;
     EGLint n;
 
diff --git a/opengl/tests/gl2_basic/gl2_basic.cpp b/opengl/tests/gl2_basic/gl2_basic.cpp
index 9f8d166..ee88667 100644
--- a/opengl/tests/gl2_basic/gl2_basic.cpp
+++ b/opengl/tests/gl2_basic/gl2_basic.cpp
@@ -30,6 +30,7 @@
 #include <EGLUtils.h>
 
 using namespace android;
+EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
 
 static void printGLString(const char *name, GLenum s) {
     // fprintf(stderr, "printGLString %s, %d\n", name, s);
@@ -46,7 +47,8 @@
 
 static void printEGLString(EGLDisplay dpy, const char *name, GLenum s) {
     const char *v = (const char *) eglQueryString(dpy, s);
-    fprintf(stderr, "GL %s = %s\n", name, v);
+    const char* va = (const char*)eglQueryStringImplementationANDROID(dpy, s);
+    fprintf(stderr, "GL %s = %s\nImplementationANDROID: %s\n", name, v, va);
 }
 
 static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) {
@@ -263,7 +265,7 @@
     return true;
 }
 
-int main(int argc, char** argv) {
+int main(int /*argc*/, char** /*argv*/) {
     EGLBoolean returnValue;
     EGLConfig myConfig = {0};
 
diff --git a/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp b/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp
index 98d8aa8..22128ab 100644
--- a/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp
+++ b/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp
@@ -331,7 +331,7 @@
     printf("\n");
 }
 
-int main(int argc, char** argv) {
+int main(int /*argc*/, char** /*argv*/) {
     EGLBoolean returnValue;
     EGLConfig myConfig = {0};
 
diff --git a/opengl/tests/gl_yuvtex/gl_yuvtex.cpp b/opengl/tests/gl_yuvtex/gl_yuvtex.cpp
index c923b07..fad26a6 100644
--- a/opengl/tests/gl_yuvtex/gl_yuvtex.cpp
+++ b/opengl/tests/gl_yuvtex/gl_yuvtex.cpp
@@ -221,7 +221,7 @@
     printf("\n");
 }
 
-int main(int argc, char** argv) {
+int main(int /*argc*/, char** /*argv*/) {
     EGLBoolean returnValue;
     EGLConfig myConfig = {0};
 
diff --git a/opengl/tests/hwc/Android.bp b/opengl/tests/hwc/Android.bp
new file mode 100644
index 0000000..425f374
--- /dev/null
+++ b/opengl/tests/hwc/Android.bp
@@ -0,0 +1,107 @@
+// Copyright (C) 2010 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.
+
+cc_defaults {
+
+    name: "hwc_tests_defaults",
+    cflags: [
+        "-DGL_GLEXT_PROTOTYPES",
+        "-DEGL_EGLEXT_PROTOTYPES",
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+}
+
+cc_library_static {
+
+    name: "libhwcTest",
+    srcs: ["hwcTestLib.cpp"],
+
+    static_libs: [
+        "libarect",
+        "libglTest",
+        "libtestUtil",
+    ],
+    shared_libs: [
+        "libui",
+        "libnativewindow"
+    ],
+    defaults: ["hwc_tests_defaults"],
+}
+
+cc_defaults {
+
+    name: "hwc_lib_defaults",
+    shared_libs: [
+        "libcutils",
+        "libEGL",
+        "libGLESv2",
+        "libhardware",
+        "liblog",
+        "libui",
+        "libutils",
+        "libnativewindow"
+    ],
+
+    static_libs: [
+        "libglTest",
+        "libhwcTest",
+        "libtestUtil",
+    ],
+}
+
+cc_test {
+
+    name: "hwcStress",
+    srcs: ["hwcStress.cpp"],
+
+    defaults: [
+        "hwc_lib_defaults",
+        "hwc_tests_defaults",
+    ],
+}
+
+cc_test {
+
+    name: "hwcRects",
+    srcs: ["hwcRects.cpp"],
+
+    defaults: [
+        "hwc_lib_defaults",
+        "hwc_tests_defaults",
+    ],
+}
+
+cc_test {
+
+    name: "hwcColorEquiv",
+    srcs: ["hwcColorEquiv.cpp"],
+
+    defaults: [
+        "hwc_lib_defaults",
+        "hwc_tests_defaults",
+    ],
+}
+
+cc_test {
+
+    name: "hwcCommit",
+    srcs: ["hwcCommit.cpp"],
+
+    defaults: [
+        "hwc_lib_defaults",
+        "hwc_tests_defaults",
+    ],
+}
diff --git a/opengl/tests/hwc/Android.mk b/opengl/tests/hwc/Android.mk
deleted file mode 100644
index 13337c2..0000000
--- a/opengl/tests/hwc/Android.mk
+++ /dev/null
@@ -1,150 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE:= libhwcTest
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror
-LOCAL_CXX_STL := libc++
-LOCAL_SRC_FILES:= hwcTestLib.cpp
-LOCAL_C_INCLUDES += system/extras/tests/include \
-    $(call include-path-for, opengl-tests-includes) \
-
-LOCAL_STATIC_LIBRARIES := libarect
-
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_MODULE:= hwcStress
-LOCAL_MODULE_TAGS := tests
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror
-LOCAL_CXX_STL := libc++
-LOCAL_SRC_FILES:= hwcStress.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    libEGL \
-    libGLESv2 \
-    libutils \
-    liblog \
-    libui \
-    libhardware \
-
-LOCAL_STATIC_LIBRARIES := \
-    libtestUtil \
-    libglTest \
-    libhwcTest \
-
-LOCAL_C_INCLUDES += \
-    system/extras/tests/include \
-    hardware/libhardware/include \
-    $(call include-path-for, opengl-tests-includes) \
-
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_MODULE:= hwcRects
-LOCAL_MODULE_TAGS := tests
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror
-LOCAL_CXX_STL := libc++
-LOCAL_SRC_FILES:= hwcRects.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    libEGL \
-    libGLESv2 \
-    libutils \
-    liblog \
-    libui \
-    libhardware \
-
-LOCAL_STATIC_LIBRARIES := \
-    libtestUtil \
-    libglTest \
-    libhwcTest \
-
-LOCAL_C_INCLUDES += \
-    system/extras/tests/include \
-    hardware/libhardware/include \
-    $(call include-path-for, opengl-tests-includes) \
-
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_MODULE:= hwcColorEquiv
-LOCAL_MODULE_TAGS := tests
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror
-LOCAL_CXX_STL := libc++
-LOCAL_SRC_FILES:= hwcColorEquiv.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    libEGL \
-    libGLESv2 \
-    libutils \
-    liblog \
-    libui \
-    libhardware \
-
-LOCAL_STATIC_LIBRARIES := \
-    libtestUtil \
-    libglTest \
-    libhwcTest \
-
-LOCAL_C_INCLUDES += \
-    system/extras/tests/include \
-    hardware/libhardware/include \
-    $(call include-path-for, opengl-tests-includes) \
-
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_MODULE:= hwcCommit
-LOCAL_MODULE_TAGS := tests
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror
-LOCAL_CXX_STL := libc++
-LOCAL_SRC_FILES:= hwcCommit.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    libEGL \
-    libGLESv2 \
-    libutils \
-    liblog \
-    libui \
-    libhardware \
-
-LOCAL_STATIC_LIBRARIES := \
-    libtestUtil \
-    libglTest \
-    libhwcTest \
-
-LOCAL_C_INCLUDES += \
-    system/extras/tests/include \
-    hardware/libhardware/include \
-    $(call include-path-for, opengl-tests-includes) \
-
-include $(BUILD_NATIVE_TEST)
diff --git a/opengl/tests/lib/Android.bp b/opengl/tests/lib/Android.bp
new file mode 100644
index 0000000..2f6095d
--- /dev/null
+++ b/opengl/tests/lib/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2010 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.
+
+cc_library_static {
+
+    name: "libglTest",
+    srcs: [
+        "glTestLib.cpp",
+        "WindowSurface.cpp",
+    ],
+    export_include_dirs: ["include"],
+
+    cflags: [
+        "-DGL_GLEXT_PROTOTYPES",
+        "-DEGL_EGLEXT_PROTOTYPES",
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+
+    shared_libs: ["libgui"],
+    static_libs: [
+        "libarect",
+        "libtestUtil",
+    ],
+
+}
diff --git a/opengl/tests/lib/Android.mk b/opengl/tests/lib/Android.mk
deleted file mode 100644
index ea94bc1..0000000
--- a/opengl/tests/lib/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE:= libglTest
-LOCAL_SRC_FILES:= glTestLib.cpp WindowSurface.cpp
-LOCAL_C_INCLUDES += system/extras/tests/include \
-	$(call include-path-for, opengl-tests-includes)
-
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -Wall -Wextra -Werror
-
-LOCAL_SHARED_LIBRARIES += libgui
-LOCAL_STATIC_LIBRARIES := libarect
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/opengl/tests/include/EGLUtils.h b/opengl/tests/lib/include/EGLUtils.h
similarity index 100%
rename from opengl/tests/include/EGLUtils.h
rename to opengl/tests/lib/include/EGLUtils.h
diff --git a/opengl/tests/include/WindowSurface.h b/opengl/tests/lib/include/WindowSurface.h
similarity index 100%
rename from opengl/tests/include/WindowSurface.h
rename to opengl/tests/lib/include/WindowSurface.h
diff --git a/opengl/tests/include/glTestLib.h b/opengl/tests/lib/include/glTestLib.h
similarity index 100%
rename from opengl/tests/include/glTestLib.h
rename to opengl/tests/lib/include/glTestLib.h
diff --git a/opengl/tools/glgen2/registry/egl.xml b/opengl/tools/glgen2/registry/egl.xml
index af13395..c2d3494 100755
--- a/opengl/tools/glgen2/registry/egl.xml
+++ b/opengl/tools/glgen2/registry/egl.xml
@@ -191,6 +191,7 @@
         <enum value="((EGLSync)0)" name="EGL_NO_SYNC"/>
         <enum value="((EGLSyncKHR)0)" name="EGL_NO_SYNC_KHR" alias="EGL_NO_SYNC"/>
         <enum value="((EGLSyncNV)0)" name="EGL_NO_SYNC_NV" alias="EGL_NO_SYNC"/>
+        <enum value="EGL_CAST(EGLConfig,0)" name="EGL_NO_CONFIG_KHR"/>
         <enum value="10000" name="EGL_DISPLAY_SCALING"/>
         <enum value="0xFFFFFFFFFFFFFFFF" name="EGL_FOREVER" type="ull"/>
         <enum value="0xFFFFFFFFFFFFFFFF" name="EGL_FOREVER_KHR" type="ull" alias="EGL_FOREVER"/>
@@ -739,7 +740,10 @@
         <enum value="50000"  name="EGL_METADATA_SCALING_EXT"/>
             <unused start="0x334B" end="0x334F"/>
         <enum value="0x3350" name="EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT"/>
-            <unused start="0x3351" end="0x339F"/>
+            <unused start="0x3351" end="0x3361"/>
+        <enum value="0x3362" name="EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT"/>
+        <enum value="0x3363" name="EGL_GL_COLORSPACE_DISPLAY_P3_EXT"/>
+            <unused start="0x3364" end="0x339F"/>
     </enums>
 
     <enums namespace="EGL" start="0x33A0" end="0x33AF" vendor="ANGLE" comment="Reserved for Shannon Woods (Bug 13175)">
@@ -1891,6 +1895,16 @@
                 <enum name="EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT"/>
             </require>
         </extension>
+        <extension name="EGL_EXT_gl_colorspace_display_p3_linear" supported="egl">
+            <require>
+                <enum name="EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT"/>
+            </require>
+        </extension>
+        <extension name="EGL_EXT_gl_colorspace_display_p3" supported="egl">
+            <require>
+                <enum name="EGL_GL_COLORSPACE_DISPLAY_P3_EXT"/>
+            </require>
+        </extension>
         <extension name="EGL_EXT_image_dma_buf_import" supported="egl">
             <require>
                 <enum name="EGL_LINUX_DMA_BUF_EXT"/>
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
new file mode 100644
index 0000000..4fd98e2
--- /dev/null
+++ b/services/inputflinger/Android.bp
@@ -0,0 +1,51 @@
+// Copyright (C) 2013 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+    name: "libinputflinger",
+
+    srcs: [
+        "EventHub.cpp",
+        "InputApplication.cpp",
+        "InputDispatcher.cpp",
+        "InputListener.cpp",
+        "InputManager.cpp",
+        "InputReader.cpp",
+        "InputWindow.cpp",
+    ],
+
+    shared_libs: [
+        "libbinder",
+        "libcrypto",
+        "libcutils",
+        "libinput",
+        "liblog",
+        "libutils",
+        "libui",
+        "libhardware_legacy",
+    ],
+
+    cflags: [
+        "-Wno-unused-parameter",
+        // TODO: Move inputflinger to its own process and mark it hidden
+        //-fvisibility=hidden
+    ],
+
+    export_include_dirs: ["."],
+}
+
+subdirs = [
+    "host",
+    "tests",
+]
diff --git a/services/inputflinger/Android.mk b/services/inputflinger/Android.mk
deleted file mode 100644
index ed867d8..0000000
--- a/services/inputflinger/Android.mk
+++ /dev/null
@@ -1,49 +0,0 @@
-# Copyright (C) 2013 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-    EventHub.cpp \
-    InputApplication.cpp \
-    InputDispatcher.cpp \
-    InputListener.cpp \
-    InputManager.cpp \
-    InputReader.cpp \
-    InputWindow.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-    libbinder \
-    libcrypto \
-    libcutils \
-    libinput \
-    liblog \
-    libutils \
-    libui \
-    libhardware_legacy
-
-
-# TODO: Move inputflinger to its own process and mark it hidden
-#LOCAL_CFLAGS += -fvisibility=hidden
-
-LOCAL_CFLAGS += -Wno-unused-parameter
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
-
-LOCAL_MODULE := libinputflinger
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index d2f8995..50589b4 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -150,7 +150,8 @@
         fd(fd), id(id), path(path), identifier(identifier),
         classes(0), configuration(NULL), virtualKeyMap(NULL),
         ffEffectPlaying(false), ffEffectId(-1), controllerNumber(0),
-        timestampOverrideSec(0), timestampOverrideUsec(0) {
+        timestampOverrideSec(0), timestampOverrideUsec(0), enabled(true),
+        isVirtual(fd < 0) {
     memset(keyBitmask, 0, sizeof(keyBitmask));
     memset(absBitmask, 0, sizeof(absBitmask));
     memset(relBitmask, 0, sizeof(relBitmask));
@@ -173,6 +174,25 @@
     }
 }
 
+status_t EventHub::Device::enable() {
+    fd = open(path, O_RDWR | O_CLOEXEC | O_NONBLOCK);
+    if(fd < 0) {
+        ALOGE("could not open %s, %s\n", path.string(), strerror(errno));
+        return -errno;
+    }
+    enabled = true;
+    return OK;
+}
+
+status_t EventHub::Device::disable() {
+    close();
+    enabled = false;
+    return OK;
+}
+
+bool EventHub::Device::hasValidFd() {
+    return !isVirtual && enabled;
+}
 
 // --- EventHub ---
 
@@ -286,7 +306,7 @@
         AutoMutex _l(mLock);
 
         Device* device = getDeviceLocked(deviceId);
-        if (device && !device->isVirtual() && test_bit(axis, device->absBitmask)) {
+        if (device && device->hasValidFd() && test_bit(axis, device->absBitmask)) {
             struct input_absinfo info;
             if(ioctl(device->fd, EVIOCGABS(axis), &info)) {
                 ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d",
@@ -337,7 +357,7 @@
         AutoMutex _l(mLock);
 
         Device* device = getDeviceLocked(deviceId);
-        if (device && !device->isVirtual() && test_bit(scanCode, device->keyBitmask)) {
+        if (device && device->hasValidFd() && test_bit(scanCode, device->keyBitmask)) {
             uint8_t keyState[sizeof_bit_array(KEY_MAX + 1)];
             memset(keyState, 0, sizeof(keyState));
             if (ioctl(device->fd, EVIOCGKEY(sizeof(keyState)), keyState) >= 0) {
@@ -352,7 +372,7 @@
     AutoMutex _l(mLock);
 
     Device* device = getDeviceLocked(deviceId);
-    if (device && !device->isVirtual() && device->keyMap.haveKeyLayout()) {
+    if (device && device->hasValidFd() && device->keyMap.haveKeyLayout()) {
         Vector<int32_t> scanCodes;
         device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode, &scanCodes);
         if (scanCodes.size() != 0) {
@@ -377,7 +397,7 @@
         AutoMutex _l(mLock);
 
         Device* device = getDeviceLocked(deviceId);
-        if (device && !device->isVirtual() && test_bit(sw, device->swBitmask)) {
+        if (device && device->hasValidFd() && test_bit(sw, device->swBitmask)) {
             uint8_t swState[sizeof_bit_array(SW_MAX + 1)];
             memset(swState, 0, sizeof(swState));
             if (ioctl(device->fd, EVIOCGSW(sizeof(swState)), swState) >= 0) {
@@ -395,7 +415,7 @@
         AutoMutex _l(mLock);
 
         Device* device = getDeviceLocked(deviceId);
-        if (device && !device->isVirtual() && test_bit(axis, device->absBitmask)) {
+        if (device && device->hasValidFd() && test_bit(axis, device->absBitmask)) {
             struct input_absinfo info;
             if(ioctl(device->fd, EVIOCGABS(axis), &info)) {
                 ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d",
@@ -532,7 +552,7 @@
 
 void EventHub::setLedStateLocked(Device* device, int32_t led, bool on) {
     int32_t sc;
-    if (device && !device->isVirtual() && mapLed(device, led, &sc) != NAME_NOT_FOUND) {
+    if (device && device->hasValidFd() && mapLed(device, led, &sc) != NAME_NOT_FOUND) {
         struct input_event ev;
         ev.time.tv_sec = 0;
         ev.time.tv_usec = 0;
@@ -636,7 +656,7 @@
 void EventHub::vibrate(int32_t deviceId, nsecs_t duration) {
     AutoMutex _l(mLock);
     Device* device = getDeviceLocked(deviceId);
-    if (device && !device->isVirtual()) {
+    if (device && device->hasValidFd()) {
         ff_effect effect;
         memset(&effect, 0, sizeof(effect));
         effect.type = FF_RUMBLE;
@@ -670,7 +690,7 @@
 void EventHub::cancelVibrate(int32_t deviceId) {
     AutoMutex _l(mLock);
     Device* device = getDeviceLocked(deviceId);
-    if (device && !device->isVirtual()) {
+    if (device && device->hasValidFd()) {
         if (device->ffEffectPlaying) {
             device->ffEffectPlaying = false;
 
@@ -1065,12 +1085,37 @@
         AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE,
 };
 
+status_t EventHub::registerDeviceForEpollLocked(Device* device) {
+    struct epoll_event eventItem;
+    memset(&eventItem, 0, sizeof(eventItem));
+    eventItem.events = EPOLLIN;
+    if (mUsingEpollWakeup) {
+        eventItem.events |= EPOLLWAKEUP;
+    }
+    eventItem.data.u32 = device->id;
+    if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, device->fd, &eventItem)) {
+        ALOGE("Could not add device fd to epoll instance.  errno=%d", errno);
+        return -errno;
+    }
+    return OK;
+}
+
+status_t EventHub::unregisterDeviceFromEpollLocked(Device* device) {
+    if (device->hasValidFd()) {
+        if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, device->fd, NULL)) {
+            ALOGW("Could not remove device fd from epoll instance.  errno=%d", errno);
+            return -errno;
+        }
+    }
+    return OK;
+}
+
 status_t EventHub::openDeviceLocked(const char *devicePath) {
     char buffer[80];
 
     ALOGV("Opening device: %s", devicePath);
 
-    int fd = open(devicePath, O_RDWR | O_CLOEXEC);
+    int fd = open(devicePath, O_RDWR | O_CLOEXEC | O_NONBLOCK);
     if(fd < 0) {
         ALOGE("could not open %s, %s\n", devicePath, strerror(errno));
         return -1;
@@ -1135,13 +1180,6 @@
     // Fill in the descriptor.
     assignDescriptorLocked(identifier);
 
-    // Make file descriptor non-blocking for use with poll().
-    if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
-        ALOGE("Error %d making device file descriptor non-blocking.", errno);
-        close(fd);
-        return -1;
-    }
-
     // Allocate device.  (The device object takes ownership of the fd at this point.)
     int32_t deviceId = mNextDeviceId++;
     Device* device = new Device(fd, deviceId, String8(devicePath), identifier);
@@ -1303,12 +1341,6 @@
                 break;
             }
         }
-
-        // Disable kernel key repeat since we handle it ourselves
-        unsigned int repeatRate[] = {0,0};
-        if (ioctl(fd, EVIOCSREP, repeatRate)) {
-            ALOGW("Unable to disable kernel key repeat for %s: %s", devicePath, strerror(errno));
-        }
     }
 
     // If the device isn't recognized as something we handle, don't monitor it.
@@ -1332,23 +1364,41 @@
     if (device->classes & (INPUT_DEVICE_CLASS_JOYSTICK | INPUT_DEVICE_CLASS_DPAD)
             && device->classes & INPUT_DEVICE_CLASS_GAMEPAD) {
         device->controllerNumber = getNextControllerNumberLocked(device);
-        setLedForController(device);
+        setLedForControllerLocked(device);
     }
 
-    // Register with epoll.
-    struct epoll_event eventItem;
-    memset(&eventItem, 0, sizeof(eventItem));
-    eventItem.events = EPOLLIN;
-    if (mUsingEpollWakeup) {
-        eventItem.events |= EPOLLWAKEUP;
-    }
-    eventItem.data.u32 = deviceId;
-    if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
-        ALOGE("Could not add device fd to epoll instance.  errno=%d", errno);
+
+    if (registerDeviceForEpollLocked(device) != OK) {
         delete device;
         return -1;
     }
 
+    configureFd(device);
+
+    ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
+            "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, ",
+         deviceId, fd, devicePath, device->identifier.name.string(),
+         device->classes,
+         device->configurationFile.string(),
+         device->keyMap.keyLayoutFile.string(),
+         device->keyMap.keyCharacterMapFile.string(),
+         toString(mBuiltInKeyboardId == deviceId));
+
+    addDeviceLocked(device);
+    return OK;
+}
+
+void EventHub::configureFd(Device* device) {
+    // Set fd parameters with ioctl, such as key repeat, suspend block, and clock type
+    if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) {
+        // Disable kernel key repeat since we handle it ourselves
+        unsigned int repeatRate[] = {0, 0};
+        if (ioctl(device->fd, EVIOCSREP, repeatRate)) {
+            ALOGW("Unable to disable kernel key repeat for %s: %s",
+                  device->path.string(), strerror(errno));
+        }
+    }
+
     String8 wakeMechanism("EPOLLWAKEUP");
     if (!mUsingEpollWakeup) {
 #ifndef EVIOCSSUSPENDBLOCK
@@ -1357,44 +1407,67 @@
         // this feature, we need to be prepared to define the ioctl ourselves.
 #define EVIOCSSUSPENDBLOCK _IOW('E', 0x91, int)
 #endif
-        if (ioctl(fd, EVIOCSSUSPENDBLOCK, 1)) {
+        if (ioctl(device->fd, EVIOCSSUSPENDBLOCK, 1)) {
             wakeMechanism = "<none>";
         } else {
             wakeMechanism = "EVIOCSSUSPENDBLOCK";
         }
     }
-
     // Tell the kernel that we want to use the monotonic clock for reporting timestamps
     // associated with input events.  This is important because the input system
     // uses the timestamps extensively and assumes they were recorded using the monotonic
     // clock.
-    //
-    // In older kernel, before Linux 3.4, there was no way to tell the kernel which
-    // clock to use to input event timestamps.  The standard kernel behavior was to
-    // record a real time timestamp, which isn't what we want.  Android kernels therefore
-    // contained a patch to the evdev_event() function in drivers/input/evdev.c to
-    // replace the call to do_gettimeofday() with ktime_get_ts() to cause the monotonic
-    // clock to be used instead of the real time clock.
-    //
-    // As of Linux 3.4, there is a new EVIOCSCLOCKID ioctl to set the desired clock.
-    // Therefore, we no longer require the Android-specific kernel patch described above
-    // as long as we make sure to set select the monotonic clock.  We do that here.
     int clockId = CLOCK_MONOTONIC;
-    bool usingClockIoctl = !ioctl(fd, EVIOCSCLOCKID, &clockId);
+    bool usingClockIoctl = !ioctl(device->fd, EVIOCSCLOCKID, &clockId);
+    ALOGI("wakeMechanism=%s, usingClockIoctl=%s", wakeMechanism.string(),
+          toString(usingClockIoctl));
+}
 
-    ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
-            "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, "
-            "wakeMechanism=%s, usingClockIoctl=%s",
-         deviceId, fd, devicePath, device->identifier.name.string(),
-         device->classes,
-         device->configurationFile.string(),
-         device->keyMap.keyLayoutFile.string(),
-         device->keyMap.keyCharacterMapFile.string(),
-         toString(mBuiltInKeyboardId == deviceId),
-         wakeMechanism.string(), toString(usingClockIoctl));
+bool EventHub::isDeviceEnabled(int32_t deviceId) {
+    AutoMutex _l(mLock);
+    Device* device = getDeviceLocked(deviceId);
+    if (device == NULL) {
+        ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__);
+        return false;
+    }
+    return device->enabled;
+}
 
-    addDeviceLocked(device);
-    return 0;
+status_t EventHub::enableDevice(int32_t deviceId) {
+    AutoMutex _l(mLock);
+    Device* device = getDeviceLocked(deviceId);
+    if (device == NULL) {
+        ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__);
+        return BAD_VALUE;
+    }
+    if (device->enabled) {
+        ALOGW("Duplicate call to %s, input device %" PRId32 " already enabled", __func__, deviceId);
+        return OK;
+    }
+    status_t result = device->enable();
+    if (result != OK) {
+        ALOGE("Failed to enable device %" PRId32, deviceId);
+        return result;
+    }
+
+    configureFd(device);
+
+    return registerDeviceForEpollLocked(device);
+}
+
+status_t EventHub::disableDevice(int32_t deviceId) {
+    AutoMutex _l(mLock);
+    Device* device = getDeviceLocked(deviceId);
+    if (device == NULL) {
+        ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__);
+        return BAD_VALUE;
+    }
+    if (!device->enabled) {
+        ALOGW("Duplicate call to %s, input device already disabled", __func__);
+        return OK;
+    }
+    unregisterDeviceFromEpollLocked(device);
+    return device->disable();
 }
 
 void EventHub::createVirtualKeyboardLocked() {
@@ -1490,7 +1563,7 @@
     mControllerNumbers.clearBit(static_cast<uint32_t>(num - 1));
 }
 
-void EventHub::setLedForController(Device* device) {
+void EventHub::setLedForControllerLocked(Device* device) {
     for (int i = 0; i < MAX_CONTROLLER_LEDS; i++) {
         setLedStateLocked(device, ALED_CONTROLLER_1 + i, device->controllerNumber == i + 1);
     }
@@ -1500,7 +1573,7 @@
     if (!device->keyMap.haveKeyLayout()) {
         return false;
     }
-    
+
     Vector<int32_t> scanCodes;
     device->keyMap.keyLayoutMap->findScanCodesForKey(keycode, &scanCodes);
     const size_t N = scanCodes.size();
@@ -1510,7 +1583,7 @@
             return true;
         }
     }
-    
+
     return false;
 }
 
@@ -1556,11 +1629,7 @@
         mBuiltInKeyboardId = NO_BUILT_IN_KEYBOARD;
     }
 
-    if (!device->isVirtual()) {
-        if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, device->fd, NULL)) {
-            ALOGW("Could not remove device fd from epoll instance.  errno=%d", errno);
-        }
-    }
+    unregisterDeviceFromEpollLocked(device);
 
     releaseControllerNumberLocked(device);
 
@@ -1691,6 +1760,7 @@
             }
             dump.appendFormat(INDENT3 "Classes: 0x%08x\n", device->classes);
             dump.appendFormat(INDENT3 "Path: %s\n", device->path.string());
+            dump.appendFormat(INDENT3 "Enabled: %s\n", toString(device->enabled));
             dump.appendFormat(INDENT3 "Descriptor: %s\n", device->identifier.descriptor.string());
             dump.appendFormat(INDENT3 "Location: %s\n", device->identifier.location.string());
             dump.appendFormat(INDENT3 "ControllerNumber: %d\n", device->controllerNumber);
diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h
index 6869253..727b73a 100644
--- a/services/inputflinger/EventHub.h
+++ b/services/inputflinger/EventHub.h
@@ -25,9 +25,8 @@
 #include <input/KeyCharacterMap.h>
 #include <input/VirtualKeyMap.h>
 #include <utils/String8.h>
-#include <utils/threads.h>
+#include <utils/Mutex.h>
 #include <utils/Log.h>
-#include <utils/threads.h>
 #include <utils/List.h>
 #include <utils/Errors.h>
 #include <utils/PropertyMap.h>
@@ -267,6 +266,15 @@
 
     /* Called by the heatbeat to ensures that the reader has not deadlocked. */
     virtual void monitor() = 0;
+
+    /* Return true if the device is enabled. */
+    virtual bool isDeviceEnabled(int32_t deviceId) = 0;
+
+    /* Enable an input device */
+    virtual status_t enableDevice(int32_t deviceId) = 0;
+
+    /* Disable an input device. Closes file descriptor to that device. */
+    virtual status_t disableDevice(int32_t deviceId) = 0;
 };
 
 class EventHub : public EventHubInterface
@@ -335,7 +343,7 @@
     struct Device {
         Device* next;
 
-        int fd; // may be -1 if device is virtual
+        int fd; // may be -1 if device is closed
         const int32_t id;
         const String8 path;
         const InputDeviceIdentifier identifier;
@@ -371,7 +379,11 @@
 
         void close();
 
-        inline bool isVirtual() const { return fd < 0; }
+        bool enabled; // initially true
+        status_t enable();
+        status_t disable();
+        bool hasValidFd();
+        const bool isVirtual; // set if fd < 0 is passed to constructor
 
         const sp<KeyCharacterMap>& getKeyCharacterMap() const {
             if (combinedKeyMap != NULL) {
@@ -390,6 +402,14 @@
     void closeDeviceLocked(Device* device);
     void closeAllDevicesLocked();
 
+    void configureFd(Device* device);
+
+    bool isDeviceEnabled(int32_t deviceId);
+    status_t enableDevice(int32_t deviceId);
+    status_t disableDevice(int32_t deviceId);
+    status_t registerDeviceForEpollLocked(Device* device);
+    status_t unregisterDeviceFromEpollLocked(Device* device);
+
     status_t scanDirLocked(const char *dirname);
     void scanDevicesLocked();
     status_t readNotifyLocked();
@@ -409,7 +429,7 @@
 
     int32_t getNextControllerNumberLocked(Device* device);
     void releaseControllerNumberLocked(Device* device);
-    void setLedForController(Device* device);
+    void setLedForControllerLocked(Device* device);
 
     status_t mapLed(Device* device, int32_t led, int32_t* outScanCode) const;
     void setLedStateLocked(Device* device, int32_t led, bool on);
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 2efb340..69067d2 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -869,10 +869,7 @@
         return true;
     }
 
-    // TODO: support sending secondary display events to input monitors
-    if (isMainDisplay(entry->displayId)) {
-        addMonitoringTargetsLocked(inputTargets);
-    }
+    addMonitoringTargetsLocked(inputTargets);
 
     // Dispatch the motion.
     if (conflictingPointerActions) {
@@ -2026,7 +2023,7 @@
 
             // Publish the motion event.
             status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
-                    motionEntry->deviceId, motionEntry->source,
+                    motionEntry->deviceId, motionEntry->source, motionEntry->displayId,
                     dispatchEntry->resolvedAction, motionEntry->actionButton,
                     dispatchEntry->resolvedFlags, motionEntry->edgeFlags,
                     motionEntry->metaState, motionEntry->buttonState,
@@ -2600,8 +2597,9 @@
         uint32_t policyFlags) {
 #if DEBUG_INBOUND_EVENT_DETAILS
     ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, "
-            "syncMode=%d, timeoutMillis=%d, policyFlags=0x%08x",
-            event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis, policyFlags);
+            "syncMode=%d, timeoutMillis=%d, policyFlags=0x%08x, displayId=%d",
+            event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis, policyFlags,
+            displayId);
 #endif
 
     nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis);
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 73255dd..cc81a29 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -835,6 +835,18 @@
     }
 }
 
+bool InputReader::isInputDeviceEnabled(int32_t deviceId) {
+    AutoMutex _l(mLock);
+
+    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
+    if (deviceIndex >= 0) {
+        InputDevice* device = mDevices.valueAt(deviceIndex);
+        return device->isEnabled();
+    }
+    ALOGW("Ignoring invalid device id %" PRId32 ".", deviceId);
+    return false;
+}
+
 void InputReader::dump(String8& dump) {
     AutoMutex _l(mLock);
 
@@ -1011,6 +1023,26 @@
     mMappers.clear();
 }
 
+bool InputDevice::isEnabled() {
+    return getEventHub()->isDeviceEnabled(mId);
+}
+
+void InputDevice::setEnabled(bool enabled, nsecs_t when) {
+    if (isEnabled() == enabled) {
+        return;
+    }
+
+    if (enabled) {
+        getEventHub()->enableDevice(mId);
+        reset(when);
+    } else {
+        reset(when);
+        getEventHub()->disableDevice(mId);
+    }
+    // Must change generation to flag this device as changed
+    bumpGeneration();
+}
+
 void InputDevice::dump(String8& dump) {
     InputDeviceInfo deviceInfo;
     getDeviceInfo(& deviceInfo);
@@ -1082,6 +1114,12 @@
             }
         }
 
+        if (!changes || (changes & InputReaderConfiguration::CHANGE_ENABLED_STATE)) {
+            ssize_t index = config->disabledDevices.indexOf(mId);
+            bool enabled = index < 0;
+            setEnabled(enabled, when);
+        }
+
         size_t numMappers = mMappers.size();
         for (size_t i = 0; i < numMappers; i++) {
             InputMapper* mapper = mMappers[i];
@@ -2291,6 +2329,35 @@
         || (scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI);
 }
 
+bool KeyboardInputMapper::isMediaKey(int32_t keyCode) {
+    switch (keyCode) {
+    case AKEYCODE_MEDIA_PLAY:
+    case AKEYCODE_MEDIA_PAUSE:
+    case AKEYCODE_MEDIA_PLAY_PAUSE:
+    case AKEYCODE_MUTE:
+    case AKEYCODE_HEADSETHOOK:
+    case AKEYCODE_MEDIA_STOP:
+    case AKEYCODE_MEDIA_NEXT:
+    case AKEYCODE_MEDIA_PREVIOUS:
+    case AKEYCODE_MEDIA_REWIND:
+    case AKEYCODE_MEDIA_RECORD:
+    case AKEYCODE_MEDIA_FAST_FORWARD:
+    case AKEYCODE_MEDIA_SKIP_FORWARD:
+    case AKEYCODE_MEDIA_SKIP_BACKWARD:
+    case AKEYCODE_MEDIA_STEP_FORWARD:
+    case AKEYCODE_MEDIA_STEP_BACKWARD:
+    case AKEYCODE_MEDIA_AUDIO_TRACK:
+    case AKEYCODE_VOLUME_UP:
+    case AKEYCODE_VOLUME_DOWN:
+    case AKEYCODE_VOLUME_MUTE:
+    case AKEYCODE_TV_AUDIO_DESCRIPTION:
+    case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP:
+    case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN:
+        return true;
+    }
+    return false;
+}
+
 void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode,
         int32_t usageCode) {
     int32_t keyCode;
@@ -2364,7 +2431,7 @@
     // For internal keyboards, the key layout file should specify the policy flags for
     // each wake key individually.
     // TODO: Use the input device configuration to control this behavior more finely.
-    if (down && getDevice()->isExternal()) {
+    if (down && getDevice()->isExternal() && !isMediaKey(keyCode)) {
         policyFlags |= POLICY_FLAG_WAKE;
     }
 
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index edb6fcc..c4f786a 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -27,11 +27,14 @@
 #include <input/VelocityTracker.h>
 #include <ui/DisplayInfo.h>
 #include <utils/KeyedVector.h>
-#include <utils/threads.h>
+#include <utils/Condition.h>
+#include <utils/Thread.h>
+#include <utils/Mutex.h>
 #include <utils/Timers.h>
 #include <utils/RefBase.h>
 #include <utils/String8.h>
 #include <utils/BitSet.h>
+#include <utils/SortedVector.h>
 
 #include <stddef.h>
 #include <unistd.h>
@@ -84,6 +87,9 @@
         // The pointer capture mode has changed.
         CHANGE_POINTER_CAPTURE = 1 << 8,
 
+        // The set of disabled input devices (disabledDevices) has changed.
+        CHANGE_ENABLED_STATE = 1 << 9,
+
         // All devices must be reopened.
         CHANGE_MUST_REOPEN = 1 << 31,
     };
@@ -174,6 +180,9 @@
     // True if pointer capture is enabled.
     bool pointerCapture;
 
+    // The set of currently disabled input devices.
+    SortedVector<int32_t> disabledDevices;
+
     InputReaderConfiguration() :
             virtualKeyQuietTime(0),
             pointerVelocityControlParameters(1.0f, 500.0f, 3000.0f, 3.0f),
@@ -288,6 +297,9 @@
     /* Called by the heatbeat to ensures that the reader has not deadlocked. */
     virtual void monitor() = 0;
 
+    /* Returns true if the input device is enabled. */
+    virtual bool isInputDeviceEnabled(int32_t deviceId) = 0;
+
     /* Runs a single iteration of the processing loop.
      * Nominally reads and processes one incoming message from the EventHub.
      *
@@ -407,6 +419,8 @@
 
     virtual void getInputDevices(Vector<InputDeviceInfo>& outInputDevices);
 
+    virtual bool isInputDeviceEnabled(int32_t deviceId);
+
     virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask,
             int32_t scanCode);
     virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask,
@@ -552,6 +566,9 @@
 
     inline bool isIgnored() { return mMappers.isEmpty(); }
 
+    bool isEnabled();
+    void setEnabled(bool enabled, nsecs_t when);
+
     void dump(String8& dump);
     void addMapper(InputMapper* mapper);
     void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
@@ -1111,6 +1128,7 @@
     void dumpParameters(String8& dump);
 
     bool isKeyboardOrGamepadKey(int32_t scanCode);
+    bool isMediaKey(int32_t keyCode);
 
     void processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode);
 
diff --git a/services/inputflinger/InputWindow.cpp b/services/inputflinger/InputWindow.cpp
index 5e82d75..b54752b 100644
--- a/services/inputflinger/InputWindow.cpp
+++ b/services/inputflinger/InputWindow.cpp
@@ -46,8 +46,10 @@
             || layoutParamsType == TYPE_MAGNIFICATION_OVERLAY
             || layoutParamsType == TYPE_STATUS_BAR
             || layoutParamsType == TYPE_NAVIGATION_BAR
+            || layoutParamsType == TYPE_NAVIGATION_BAR_PANEL
             || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY
-            || layoutParamsType == TYPE_DOCK_DIVIDER;
+            || layoutParamsType == TYPE_DOCK_DIVIDER
+            || layoutParamsType == TYPE_ACCESSIBILITY_OVERLAY;
 }
 
 bool InputWindowInfo::supportsSplitTouch() const {
diff --git a/services/inputflinger/InputWindow.h b/services/inputflinger/InputWindow.h
index feca6cf..610290b 100644
--- a/services/inputflinger/InputWindow.h
+++ b/services/inputflinger/InputWindow.h
@@ -101,7 +101,9 @@
         TYPE_NAVIGATION_BAR     = FIRST_SYSTEM_WINDOW+19,
         TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20,
         TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21,
-        TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+22,
+        TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24,
+        TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27,
+        TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32,
         TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW+34,
         LAST_SYSTEM_WINDOW      = 2999,
     };
diff --git a/services/inputflinger/host/Android.bp b/services/inputflinger/host/Android.bp
new file mode 100644
index 0000000..b8e9bce
--- /dev/null
+++ b/services/inputflinger/host/Android.bp
@@ -0,0 +1,57 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+    name: "libinputflingerhost",
+
+    srcs: [
+        "InputFlinger.cpp",
+        "InputDriver.cpp",
+        "InputHost.cpp",
+    ],
+
+    shared_libs: [
+        "libbinder",
+        "libcrypto",
+        "libcutils",
+        "libinput",
+        "liblog",
+        "libutils",
+        "libhardware",
+    ],
+
+    cflags: [
+        "-Wno-unused-parameter",
+        // TODO: Move inputflinger to its own process and mark it hidden
+        //-fvisibility=hidden
+    ],
+
+    export_include_dirs: ["."],
+}
+
+//#######################################################################
+// build input flinger executable
+cc_binary {
+    name: "inputflinger",
+
+    srcs: ["main.cpp"],
+
+    shared_libs: [
+        "libbinder",
+        "libinputflingerhost",
+        "libutils",
+    ],
+
+    init_rc: ["inputflinger.rc"],
+}
diff --git a/services/inputflinger/host/Android.mk b/services/inputflinger/host/Android.mk
deleted file mode 100644
index 0a7fc27..0000000
--- a/services/inputflinger/host/Android.mk
+++ /dev/null
@@ -1,63 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_CLANG := true
-
-LOCAL_SRC_FILES:= \
-    InputFlinger.cpp \
-    InputDriver.cpp \
-    InputHost.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-    libbinder \
-    libcrypto \
-    libcutils \
-    libinput \
-    liblog \
-    libutils \
-    libhardware
-
-
-# TODO: Move inputflinger to its own process and mark it hidden
-#LOCAL_CFLAGS += -fvisibility=hidden
-
-LOCAL_CFLAGS += -Wno-unused-parameter
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
-
-LOCAL_MODULE := libinputflingerhost
-
-include $(BUILD_SHARED_LIBRARY)
-
-########################################################################
-# build input flinger executable
-include $(CLEAR_VARS)
-
-LOCAL_CLANG := true
-
-LOCAL_SRC_FILES:= \
-	main.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	libbinder \
-	libinputflingerhost \
-	libutils
-
-LOCAL_MODULE := inputflinger
-LOCAL_INIT_RC := inputflinger.rc
-
-include $(BUILD_EXECUTABLE)
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
new file mode 100644
index 0000000..29d93f0
--- /dev/null
+++ b/services/inputflinger/tests/Android.bp
@@ -0,0 +1,23 @@
+// Build the unit tests.
+
+cc_test {
+    name: "inputflinger_tests",
+    srcs: [
+        "InputReader_test.cpp",
+        "InputDispatcher_test.cpp",
+    ],
+    test_per_src: true,
+    cflags: ["-Wno-unused-parameter"],
+    shared_libs = [
+        "libcutils",
+        "liblog",
+        "libutils",
+        "libhardware",
+        "libhardware_legacy",
+        "libui",
+        "libskia",
+        "libinput",
+        "libinputflinger",
+        "libinputservice",
+    ],
+}
diff --git a/services/inputflinger/tests/Android.mk b/services/inputflinger/tests/Android.mk
deleted file mode 100644
index 4c43392..0000000
--- a/services/inputflinger/tests/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-# Build the unit tests.
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# Build the unit tests.
-test_src_files := \
-    InputReader_test.cpp \
-    InputDispatcher_test.cpp
-
-shared_libraries := \
-    libcutils \
-    liblog \
-    libutils \
-    libhardware \
-    libhardware_legacy \
-    libui \
-    libskia \
-    libinput \
-    libinputflinger \
-    libinputservice
-
-c_includes := \
-    external/skia/include/core
-
-
-module_tags := tests
-
-$(foreach file,$(test_src_files), \
-    $(eval include $(CLEAR_VARS)) \
-    $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
-    $(eval LOCAL_C_INCLUDES := $(c_includes)) \
-    $(eval LOCAL_CFLAGS += -Wno-unused-parameter) \
-    $(eval LOCAL_SRC_FILES := $(file)) \
-    $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
-    $(eval LOCAL_MODULE_TAGS := $(module_tags)) \
-    $(eval include $(BUILD_NATIVE_TEST)) \
-)
-
-# Build the manual test programs.
-include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index dcfe114..76291a5 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -16,6 +16,7 @@
 
 #include "../InputReader.h"
 
+#include <inttypes.h>
 #include <utils/List.h>
 #include <gtest/gtest.h>
 #include <math.h>
@@ -159,6 +160,22 @@
         mConfig.excludedDeviceNames.push(deviceName);
     }
 
+    void addDisabledDevice(int32_t deviceId) {
+        ssize_t index = mConfig.disabledDevices.indexOf(deviceId);
+        bool currentlyEnabled = index < 0;
+        if (currentlyEnabled) {
+            mConfig.disabledDevices.add(deviceId);
+        }
+    }
+
+    void removeDisabledDevice(int32_t deviceId) {
+        ssize_t index = mConfig.disabledDevices.indexOf(deviceId);
+        bool currentlyEnabled = index < 0;
+        if (!currentlyEnabled) {
+            mConfig.disabledDevices.remove(deviceId);
+        }
+    }
+
     void setPointerController(int32_t deviceId, const sp<FakePointerController>& controller) {
         mPointerControllers.add(deviceId, controller);
     }
@@ -255,6 +272,11 @@
         mNotifyConfigurationChangedArgsQueue.erase(mNotifyConfigurationChangedArgsQueue.begin());
     }
 
+    void assertNotifyConfigurationChangedWasNotCalled() {
+        ASSERT_TRUE(mNotifyConfigurationChangedArgsQueue.empty())
+                << "Expected notifyConfigurationChanged() to not have been called.";
+    }
+
     void assertNotifyDeviceResetWasCalled(
             NotifyDeviceResetArgs* outEventArgs = NULL) {
         ASSERT_FALSE(mNotifyDeviceResetArgsQueue.empty())
@@ -265,6 +287,11 @@
         mNotifyDeviceResetArgsQueue.erase(mNotifyDeviceResetArgsQueue.begin());
     }
 
+    void assertNotifyDeviceResetWasNotCalled() {
+        ASSERT_TRUE(mNotifyDeviceResetArgsQueue.empty())
+                << "Expected notifyDeviceReset() to not have been called.";
+    }
+
     void assertNotifyKeyWasCalled(NotifyKeyArgs* outEventArgs = NULL) {
         ASSERT_FALSE(mNotifyKeyArgsQueue.empty())
                 << "Expected notifyKey() to have been called.";
@@ -347,9 +374,20 @@
         KeyedVector<int32_t, KeyInfo> keysByUsageCode;
         KeyedVector<int32_t, bool> leds;
         Vector<VirtualKeyDefinition> virtualKeys;
+        bool enabled;
+
+        status_t enable() {
+            enabled = true;
+            return OK;
+        }
+
+        status_t disable() {
+            enabled = false;
+            return OK;
+        }
 
         explicit Device(uint32_t classes) :
-                classes(classes) {
+                classes(classes), enabled(true) {
         }
     };
 
@@ -382,6 +420,43 @@
         enqueueEvent(ARBITRARY_TIME, deviceId, EventHubInterface::DEVICE_REMOVED, 0, 0);
     }
 
+    bool isDeviceEnabled(int32_t deviceId) {
+        Device* device = getDevice(deviceId);
+        if (device == NULL) {
+            ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__);
+            return false;
+        }
+        return device->enabled;
+    }
+
+    status_t enableDevice(int32_t deviceId) {
+        status_t result;
+        Device* device = getDevice(deviceId);
+        if (device == NULL) {
+            ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__);
+            return BAD_VALUE;
+        }
+        if (device->enabled) {
+            ALOGW("Duplicate call to %s, device %" PRId32 " already enabled", __func__, deviceId);
+            return OK;
+        }
+        result = device->enable();
+        return result;
+    }
+
+    status_t disableDevice(int32_t deviceId) {
+        Device* device = getDevice(deviceId);
+        if (device == NULL) {
+            ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__);
+            return BAD_VALUE;
+        }
+        if (!device->enabled) {
+            ALOGW("Duplicate call to %s, device %" PRId32 " already disabled", __func__, deviceId);
+            return OK;
+        }
+        return device->disable();
+    }
+
     void finishDeviceScan() {
         enqueueEvent(ARBITRARY_TIME, 0, EventHubInterface::FINISHED_DEVICE_SCAN, 0, 0);
     }
@@ -1039,6 +1114,20 @@
         mFakeEventHub->assertQueueIsEmpty();
     }
 
+    void disableDevice(int32_t deviceId, InputDevice* device) {
+        mFakePolicy->addDisabledDevice(deviceId);
+        configureDevice(InputReaderConfiguration::CHANGE_ENABLED_STATE, device);
+    }
+
+    void enableDevice(int32_t deviceId, InputDevice* device) {
+        mFakePolicy->removeDisabledDevice(deviceId);
+        configureDevice(InputReaderConfiguration::CHANGE_ENABLED_STATE, device);
+    }
+
+    void configureDevice(uint32_t changes, InputDevice* device) {
+        device->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), changes);
+    }
+
     FakeInputMapper* addDeviceWithFakeInputMapper(int32_t deviceId, int32_t controllerNumber,
             const String8& name, uint32_t classes, uint32_t sources,
             const PropertyMap* configuration) {
@@ -1077,6 +1166,46 @@
     ASSERT_EQ(size_t(0), inputDevices[0].getMotionRanges().size());
 }
 
+TEST_F(InputReaderTest, WhenEnabledChanges_SendsDeviceResetNotification) {
+    constexpr int32_t deviceId = 1;
+    constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD;
+    InputDevice* device = mReader->newDevice(deviceId, 0, String8("fake"), deviceClass);
+    // Must add at least one mapper or the device will be ignored!
+    FakeInputMapper* mapper = new FakeInputMapper(device, AINPUT_SOURCE_KEYBOARD);
+    device->addMapper(mapper);
+    mReader->setNextDevice(device);
+    addDevice(deviceId, String8("fake"), deviceClass, NULL);
+
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyConfigurationChangedWasCalled(NULL));
+
+    NotifyDeviceResetArgs resetArgs;
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
+    ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime);
+    ASSERT_EQ(deviceId, resetArgs.deviceId);
+
+    ASSERT_EQ(device->isEnabled(), true);
+    disableDevice(deviceId, device);
+    mReader->loopOnce();
+
+    mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs);
+    ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime);
+    ASSERT_EQ(deviceId, resetArgs.deviceId);
+    ASSERT_EQ(device->isEnabled(), false);
+
+    disableDevice(deviceId, device);
+    mReader->loopOnce();
+    mFakeListener->assertNotifyDeviceResetWasNotCalled();
+    mFakeListener->assertNotifyConfigurationChangedWasNotCalled();
+    ASSERT_EQ(device->isEnabled(), false);
+
+    enableDevice(deviceId, device);
+    mReader->loopOnce();
+    mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs);
+    ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime);
+    ASSERT_EQ(deviceId, resetArgs.deviceId);
+    ASSERT_EQ(device->isEnabled(), true);
+}
+
 TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) {
     FakeInputMapper* mapper = NULL;
     ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
@@ -1274,6 +1403,10 @@
     ASSERT_EQ(DEVICE_CLASSES, mDevice->getClasses());
 }
 
+TEST_F(InputDeviceTest, WhenDeviceCreated_EnabledIsTrue) {
+    ASSERT_EQ(mDevice->isEnabled(), true);
+}
+
 TEST_F(InputDeviceTest, WhenNoMappersAreRegistered_DeviceIsIgnored) {
     // Configuration.
     InputReaderConfiguration config;
diff --git a/services/schedulerservice/Android.bp b/services/schedulerservice/Android.bp
index 1f1340c..ca91b8e 100644
--- a/services/schedulerservice/Android.bp
+++ b/services/schedulerservice/Android.bp
@@ -10,7 +10,6 @@
         "libmediautils",
         "liblog",
         "libutils",
-        "android.hidl.base@1.0",
         "android.frameworks.schedulerservice@1.0",
     ],
     header_libs: [
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index 8c2300e..8d381b1 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -1,3 +1,73 @@
 subdirs = [
     "hidl"
 ]
+cc_library_shared {
+    name: "libsensorservice",
+
+    srcs: [
+        "BatteryService.cpp",
+        "CorrectedGyroSensor.cpp",
+        "Fusion.cpp",
+        "GravitySensor.cpp",
+        "LinearAccelerationSensor.cpp",
+        "OrientationSensor.cpp",
+        "RecentEventLogger.cpp",
+        "RotationVectorSensor.cpp",
+        "SensorDevice.cpp",
+        "SensorDirectConnection.cpp",
+        "SensorEventConnection.cpp",
+        "SensorFusion.cpp",
+        "SensorInterface.cpp",
+        "SensorList.cpp",
+        "SensorRecord.cpp",
+        "SensorService.cpp",
+        "SensorServiceUtils.cpp",
+    ],
+
+    cflags: [
+        "-DLOG_TAG=\"SensorService\"",
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+        "-fvisibility=hidden"
+    ],
+
+    shared_libs: [
+        "libcutils",
+        "libhardware",
+        "libhardware_legacy",
+        "libutils",
+        "liblog",
+        "libbinder",
+        "libsensor",
+        "libcrypto",
+        "libbase",
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "android.hardware.sensors@1.0",
+    ],
+
+    static_libs: ["android.hardware.sensors@1.0-convert"],
+
+    // our public headers depend on libsensor
+    export_shared_lib_headers: ["libsensor"],
+}
+
+cc_binary {
+    name: "sensorservice",
+
+    srcs: ["main_sensorservice.cpp"],
+
+    shared_libs: [
+        "libsensorservice",
+        "libbinder",
+        "libutils",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
+}
diff --git a/services/sensorservice/Android.mk b/services/sensorservice/Android.mk
deleted file mode 100644
index cfb7231..0000000
--- a/services/sensorservice/Android.mk
+++ /dev/null
@@ -1,73 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-    BatteryService.cpp \
-    CorrectedGyroSensor.cpp \
-    Fusion.cpp \
-    GravitySensor.cpp \
-    LinearAccelerationSensor.cpp \
-    OrientationSensor.cpp \
-    RecentEventLogger.cpp \
-    RotationVectorSensor.cpp \
-    SensorDevice.cpp \
-    SensorDirectConnection.cpp \
-    SensorEventConnection.cpp \
-    SensorFusion.cpp \
-    SensorInterface.cpp \
-    SensorList.cpp \
-    SensorRecord.cpp \
-    SensorService.cpp \
-    SensorServiceUtils.cpp \
-
-LOCAL_CFLAGS:= -DLOG_TAG=\"SensorService\"
-
-LOCAL_CFLAGS += -Wall -Werror -Wextra
-
-LOCAL_CFLAGS += -fvisibility=hidden
-
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    libhardware \
-    libhardware_legacy \
-    libutils \
-    liblog \
-    libbinder \
-    libsensor \
-    libcrypto \
-    libbase \
-    libhidlbase \
-    libhidltransport \
-    libhwbinder \
-    android.hardware.sensors@1.0
-
-LOCAL_STATIC_LIBRARIES := \
-    android.hardware.sensors@1.0-convert
-
-# our public headers depend on libsensor
-LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := \
-    libsensor \
-
-LOCAL_MODULE:= libsensorservice
-
-include $(BUILD_SHARED_LIBRARY)
-
-#####################################################################
-# build executable
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-    main_sensorservice.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-    libsensorservice \
-    libbinder \
-    libutils
-
-LOCAL_CFLAGS := -Wall -Werror -Wextra
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE:= sensorservice
-
-include $(BUILD_EXECUTABLE)
diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp
index 870635b..538d728 100644
--- a/services/sensorservice/SensorDirectConnection.cpp
+++ b/services/sensorservice/SensorDirectConnection.cpp
@@ -27,12 +27,21 @@
         const String16& opPackageName)
         : mService(service), mUid(uid), mMem(*mem),
         mHalChannelHandle(halChannelHandle),
-        mOpPackageName(opPackageName) {
+        mOpPackageName(opPackageName), mDestroyed(false) {
     ALOGD_IF(DEBUG_CONNECTIONS, "Created SensorDirectConnection");
 }
 
 SensorService::SensorDirectConnection::~SensorDirectConnection() {
     ALOGD_IF(DEBUG_CONNECTIONS, "~SensorDirectConnection %p", this);
+    destroy();
+}
+
+void SensorService::SensorDirectConnection::destroy() {
+    Mutex::Autolock _l(mDestroyLock);
+    // destroy once only
+    if (mDestroyed) {
+        return;
+    }
 
     stopAll();
     mService->cleanupConnection(this);
@@ -40,6 +49,7 @@
         native_handle_close(mMem.handle);
         native_handle_delete(const_cast<struct native_handle*>(mMem.handle));
     }
+    mDestroyed = true;
 }
 
 void SensorService::SensorDirectConnection::onFirstRef() {
diff --git a/services/sensorservice/SensorDirectConnection.h b/services/sensorservice/SensorDirectConnection.h
index 27458d4..5c398a8 100644
--- a/services/sensorservice/SensorDirectConnection.h
+++ b/services/sensorservice/SensorDirectConnection.h
@@ -47,7 +47,7 @@
     // stop all active sensor report. if backupRecord is set to false,
     // those report can be recovered by recoverAll
     // called by SensorService when enter restricted mode
-    void stopAll(bool clearRecord = false);
+    void stopAll(bool backupRecord = false);
 
     // recover sensor reports previously stopped by stopAll(true)
     // called by SensorService when return to NORMAL mode.
@@ -63,7 +63,7 @@
     virtual status_t setEventRate(int handle, nsecs_t samplingPeriodNs);
     virtual status_t flush();
     virtual int32_t configureChannel(int handle, int rateLevel);
-
+    virtual void destroy();
 private:
     const sp<SensorService> mService;
     const uid_t mUid;
@@ -74,6 +74,9 @@
     mutable Mutex mConnectionLock;
     std::unordered_map<int, int> mActivated;
     std::unordered_map<int, int> mActivatedBackup;
+
+    mutable Mutex mDestroyLock;
+    bool mDestroyed;
 };
 
 } // namepsace android
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index fad046c..0a05dd1 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -32,7 +32,8 @@
         const String16& opPackageName)
     : mService(service), mUid(uid), mWakeLockRefCount(0), mHasLooperCallbacks(false),
       mDead(false), mDataInjectionMode(isDataInjectionMode), mEventCache(NULL),
-      mCacheSize(0), mMaxCacheSize(0), mPackageName(packageName), mOpPackageName(opPackageName) {
+      mCacheSize(0), mMaxCacheSize(0), mPackageName(packageName), mOpPackageName(opPackageName),
+      mDestroyed(false) {
     mChannel = new BitTube(mService->mSocketBufferSize);
 #if DEBUG_CONNECTIONS
     mEventsReceived = mEventsSentFromCache = mEventsSent = 0;
@@ -42,10 +43,22 @@
 
 SensorService::SensorEventConnection::~SensorEventConnection() {
     ALOGD_IF(DEBUG_CONNECTIONS, "~SensorEventConnection(%p)", this);
+    destroy();
+}
+
+void SensorService::SensorEventConnection::destroy() {
+    Mutex::Autolock _l(mDestroyLock);
+
+    // destroy once only
+    if (mDestroyed) {
+        return;
+    }
+
     mService->cleanupConnection(this);
     if (mEventCache != NULL) {
         delete mEventCache;
     }
+    mDestroyed = true;
 }
 
 void SensorService::SensorEventConnection::onFirstRef() {
@@ -477,7 +490,14 @@
     // separately before the next batch of events.
     for (int j = 0; j < numEventsDropped; ++j) {
         if (scratch[j].type == SENSOR_TYPE_META_DATA) {
-            FlushInfo& flushInfo = mSensorInfo.editValueFor(scratch[j].meta_data.sensor);
+            ssize_t index = mSensorInfo.indexOfKey(scratch[j].meta_data.sensor);
+            if (index < 0) {
+                ALOGW("%s: sensor 0x%x is not found in connection",
+                      __func__, scratch[j].meta_data.sensor);
+                continue;
+            }
+
+            FlushInfo& flushInfo = mSensorInfo.editValueAt(index);
             flushInfo.mPendingFlushEventsToSend++;
             ALOGD_IF(DEBUG_CONNECTIONS, "increment pendingFlushCount %d",
                      flushInfo.mPendingFlushEventsToSend);
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index c81e015..6f282cd 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -75,6 +75,7 @@
     virtual status_t setEventRate(int handle, nsecs_t samplingPeriodNs);
     virtual status_t flush();
     virtual int32_t configureChannel(int handle, int rateLevel);
+    virtual void destroy();
 
     // Count the number of flush complete events which are about to be dropped in the buffer.
     // Increment mPendingFlushEventsToSend in mSensorInfo. These flush complete events will be sent
@@ -164,6 +165,8 @@
     int mTotalAcksNeeded, mTotalAcksReceived;
 #endif
 
+    mutable Mutex mDestroyLock;
+    bool mDestroyed;
 };
 
 } // namepsace android
diff --git a/services/sensorservice/SensorList.cpp b/services/sensorservice/SensorList.cpp
index ab08cac..aa306d8 100644
--- a/services/sensorservice/SensorList.cpp
+++ b/services/sensorservice/SensorList.cpp
@@ -124,14 +124,15 @@
     forEachSensor([&result] (const Sensor& s) -> bool {
             result.appendFormat(
                     "%#010x) %-25s | %-15s | ver: %" PRId32 " | type: %20s(%" PRId32
-                        ") | perm: %s\n",
+                        ") | perm: %s | flags: 0x%08x\n",
                     s.getHandle(),
                     s.getName().string(),
                     s.getVendor().string(),
                     s.getVersion(),
                     s.getStringType().string(),
                     s.getType(),
-                    s.getRequiredPermission().size() ? s.getRequiredPermission().string() : "n/a");
+                    s.getRequiredPermission().size() ? s.getRequiredPermission().string() : "n/a",
+                    static_cast<int>(s.getFlags()));
 
             result.append("\t");
             const int reportingMode = s.getReportingMode();
@@ -173,9 +174,14 @@
                 result.appendFormat("non-wakeUp | ");
             }
 
+            if (s.isDataInjectionSupported()) {
+                result.appendFormat("data-injection, ");
+            }
+
             if (s.isDynamicSensor()) {
                 result.appendFormat("dynamic, ");
             }
+
             if (s.hasAdditionalInfo()) {
                 result.appendFormat("has-additional-info, ");
             }
@@ -190,7 +196,6 @@
                 if (s.isDirectChannelTypeSupported(SENSOR_DIRECT_MEM_TYPE_GRALLOC)) {
                     result.append("gralloc, ");
                 }
-                result.appendFormat("flag =0x%08x", static_cast<int>(s.getFlags()));
                 result.append("\n");
             }
             return true;
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index d60768c..62c2756 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -394,6 +394,7 @@
             }
         } else if (!mSensors.hasAnySensor()) {
             result.append("No Sensors on the device\n");
+            result.appendFormat("devInitCheck : %d\n", SensorDevice::getInstance().initCheck());
         } else {
             // Default dump the sensor list and debugging information.
             //
@@ -1032,17 +1033,16 @@
 }
 
 int SensorService::setOperationParameter(
-            int32_t type, const Vector<float> &floats, const Vector<int32_t> &ints) {
+            int32_t handle, int32_t type,
+            const Vector<float> &floats, const Vector<int32_t> &ints) {
     Mutex::Autolock _l(mLock);
 
-    // check permission
-    int32_t uid;
-    bool hasPermission = checkCallingPermission(sLocationHardwarePermission, nullptr, &uid);
-    if (!hasPermission || (uid != 1000 && uid != 0)) {
+    if (!checkCallingPermission(sLocationHardwarePermission, nullptr, nullptr)) {
         return PERMISSION_DENIED;
     }
 
     bool isFloat = true;
+    bool isCustom = false;
     size_t expectSize = INT32_MAX;
     switch (type) {
         case AINFO_LOCAL_GEOMAGNETIC_FIELD:
@@ -1060,7 +1060,21 @@
             expectSize = 1;
             break;
         default:
-            return BAD_VALUE;
+            // CUSTOM events must only contain float data; it may have variable size
+            if (type < AINFO_CUSTOM_START || type >= AINFO_DEBUGGING_START ||
+                    ints.size() ||
+                    sizeof(additional_info_event_t::data_float)/sizeof(float) < floats.size() ||
+                    handle < 0) {
+                return BAD_VALUE;
+            }
+            isFloat = true;
+            isCustom = true;
+            expectSize = floats.size();
+            break;
+    }
+
+    if (!isCustom && handle != -1) {
+        return BAD_VALUE;
     }
 
     // three events: first one is begin tag, last one is end tag, the one in the middle
@@ -1070,7 +1084,7 @@
     for (sensors_event_t* i = event; i < event + 3; i++) {
         *i = (sensors_event_t) {
             .version = sizeof(sensors_event_t),
-            .sensor = SENSORS_HANDLE_BASE - 1, // sensor that never exists
+            .sensor = handle,
             .type = SENSOR_TYPE_ADDITIONAL_INFO,
             .timestamp = timestamp++,
             .additional_info = (additional_info_event_t) {
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 2a9d6e8..3e18394 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -159,7 +159,7 @@
     virtual sp<ISensorEventConnection> createSensorDirectConnection(const String16& opPackageName,
             uint32_t size, int32_t type, int32_t format, const native_handle *resource);
     virtual int setOperationParameter(
-            int32_t type, const Vector<float> &floats, const Vector<int32_t> &ints);
+            int32_t handle, int32_t type, const Vector<float> &floats, const Vector<int32_t> &ints);
     virtual status_t dump(int fd, const Vector<String16>& args);
 
     String8 getSensorName(int handle) const;
diff --git a/services/sensorservice/hidl/Android.bp b/services/sensorservice/hidl/Android.bp
index 748dafc..8bbc4c5 100644
--- a/services/sensorservice/hidl/Android.bp
+++ b/services/sensorservice/hidl/Android.bp
@@ -18,7 +18,6 @@
         "libsensor",
         "android.frameworks.sensorservice@1.0",
         "android.hardware.sensors@1.0",
-        "android.hidl.base@1.0",
     ],
     static_libs: [
         "android.hardware.sensors@1.0-convert",
diff --git a/services/sensorservice/hidl/SensorManager.cpp b/services/sensorservice/hidl/SensorManager.cpp
index 25a3dc5..cf5ab05 100644
--- a/services/sensorservice/hidl/SensorManager.cpp
+++ b/services/sensorservice/hidl/SensorManager.cpp
@@ -24,7 +24,6 @@
 
 #include <sched.h>
 
-#include <thread>
 
 #include "EventQueue.h"
 #include "DirectReportChannel.h"
@@ -40,20 +39,24 @@
 using ::android::hardware::sensors::V1_0::SensorsEventFormatOffset;
 using ::android::hardware::hidl_vec;
 using ::android::hardware::Void;
-using ::android::sp;
 
 static const char* POLL_THREAD_NAME = "hidl_ssvc_poll";
 
 SensorManager::SensorManager(JavaVM* vm)
-        : mJavaVm(vm) {
+        : mLooper(new Looper(false /*allowNonCallbacks*/)), mStopThread(true), mJavaVm(vm) {
 }
 
 SensorManager::~SensorManager() {
     // Stops pollAll inside the thread.
-    std::unique_lock<std::mutex> lock(mLooperMutex);
+    std::lock_guard<std::mutex> lock(mThreadMutex);
+
+    mStopThread = true;
     if (mLooper != nullptr) {
         mLooper->wake();
     }
+    if (mPollThread.joinable()) {
+        mPollThread.join();
+    }
 }
 
 // Methods from ::android::frameworks::sensorservice::V1_0::ISensorManager follow.
@@ -128,12 +131,13 @@
 }
 
 /* One global looper for all event queues created from this SensorManager. */
-sp<::android::Looper> SensorManager::getLooper() {
-    std::unique_lock<std::mutex> lock(mLooperMutex);
-    if (mLooper == nullptr) {
-        std::condition_variable looperSet;
+sp<Looper> SensorManager::getLooper() {
+    std::lock_guard<std::mutex> lock(mThreadMutex);
 
-        std::thread{[&mutex = mLooperMutex, &looper = mLooper, &looperSet, javaVm = mJavaVm] {
+    if (!mPollThread.joinable()) {
+        // if thread not initialized, start thread
+        mStopThread = false;
+        std::thread pollThread{[&stopThread = mStopThread, looper = mLooper, javaVm = mJavaVm] {
 
             struct sched_param p = {0};
             p.sched_priority = 10;
@@ -142,16 +146,11 @@
                         << strerror(errno);
             }
 
-            std::unique_lock<std::mutex> lock(mutex);
-            if (looper != nullptr) {
-                LOG(INFO) << "Another thread has already set the looper, exiting this one.";
-                return;
-            }
-            looper = Looper::prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS /* opts */);
-            lock.unlock();
+            // set looper
+            Looper::setForThread(looper);
 
-            // Attach the thread to JavaVM so that pollAll do not crash if the event
-            // is from Java.
+            // Attach the thread to JavaVM so that pollAll do not crash if the thread
+            // eventually calls into Java.
             JavaVMAttachArgs args{
                 .version = JNI_VERSION_1_2,
                 .name = POLL_THREAD_NAME,
@@ -162,19 +161,30 @@
                 LOG(FATAL) << "Cannot attach SensorManager looper thread to Java VM.";
             }
 
-            looperSet.notify_one();
-            int pollResult = looper->pollAll(-1 /* timeout */);
-            if (pollResult != ALOOPER_POLL_WAKE) {
-                LOG(ERROR) << "Looper::pollAll returns unexpected " << pollResult;
+            LOG(INFO) << POLL_THREAD_NAME << " started.";
+            for (;;) {
+                int pollResult = looper->pollAll(-1 /* timeout */);
+                if (pollResult == Looper::POLL_WAKE) {
+                    if (stopThread == true) {
+                        LOG(INFO) << POLL_THREAD_NAME << ": requested to stop";
+                        break;
+                    } else {
+                        LOG(INFO) << POLL_THREAD_NAME << ": spurious wake up, back to work";
+                    }
+                } else {
+                    LOG(ERROR) << POLL_THREAD_NAME << ": Looper::pollAll returns unexpected "
+                               << pollResult;
+                    break;
+                }
             }
 
             if (javaVm->DetachCurrentThread() != JNI_OK) {
                 LOG(ERROR) << "Cannot detach SensorManager looper thread from Java VM.";
             }
 
-            LOG(INFO) << "Looper thread is terminated.";
-        }}.detach();
-        looperSet.wait(lock, [this]{ return this->mLooper != nullptr; });
+            LOG(INFO) << POLL_THREAD_NAME << " is terminated.";
+        }};
+        mPollThread = std::move(pollThread);
     }
     return mLooper;
 }
@@ -196,6 +206,12 @@
     }
 
     sp<::android::Looper> looper = getLooper();
+    if (looper == nullptr) {
+        LOG(ERROR) << "::android::SensorManager::createEventQueue cannot initialize looper";
+        _hidl_cb(nullptr, Result::UNKNOWN_ERROR);
+        return Void();
+    }
+
     sp<::android::SensorEventQueue> internalQueue = getInternalManager().createEventQueue();
     if (internalQueue == nullptr) {
         LOG(WARNING) << "::android::SensorManager::createEventQueue returns nullptr.";
diff --git a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
index e66c8e5..ddcee28 100644
--- a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
+++ b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
@@ -20,6 +20,7 @@
 #include <jni.h>
 
 #include <mutex>
+#include <thread>
 
 #include <android/frameworks/sensorservice/1.0/ISensorManager.h>
 #include <android/frameworks/sensorservice/1.0/types.h>
@@ -38,6 +39,7 @@
 using ::android::hardware::hidl_handle;
 using ::android::hardware::hidl_memory;
 using ::android::hardware::Return;
+using ::android::sp;
 
 struct SensorManager final : public ISensorManager {
 
@@ -54,13 +56,15 @@
 private:
     // Block until ::android::SensorManager is initialized.
     ::android::SensorManager& getInternalManager();
-    sp<::android::Looper> getLooper();
+    sp<Looper> getLooper();
 
     std::mutex mInternalManagerMutex;
     ::android::SensorManager* mInternalManager = nullptr; // does not own
+    sp<Looper> mLooper;
 
-    std::mutex mLooperMutex;
-    sp<::android::Looper> mLooper;
+    volatile bool mStopThread;
+    std::mutex mThreadMutex; //protects mPollThread
+    std::thread mPollThread;
 
     JavaVM* mJavaVm;
 };
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 95a522d..38529b6 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -9,7 +9,7 @@
     DisplayDevice.cpp \
     DispSync.cpp \
     EventControlThread.cpp \
-    StartBootAnimThread.cpp \
+    StartPropertySetThread.cpp \
     EventThread.cpp \
     FrameTracker.cpp \
     GpuService.cpp \
@@ -104,7 +104,7 @@
     libhidltransport \
     libhwbinder
 
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code -std=c++1z
 
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index bd9b8aa..ea04839 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -377,11 +377,16 @@
 DispSync::DispSync(const char* name) :
         mName(name),
         mRefreshSkipCount(0),
-        mThread(new DispSyncThread(name)),
-        mIgnorePresentFences(!SurfaceFlinger::hasSyncFramework){
+        mThread(new DispSyncThread(name)) {
+}
 
-    mPresentTimeOffset = SurfaceFlinger::dispSyncPresentTimeOffset;
+DispSync::~DispSync() {}
+
+void DispSync::init(bool hasSyncFramework, int64_t dispSyncPresentTimeOffset) {
+    mIgnorePresentFences = !hasSyncFramework;
+    mPresentTimeOffset = dispSyncPresentTimeOffset;
     mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
+
     // set DispSync to SCHED_FIFO to minimize jitter
     struct sched_param param = {0};
     param.sched_priority = 2;
@@ -389,7 +394,6 @@
         ALOGE("Couldn't set SCHED_FIFO for DispSyncThread");
     }
 
-
     reset();
     beginResync();
 
@@ -405,8 +409,6 @@
     }
 }
 
-DispSync::~DispSync() {}
-
 void DispSync::reset() {
     Mutex::Autolock lock(mMutex);
 
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index 82ae795..3c34fb0 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -55,6 +55,8 @@
     explicit DispSync(const char* name);
     ~DispSync();
 
+    void init(bool hasSyncFramework, int64_t dispSyncPresentTimeOffset);
+
     // reset clears the resync samples and error value.
     void reset();
 
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index b5ffc60..fc60002 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -121,7 +121,7 @@
     ANativeWindow* const window = mNativeWindow.get();
 
 #ifdef USE_HWC2
-    mActiveColorMode = static_cast<android_color_mode_t>(-1);
+    mActiveColorMode = HAL_COLOR_MODE_NATIVE;
     mDisplayHasWideColor = supportWideColor;
 #else
     (void) supportWideColor;
@@ -442,6 +442,11 @@
 android_color_mode_t DisplayDevice::getActiveColorMode() const {
     return mActiveColorMode;
 }
+
+void DisplayDevice::setCompositionDataSpace(android_dataspace dataspace) {
+    ANativeWindow* const window = mNativeWindow.get();
+    native_window_set_buffers_data_space(window, dataspace);
+}
 #endif
 
 // ----------------------------------------------------------------------------
@@ -610,23 +615,25 @@
 
 void DisplayDevice::dump(String8& result) const {
     const Transform& tr(mGlobalTransform);
-    result.appendFormat(
-        "+ DisplayDevice: %s\n"
-        "   type=%x, hwcId=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p, orient=%2d (type=%08x), "
-        "flips=%u, isSecure=%d, powerMode=%d, activeConfig=%d, numLayers=%zu\n"
-        "   v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], s:[%d,%d,%d,%d],"
-        "transform:[[%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f]]\n",
-        mDisplayName.string(), mType, mHwcDisplayId,
-        mLayerStack, mDisplayWidth, mDisplayHeight, mNativeWindow.get(),
-        mOrientation, tr.getType(), getPageFlipCount(),
-        mIsSecure, mPowerMode, mActiveConfig,
-        mVisibleLayersSortedByZ.size(),
-        mViewport.left, mViewport.top, mViewport.right, mViewport.bottom,
-        mFrame.left, mFrame.top, mFrame.right, mFrame.bottom,
-        mScissor.left, mScissor.top, mScissor.right, mScissor.bottom,
-        tr[0][0], tr[1][0], tr[2][0],
-        tr[0][1], tr[1][1], tr[2][1],
-        tr[0][2], tr[1][2], tr[2][2]);
+    EGLint redSize, greenSize, blueSize, alphaSize;
+    eglGetConfigAttrib(mDisplay, mConfig, EGL_RED_SIZE, &redSize);
+    eglGetConfigAttrib(mDisplay, mConfig, EGL_GREEN_SIZE, &greenSize);
+    eglGetConfigAttrib(mDisplay, mConfig, EGL_BLUE_SIZE, &blueSize);
+    eglGetConfigAttrib(mDisplay, mConfig, EGL_ALPHA_SIZE, &alphaSize);
+    result.appendFormat("+ DisplayDevice: %s\n", mDisplayName.string());
+    result.appendFormat("   type=%x, hwcId=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p "
+                        "(%d:%d:%d:%d), orient=%2d (type=%08x), "
+                        "flips=%u, isSecure=%d, powerMode=%d, activeConfig=%d, numLayers=%zu\n",
+                        mType, mHwcDisplayId, mLayerStack, mDisplayWidth, mDisplayHeight,
+                        mNativeWindow.get(), redSize, greenSize, blueSize, alphaSize, mOrientation,
+                        tr.getType(), getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig,
+                        mVisibleLayersSortedByZ.size());
+    result.appendFormat("   v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], s:[%d,%d,%d,%d],"
+                        "transform:[[%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f]]\n",
+                        mViewport.left, mViewport.top, mViewport.right, mViewport.bottom,
+                        mFrame.left, mFrame.top, mFrame.right, mFrame.bottom, mScissor.left,
+                        mScissor.top, mScissor.right, mScissor.bottom, tr[0][0], tr[1][0], tr[2][0],
+                        tr[0][1], tr[1][1], tr[2][1], tr[0][2], tr[1][2], tr[2][2]);
 
     String8 surfaceDump;
     mDisplaySurface->dumpAsString(surfaceDump);
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index e2852a7..8636e2a 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -141,6 +141,7 @@
 
     uint32_t                getLayerStack() const { return mLayerStack; }
     int32_t                 getDisplayType() const { return mType; }
+    bool                    isPrimary() const { return mType == DISPLAY_PRIMARY; }
     int32_t                 getHwcDisplayId() const { return mHwcDisplayId; }
     const wp<IBinder>&      getDisplayToken() const { return mDisplayToken; }
 
@@ -189,6 +190,7 @@
 #ifdef USE_HWC2
     android_color_mode_t getActiveColorMode() const;
     void setActiveColorMode(android_color_mode_t mode);
+    void setCompositionDataSpace(android_dataspace dataspace);
 #endif
 
     /* ------------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index 9d16044..e34fa16 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -181,6 +181,13 @@
     if (mClient == nullptr) {
         LOG_ALWAYS_FATAL("failed to create composer client");
     }
+
+    if (mIsUsingVrComposer) {
+        sp<IVrComposerClient> vrClient = IVrComposerClient::castFrom(mClient);
+        if (vrClient == nullptr) {
+            LOG_ALWAYS_FATAL("failed to create vr composer client");
+        }
+    }
 }
 
 std::vector<IComposer::Capability> Composer::getCapabilities()
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 5b869e1..68d7a18 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -106,12 +106,6 @@
     if (result != NO_ERROR) {
         ALOGE("error latching next FramebufferSurface buffer: %s (%d)",
                 strerror(-result), result);
-        return result;
-    }
-    result = mHwc.setClientTarget(mDisplayType, slot,
-            acquireFence, buf, dataspace);
-    if (result != NO_ERROR) {
-        ALOGE("error posting framebuffer: %d", result);
     }
     return result;
 #else
@@ -182,7 +176,13 @@
 #else
     outBuffer = mCurrentBuffer;
 #endif
-    return NO_ERROR;
+    status_t result =
+            mHwc.setClientTarget(mDisplayType, outSlot, outFence, outBuffer, outDataspace);
+    if (result != NO_ERROR) {
+        ALOGE("error posting framebuffer: %d", result);
+    }
+
+    return result;
 }
 
 #ifndef USE_HWC2
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index c48a28f..270a732 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -884,6 +884,10 @@
 
 Error Layer::setDataspace(android_dataspace_t dataspace)
 {
+    if (dataspace == mDataSpace) {
+        return Error::None;
+    }
+    mDataSpace = dataspace;
     auto intDataspace = static_cast<Hwc2::Dataspace>(dataspace);
     auto intError = mDevice.mComposer->setLayerDataspace(mDisplayId,
             mId, intDataspace);
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 7463e3b..404bb28 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -338,6 +338,7 @@
     hwc2_display_t mDisplayId;
     Device& mDevice;
     hwc2_layer_t mId;
+    android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN;
 };
 
 } // namespace HWC2
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 8217540..c129ae5 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -16,12 +16,16 @@
 
 // #define LOG_NDEBUG 0
 #include "VirtualDisplaySurface.h"
+
+#include <inttypes.h>
+
 #include "HWComposer.h"
 #include "SurfaceFlinger.h"
 
 #include <gui/BufferItem.h>
 #include <gui/BufferQueue.h>
 #include <gui/IProducerListener.h>
+#include <system/window.h>
 
 // ---------------------------------------------------------------------------
 namespace android {
@@ -338,7 +342,7 @@
 }
 
 status_t VirtualDisplaySurface::dequeueBuffer(Source source,
-        PixelFormat format, uint32_t usage, int* sslot, sp<Fence>* fence) {
+        PixelFormat format, uint64_t usage, int* sslot, sp<Fence>* fence) {
     LOG_FATAL_IF(mDisplayId < 0, "mDisplayId=%d but should not be < 0.", mDisplayId);
 
     status_t result = mSource[source]->dequeueBuffer(sslot, fence,
@@ -371,7 +375,7 @@
             mSource[source]->cancelBuffer(*sslot, *fence);
             return result;
         }
-        VDS_LOGV("dequeueBuffer(%s): buffers[%d]=%p fmt=%d usage=%#x",
+        VDS_LOGV("dequeueBuffer(%s): buffers[%d]=%p fmt=%d usage=%#" PRIx64,
                 dbgSourceStr(source), pslot, mProducerBuffers[pslot].get(),
                 mProducerBuffers[pslot]->getPixelFormat(),
                 mProducerBuffers[pslot]->getUsage());
@@ -381,7 +385,7 @@
 }
 
 status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence,
-        uint32_t w, uint32_t h, PixelFormat format, uint32_t usage,
+        uint32_t w, uint32_t h, PixelFormat format, uint64_t usage,
         FrameEventHistoryDelta* outTimestamps) {
     if (mDisplayId < 0) {
         return mSource[SOURCE_SINK]->dequeueBuffer(
@@ -392,7 +396,7 @@
             "Unexpected dequeueBuffer() in %s state", dbgStateStr());
     mDbgState = DBG_STATE_GLES;
 
-    VDS_LOGV("dequeueBuffer %dx%d fmt=%d usage=%#x", w, h, format, usage);
+    VDS_LOGV("dequeueBuffer %dx%d fmt=%d usage=%#" PRIx64, w, h, format, usage);
 
     status_t result = NO_ERROR;
     Source source = fbSourceForCompositionType(mCompositionType);
@@ -422,8 +426,8 @@
                 (w != 0 && w != mSinkBufferWidth) ||
                 (h != 0 && h != mSinkBufferHeight)) {
             VDS_LOGV("dequeueBuffer: dequeueing new output buffer: "
-                    "want %dx%d fmt=%d use=%#x, "
-                    "have %dx%d fmt=%d use=%#x",
+                    "want %dx%d fmt=%d use=%#" PRIx64 ", "
+                    "have %dx%d fmt=%d use=%#" PRIx64,
                     w, h, format, usage,
                     mSinkBufferWidth, mSinkBufferHeight,
                     buf->getPixelFormat(), buf->getUsage());
@@ -574,7 +578,7 @@
 }
 
 void VirtualDisplaySurface::allocateBuffers(uint32_t /* width */,
-        uint32_t /* height */, PixelFormat /* format */, uint32_t /* usage */) {
+        uint32_t /* height */, PixelFormat /* format */, uint64_t /* usage */) {
     // TODO: Should we actually allocate buffers for a virtual display?
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 5c0e084..7f8b39b 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -105,7 +105,7 @@
     virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers);
     virtual status_t setAsyncMode(bool async);
     virtual status_t dequeueBuffer(int* pslot, sp<Fence>* fence, uint32_t w,
-            uint32_t h, PixelFormat format, uint32_t usage,
+            uint32_t h, PixelFormat format, uint64_t usage,
             FrameEventHistoryDelta *outTimestamps);
     virtual status_t detachBuffer(int slot);
     virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer,
@@ -120,7 +120,7 @@
     virtual status_t disconnect(int api, DisconnectMode mode);
     virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
     virtual void allocateBuffers(uint32_t width, uint32_t height,
-            PixelFormat format, uint32_t usage);
+            PixelFormat format, uint64_t usage);
     virtual status_t allowAllocation(bool allow);
     virtual status_t setGenerationNumber(uint32_t generationNumber);
     virtual String8 getConsumerName() const override;
@@ -135,7 +135,7 @@
     // Utility methods
     //
     static Source fbSourceForCompositionType(CompositionType type);
-    status_t dequeueBuffer(Source source, PixelFormat format, uint32_t usage,
+    status_t dequeueBuffer(Source source, PixelFormat format, uint64_t usage,
             int* sslot, sp<Fence>* fence);
     void updateQueueBufferOutput(QueueBufferOutput&& qbo);
     void resetPerFrameState();
@@ -168,7 +168,7 @@
     // the composition type changes or the GLES driver starts requesting
     // different usage/format, we'll get a new buffer.
     uint32_t mOutputFormat;
-    uint32_t mOutputUsage;
+    uint64_t mOutputUsage;
 
     // Since we present a single producer interface to the GLES driver, but
     // are internally muxing between the sink and scratch producers, we have
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
old mode 100644
new mode 100755
index 88a5bd4..1b864fd
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -34,6 +34,7 @@
 #include <utils/StopWatch.h>
 #include <utils/Trace.h>
 
+#include <ui/DebugUtils.h>
 #include <ui/GraphicBuffer.h>
 #include <ui/PixelFormat.h>
 
@@ -125,6 +126,7 @@
         mPremultipliedAlpha = false;
 
     mName = name;
+    mTransactionName = String8("TX - ") + mName;
 
     mCurrentState.active.w = w;
     mCurrentState.active.h = h;
@@ -472,7 +474,7 @@
 
     Rect activeCrop(s.active.w, s.active.h);
     if (!s.crop.isEmpty()) {
-        activeCrop = s.crop;
+        activeCrop.intersect(s.crop, &activeCrop);
     }
 
     Transform t = getTransform();
@@ -893,9 +895,6 @@
     }
 }
 
-android_dataspace Layer::getDataSpace() const {
-    return mCurrentState.dataSpace;
-}
 #else
 void Layer::setPerFrameData(const sp<const DisplayDevice>& hw,
         HWComposer::HWCLayerInterface& layer) {
@@ -1417,9 +1416,9 @@
 
 bool Layer::isOpaque(const Layer::State& s) const
 {
-    // if we don't have a buffer yet, we're translucent regardless of the
+    // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the
     // layer's opaque flag.
-    if (mActiveBuffer == 0) {
+    if ((mSidebandStream == nullptr) && (mActiveBuffer == nullptr)) {
         return false;
     }
 
@@ -1505,6 +1504,7 @@
         mFlinger->setTransactionFlags(eTraversalNeeded);
     }
     mPendingStates.push_back(mCurrentState);
+    ATRACE_INT(mTransactionName.string(), mPendingStates.size());
 }
 
 void Layer::popPendingState(State* stateToCommit) {
@@ -1514,6 +1514,7 @@
             (stateToCommit->flags & stateToCommit->mask);
 
     mPendingStates.removeAt(0);
+    ATRACE_INT(mTransactionName.string(), mPendingStates.size());
 }
 
 bool Layer::applyPendingStates(State* stateToCommit) {
@@ -1928,6 +1929,10 @@
     return true;
 }
 
+android_dataspace Layer::getDataSpace() const {
+    return mCurrentState.dataSpace;
+}
+
 uint32_t Layer::getLayerStack() const {
     auto p = mDrawingParent.promote();
     if (p == nullptr) {
@@ -2372,11 +2377,17 @@
     visibleRegion.dump(result, "visibleRegion");
     surfaceDamageRegion.dump(result, "surfaceDamageRegion");
     sp<Client> client(mClientRef.promote());
+    PixelFormat pf = PIXEL_FORMAT_UNKNOWN;
+    const sp<GraphicBuffer>& buffer(getActiveBuffer());
+    if (buffer != NULL) {
+        pf = buffer->getPixelFormat();
+    }
 
     result.appendFormat(            "      "
             "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), "
             "crop=(%4d,%4d,%4d,%4d), finalCrop=(%4d,%4d,%4d,%4d), "
             "isOpaque=%1d, invalidate=%1d, "
+            "dataspace=%s, pixelformat=%s "
 #ifdef USE_HWC2
             "alpha=%.3f, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n"
 #else
@@ -2391,6 +2402,7 @@
             s.finalCrop.left, s.finalCrop.top,
             s.finalCrop.right, s.finalCrop.bottom,
             isOpaque(s), contentDirty,
+            dataspaceDetails(getDataSpace()).c_str(), decodePixelFormat(pf).c_str(),
             s.alpha, s.flags,
             s.active.transform[0][0], s.active.transform[0][1],
             s.active.transform[1][0], s.active.transform[1][1],
@@ -2682,7 +2694,7 @@
         // for in the transform. We need to mirror this scaling in child surfaces
         // or we will break the contract where WM can treat child surfaces as
         // pixels in the parent surface.
-        if (p->isFixedSize()) {
+        if (p->isFixedSize() && p->mActiveBuffer != nullptr) {
             int bufferWidth;
             int bufferHeight;
             if ((p->mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) == 0) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 24fc10d..2306d1a 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -166,6 +166,8 @@
 
     virtual ~Layer();
 
+    void setPrimaryDisplayOnly() { mPrimaryDisplayOnly = true; }
+
     // the this layer's size and format
     status_t setBuffers(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags);
 
@@ -231,6 +233,7 @@
     bool setFlags(uint8_t flags, uint8_t mask);
     bool setLayerStack(uint32_t layerStack);
     bool setDataSpace(android_dataspace dataSpace);
+    android_dataspace getDataSpace() const;
     uint32_t getLayerStack() const;
     void deferTransactionUntil(const sp<IBinder>& barrierHandle, uint64_t frameNumber);
     void deferTransactionUntil(const sp<Layer>& barrierLayer, uint64_t frameNumber);
@@ -248,6 +251,10 @@
     uint32_t getTransactionFlags(uint32_t flags);
     uint32_t setTransactionFlags(uint32_t flags);
 
+    bool belongsToDisplay(uint32_t layerStack, bool isPrimaryDisplay) const {
+        return getLayerStack() == layerStack && (!mPrimaryDisplayOnly || isPrimaryDisplay);
+    }
+
     void computeGeometry(const sp<const DisplayDevice>& hw, Mesh& mesh,
             bool useIdentityTransform) const;
     Rect computeBounds(const Region& activeTransparentRegion) const;
@@ -314,8 +321,6 @@
     void forceClientComposition(int32_t hwcId);
     void setPerFrameData(const sp<const DisplayDevice>& displayDevice);
 
-    android_dataspace getDataSpace() const;
-
     // callIntoHwc exists so we can update our local state and call
     // acceptDisplayChanges without unnecessarily updating the device's state
     void setCompositionType(int32_t hwcId, HWC2::Composition type,
@@ -409,6 +414,7 @@
      * to figure out if the content or size of a surface has changed.
      */
     Region latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime);
+    bool isBufferLatched() const { return mRefreshPending; }
 
     bool isPotentialCursor() const { return mPotentialCursor;}
 
@@ -698,8 +704,11 @@
     uint32_t mTextureName;      // from GLES
     bool mPremultipliedAlpha;
     String8 mName;
+    String8 mTransactionName; // A cached version of "TX - " + mName for systraces
     PixelFormat mFormat;
 
+    bool mPrimaryDisplayOnly = false;
+
     // these are protected by an external lock
     State mCurrentState;
     State mDrawingState;
diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp
index 6e37b45..e864607 100644
--- a/services/surfaceflinger/LayerRejecter.cpp
+++ b/services/surfaceflinger/LayerRejecter.cpp
@@ -17,6 +17,7 @@
 #include "LayerRejecter.h"
 
 #include <gui/BufferItem.h>
+#include <system/window.h>
 
 #include "clz.h"
 
diff --git a/services/surfaceflinger/MessageQueue.h b/services/surfaceflinger/MessageQueue.h
index 85a33c8..14f50bb 100644
--- a/services/surfaceflinger/MessageQueue.h
+++ b/services/surfaceflinger/MessageQueue.h
@@ -30,6 +30,8 @@
 
 #include "Barrier.h"
 
+#include <functional>
+
 namespace android {
 
 class IDisplayEventConnection;
@@ -58,6 +60,21 @@
     mutable Barrier barrier;
 };
 
+class LambdaMessage : public MessageBase {
+public:
+    explicit LambdaMessage(std::function<void()> handler)
+          : MessageBase(), mHandler(std::move(handler)) {}
+
+    bool handler() override {
+        mHandler();
+        // This return value is no longer checked, so it's always safe to return true
+        return true;
+    }
+
+private:
+    const std::function<void()> mHandler;
+};
+
 // ---------------------------------------------------------------------------
 
 class MessageQueue {
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index 2ba1b33..e717632 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -69,7 +69,7 @@
 }
 
 status_t MonitoredProducer::dequeueBuffer(int* slot, sp<Fence>* fence,
-        uint32_t w, uint32_t h, PixelFormat format, uint32_t usage,
+        uint32_t w, uint32_t h, PixelFormat format, uint64_t usage,
         FrameEventHistoryDelta* outTimestamps) {
     return mProducer->dequeueBuffer(
             slot, fence, w, h, format, usage, outTimestamps);
@@ -116,7 +116,7 @@
 }
 
 void MonitoredProducer::allocateBuffers(uint32_t width, uint32_t height,
-        PixelFormat format, uint32_t usage) {
+        PixelFormat format, uint64_t usage) {
     mProducer->allocateBuffers(width, height, format, usage);
 }
 
diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
index a3ec29d..58b9bc4 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -40,7 +40,7 @@
     virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers);
     virtual status_t setAsyncMode(bool async);
     virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w,
-            uint32_t h, PixelFormat format, uint32_t usage,
+            uint32_t h, PixelFormat format, uint64_t usage,
             FrameEventHistoryDelta* outTimestamps);
     virtual status_t detachBuffer(int slot);
     virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer,
@@ -56,7 +56,7 @@
     virtual status_t disconnect(int api, DisconnectMode mode);
     virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
     virtual void allocateBuffers(uint32_t width, uint32_t height,
-            PixelFormat format, uint32_t usage);
+            PixelFormat format, uint64_t usage);
     virtual status_t allowAllocation(bool allow);
     virtual status_t setGenerationNumber(uint32_t generationNumber);
     virtual String8 getConsumerName() const override;
diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/services/surfaceflinger/RenderEngine/Description.cpp
index 0dab872..effd319 100644
--- a/services/surfaceflinger/RenderEngine/Description.cpp
+++ b/services/surfaceflinger/RenderEngine/Description.cpp
@@ -26,8 +26,7 @@
 
 namespace android {
 
-Description::Description() :
-    mUniformsDirty(true) {
+Description::Description() {
     mPlaneAlpha = 1.0f;
     mPremultipliedAlpha = false;
     mOpaque = true;
@@ -41,28 +40,20 @@
 }
 
 void Description::setPlaneAlpha(GLclampf planeAlpha) {
-    if (planeAlpha != mPlaneAlpha) {
-        mUniformsDirty = true;
-        mPlaneAlpha = planeAlpha;
-    }
+    mPlaneAlpha = planeAlpha;
 }
 
 void Description::setPremultipliedAlpha(bool premultipliedAlpha) {
-    if (premultipliedAlpha != mPremultipliedAlpha) {
-        mPremultipliedAlpha = premultipliedAlpha;
-    }
+    mPremultipliedAlpha = premultipliedAlpha;
 }
 
 void Description::setOpaque(bool opaque) {
-    if (opaque != mOpaque) {
-        mOpaque = opaque;
-    }
+    mOpaque = opaque;
 }
 
 void Description::setTexture(const Texture& texture) {
     mTexture = texture;
     mTextureEnabled = true;
-    mUniformsDirty = true;
 }
 
 void Description::disableTexture() {
@@ -74,12 +65,10 @@
     mColor[1] = green;
     mColor[2] = blue;
     mColor[3] = alpha;
-    mUniformsDirty = true;
 }
 
 void Description::setProjectionMatrix(const mat4& mtx) {
     mProjectionMatrix = mtx;
-    mUniformsDirty = true;
 }
 
 void Description::setColorMatrix(const mat4& mtx) {
@@ -92,5 +81,8 @@
     return mColorMatrix;
 }
 
+void Description::setWideGamut(bool wideGamut) {
+    mIsWideGamut = wideGamut;
+}
 
 } /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/Description.h b/services/surfaceflinger/RenderEngine/Description.h
index 8a3447c..3beffdf 100644
--- a/services/surfaceflinger/RenderEngine/Description.h
+++ b/services/surfaceflinger/RenderEngine/Description.h
@@ -54,6 +54,8 @@
     bool mColorMatrixEnabled;
     mat4 mColorMatrix;
 
+    bool mIsWideGamut;
+
 public:
     Description();
     ~Description();
@@ -67,9 +69,7 @@
     void setProjectionMatrix(const mat4& mtx);
     void setColorMatrix(const mat4& mtx);
     const mat4& getColorMatrix() const;
-
-private:
-    bool mUniformsDirty;
+    void setWideGamut(bool wideGamut);
 };
 
 } /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
index 04fe182..37a530b 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -40,9 +40,7 @@
 #include "Mesh.h"
 #include "Texture.h"
 
-#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
-#include <configstore/Utils.h>
-
+#include <sstream>
 #include <fstream>
 
 // ---------------------------------------------------------------------------
@@ -111,8 +109,10 @@
 namespace android {
 // ---------------------------------------------------------------------------
 
-GLES20RenderEngine::GLES20RenderEngine() :
-        mVpWidth(0), mVpHeight(0) {
+GLES20RenderEngine::GLES20RenderEngine(uint32_t featureFlags) :
+         mVpWidth(0),
+         mVpHeight(0),
+         mPlatformHasWideColor((featureFlags & WIDE_COLOR_SUPPORT) != 0) {
 
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
     glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
@@ -133,23 +133,16 @@
     //mColorBlindnessCorrection = M;
 
 #ifdef USE_HWC2
-    // retrieve wide-color and hdr settings from configstore
-    using namespace android::hardware::configstore;
-    using namespace android::hardware::configstore::V1_0;
-
-    mPlatformHasWideColor =
-            getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
     if (mPlatformHasWideColor) {
         // Compute sRGB to DisplayP3 color transform
         // NOTE: For now, we are limiting wide-color support to
         // Display-P3 only.
-        mat3 srgbToP3 = ColorSpace::DisplayP3().getXYZtoRGB() * ColorSpace::sRGB().getRGBtoXYZ();
+        mat3 srgbToP3 = ColorSpaceConnector(ColorSpace::sRGB(), ColorSpace::DisplayP3()).getTransform();
 
-        // color transform needs to be transposed and expanded to 4x4
-        // to be what the shader wants
+        // color transform needs to be expanded to 4x4 to be what the shader wants
         // mat has an initializer that expands mat3 to mat4, but
         // not an assignment operator
-        mat4 gamutTransform(transpose(srgbToP3));
+        mat4 gamutTransform(srgbToP3);
         mSrgbToDisplayP3 = gamutTransform;
     }
 #endif
@@ -392,6 +385,7 @@
         Description wideColorState = mState;
         if (mDataSpace != HAL_DATASPACE_DISPLAY_P3) {
             wideColorState.setColorMatrix(mState.getColorMatrix() * mSrgbToDisplayP3);
+            wideColorState.setWideGamut(true);
             ALOGV("drawMesh: gamut transform applied");
         }
         ProgramCache::getInstance().useProgram(wideColorState);
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
index 19cbb60..eaf94af 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
@@ -59,7 +59,7 @@
     virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName);
 
 public:
-    GLES20RenderEngine();
+    GLES20RenderEngine(uint32_t featureFlags); // See RenderEngine::FeatureFlag
 
 protected:
     virtual ~GLES20RenderEngine();
@@ -86,7 +86,6 @@
     android_dataspace mDataSpace = HAL_DATASPACE_V0_SRGB;
 
     // Indicate if wide-color mode is needed or not
-    bool mPlatformHasWideColor = false;
     bool mDisplayHasWideColor = false;
     bool mUseWideColor = false;
     uint64_t mWideColorFrameCount = 0;
@@ -98,6 +97,8 @@
             int alpha);
     virtual void setupDimLayerBlending(int alpha);
 #endif
+    bool mPlatformHasWideColor = false;
+
     virtual void setupLayerTexturing(const Texture& texture);
     virtual void setupLayerBlackedOut();
     virtual void setupFillWithColor(float r, float g, float b, float a);
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
index ba11259..06b2252 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
@@ -129,7 +129,9 @@
     .set(Key::OPACITY_MASK,
             description.mOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT)
     .set(Key::COLOR_MATRIX_MASK,
-            description.mColorMatrixEnabled ? Key::COLOR_MATRIX_ON :  Key::COLOR_MATRIX_OFF);
+            description.mColorMatrixEnabled ? Key::COLOR_MATRIX_ON :  Key::COLOR_MATRIX_OFF)
+    .set(Key::WIDE_GAMUT_MASK,
+            description.mIsWideGamut ? Key::WIDE_GAMUT_ON : Key::WIDE_GAMUT_OFF);
     return needs;
 }
 
@@ -175,6 +177,50 @@
     if (needs.hasColorMatrix()) {
         fs << "uniform mat4 colorMatrix;";
     }
+    if (needs.hasColorMatrix()) {
+        // When in wide gamut mode, the color matrix will contain a color space
+        // conversion matrix that needs to be applied in linear space
+        // When not in wide gamut, we can simply no-op the transfer functions
+        // and let the shader compiler get rid of them
+        if (needs.isWideGamut()) {
+            fs << R"__SHADER__(
+                  float OETF_sRGB(const float linear) {
+                      return linear <= 0.0031308 ?
+                              linear * 12.92 : (pow(linear, 1.0 / 2.4) * 1.055) - 0.055;
+                  }
+
+                  vec3 OETF_sRGB(const vec3 linear) {
+                      return vec3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b));
+                  }
+
+                  vec3 OETF_scRGB(const vec3 linear) {
+                      return sign(linear.rgb) * OETF_sRGB(abs(linear.rgb));
+                  }
+
+                  float EOTF_sRGB(float srgb) {
+                      return srgb <= 0.04045 ? srgb / 12.92 : pow((srgb + 0.055) / 1.055, 2.4);
+                  }
+
+                  vec3 EOTF_sRGB(const vec3 srgb) {
+                      return vec3(EOTF_sRGB(srgb.r), EOTF_sRGB(srgb.g), EOTF_sRGB(srgb.b));
+                  }
+
+                  vec3 EOTF_scRGB(const vec3 srgb) {
+                      return sign(srgb.rgb) * EOTF_sRGB(abs(srgb.rgb));
+                  }
+            )__SHADER__";
+        } else {
+            fs << R"__SHADER__(
+                  vec3 OETF_scRGB(const vec3 linear) {
+                      return linear;
+                  }
+
+                  vec3 EOTF_scRGB(const vec3 srgb) {
+                      return srgb;
+                  }
+            )__SHADER__";
+        }
+    }
     fs << "void main(void) {" << indent;
     if (needs.isTexturing()) {
         fs << "gl_FragColor = texture2D(sampler, outTexCoords);";
@@ -197,13 +243,15 @@
     if (needs.hasColorMatrix()) {
         if (!needs.isOpaque() && needs.isPremultiplied()) {
             // un-premultiply if needed before linearization
-            fs << "gl_FragColor.rgb = gl_FragColor.rgb/gl_FragColor.a;";
+            // avoid divide by 0 by adding 0.5/256 to the alpha channel
+            fs << "gl_FragColor.rgb = gl_FragColor.rgb / (gl_FragColor.a + 0.0019);";
         }
-        fs << "vec4 transformed = colorMatrix * vec4(gl_FragColor.rgb, 1);";
-        fs << "gl_FragColor.rgb = transformed.rgb/transformed.a;";
+        fs << "vec4 transformed = colorMatrix * vec4(EOTF_scRGB(gl_FragColor.rgb), 1);";
+        // We assume the last row is always {0,0,0,1} and we skip the division by w
+        fs << "gl_FragColor.rgb = OETF_scRGB(transformed.rgb);";
         if (!needs.isOpaque() && needs.isPremultiplied()) {
             // and re-premultiply if needed after gamma correction
-            fs << "gl_FragColor.rgb = gl_FragColor.rgb*gl_FragColor.a;";
+            fs << "gl_FragColor.rgb = gl_FragColor.rgb * (gl_FragColor.a + 0.0019);";
         }
     }
 
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.h b/services/surfaceflinger/RenderEngine/ProgramCache.h
index 1fa53d3..5b0fbcd 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.h
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.h
@@ -69,6 +69,10 @@
             COLOR_MATRIX_OFF        =       0x00000000,
             COLOR_MATRIX_ON         =       0x00000020,
             COLOR_MATRIX_MASK       =       0x00000020,
+
+            WIDE_GAMUT_OFF          =       0x00000000,
+            WIDE_GAMUT_ON           =       0x00000040,
+            WIDE_GAMUT_MASK         =       0x00000040,
         };
 
         inline Key() : mKey(0) { }
@@ -97,10 +101,13 @@
         inline bool hasColorMatrix() const {
             return (mKey & COLOR_MATRIX_MASK) == COLOR_MATRIX_ON;
         }
+        inline bool isWideGamut() const {
+            return (mKey & WIDE_GAMUT_MASK) == WIDE_GAMUT_ON;
+        }
 
         // this is the definition of a friend function -- not a method of class Needs
         friend inline int strictly_order_type(const Key& lhs, const Key& rhs) {
-            return  (lhs.mKey < rhs.mKey) ? 1 : 0;
+            return (lhs.mKey < rhs.mKey) ? 1 : 0;
         }
     };
 
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index 7564269..ac2d8b2 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -47,19 +47,23 @@
     return false;
 }
 
-RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat) {
+RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat, uint32_t featureFlags) {
     // EGL_ANDROIDX_no_config_context is an experimental extension with no
     // written specification. It will be replaced by something more formal.
     // SurfaceFlinger is using it to allow a single EGLContext to render to
     // both a 16-bit primary display framebuffer and a 32-bit virtual display
     // framebuffer.
     //
+    // EGL_KHR_no_config_context is official extension to allow creating a
+    // context that works with any surface of a display.
+    //
     // The code assumes that ES2 or later is available if this extension is
     // supported.
     EGLConfig config = EGL_NO_CONFIG;
-    if (!findExtension(
-            eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS),
-            "EGL_ANDROIDX_no_config_context")) {
+    if (!findExtension(eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS),
+                       "EGL_ANDROIDX_no_config_context") &&
+        !findExtension(eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS),
+                       "EGL_KHR_no_config_context")) {
         config = chooseEglConfig(display, hwcFormat);
     }
 
@@ -131,7 +135,7 @@
         break;
     case GLES_VERSION_2_0:
     case GLES_VERSION_3_0:
-        engine = new GLES20RenderEngine();
+        engine = new GLES20RenderEngine(featureFlags);
         break;
     }
     engine->setEGLHandles(config, ctxt);
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index 8b031bc..56f5827 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -59,7 +59,10 @@
     virtual ~RenderEngine() = 0;
 
 public:
-    static RenderEngine* create(EGLDisplay display, int hwcFormat);
+    enum FeatureFlag {
+        WIDE_COLOR_SUPPORT = 1 << 0 // Platform has a wide color display
+    };
+    static RenderEngine* create(EGLDisplay display, int hwcFormat, uint32_t featureFlags);
 
     static EGLConfig chooseEglConfig(EGLDisplay display, int format);
 
diff --git a/services/surfaceflinger/StartBootAnimThread.cpp b/services/surfaceflinger/StartBootAnimThread.cpp
deleted file mode 100644
index c3f7296..0000000
--- a/services/surfaceflinger/StartBootAnimThread.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2017 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 <cutils/properties.h>
-#include "StartBootAnimThread.h"
-
-namespace android {
-
-StartBootAnimThread::StartBootAnimThread():
-        Thread(false) {
-}
-
-status_t StartBootAnimThread::Start() {
-    return run("SurfaceFlinger::StartBootAnimThread", PRIORITY_NORMAL);
-}
-
-bool StartBootAnimThread::threadLoop() {
-    property_set("service.bootanim.exit", "0");
-    property_set("ctl.start", "bootanim");
-    // Exit immediately
-    return false;
-}
-
-} // namespace android
diff --git a/services/surfaceflinger/StartPropertySetThread.cpp b/services/surfaceflinger/StartPropertySetThread.cpp
new file mode 100644
index 0000000..db82772
--- /dev/null
+++ b/services/surfaceflinger/StartPropertySetThread.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 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 <cutils/properties.h>
+#include "StartPropertySetThread.h"
+
+namespace android {
+
+StartPropertySetThread::StartPropertySetThread(bool timestampPropertyValue):
+        Thread(false), mTimestampPropertyValue(timestampPropertyValue) {}
+
+status_t StartPropertySetThread::Start() {
+    return run("SurfaceFlinger::StartPropertySetThread", PRIORITY_NORMAL);
+}
+
+bool StartPropertySetThread::threadLoop() {
+    // Set property service.sf.present_timestamp, consumer need check its readiness
+    property_set(kTimestampProperty, mTimestampPropertyValue ? "1" : "0");
+    // Clear BootAnimation exit flag
+    property_set("service.bootanim.exit", "0");
+    // Start BootAnimation if not started
+    property_set("ctl.start", "bootanim");
+    // Exit immediately
+    return false;
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/StartBootAnimThread.h b/services/surfaceflinger/StartPropertySetThread.h
similarity index 78%
rename from services/surfaceflinger/StartBootAnimThread.h
rename to services/surfaceflinger/StartPropertySetThread.h
index dba2bee..a64c21b 100644
--- a/services/surfaceflinger/StartBootAnimThread.h
+++ b/services/surfaceflinger/StartPropertySetThread.h
@@ -24,17 +24,21 @@
 
 namespace android {
 
-class StartBootAnimThread : public Thread {
+class StartPropertySetThread : public Thread {
 // Boot animation is triggered via calls to "property_set()" which can block
 // if init's executing slow operation such as 'mount_all --late' (currently
 // happening 1/10th with fsck)  concurrently. Running in a separate thread
 // allows to pursue the SurfaceFlinger's init process without blocking.
 // see b/34499826.
+// Any property_set() will block during init stage so need to be offloaded
+// to this thread. see b/63844978.
 public:
-    StartBootAnimThread();
+    StartPropertySetThread(bool timestampPropertyValue);
     status_t Start();
 private:
     virtual bool threadLoop();
+    static constexpr const char* kTimestampProperty = "service.sf.present_timestamp";
+    const bool mTimestampPropertyValue;
 };
 
 }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 29e7bd6..2703db8 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -19,12 +19,14 @@
 
 #include <stdint.h>
 #include <sys/types.h>
+#include <algorithm>
 #include <errno.h>
 #include <math.h>
 #include <mutex>
 #include <dlfcn.h>
 #include <inttypes.h>
 #include <stdatomic.h>
+#include <optional>
 
 #include <EGL/egl.h>
 
@@ -193,6 +195,8 @@
     hasWideColorDisplay =
             getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
 
+    mPrimaryDispSync.init(hasSyncFramework, dispSyncPresentTimeOffset);
+
     // debugging stuff...
     char value[PROPERTY_VALUE_MAX];
 
@@ -224,6 +228,11 @@
     property_get("ro.sf.disable_triple_buffer", value, "1");
     mLayerTripleBufferingDisabled = atoi(value);
     ALOGI_IF(mLayerTripleBufferingDisabled, "Disabling Triple Buffering");
+
+    // We should be reading 'persist.sys.sf.color_saturation' here
+    // but since /data may be encrypted, we need to wait until after vold
+    // comes online to attempt to read the property. The property is
+    // instead read after the boot animation
 }
 
 void SurfaceFlinger::onFirstRef()
@@ -341,13 +350,12 @@
 
 void SurfaceFlinger::bootFinished()
 {
-    if (mStartBootAnimThread->join() != NO_ERROR) {
-        ALOGE("Join StartBootAnimThread failed!");
+    if (mStartPropertySetThread->join() != NO_ERROR) {
+        ALOGE("Join StartPropertySetThread failed!");
     }
     const nsecs_t now = systemTime();
     const nsecs_t duration = now - mBootTime;
     ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
-    mBootFinished = true;
 
     // wait patiently for the window manager death
     const String16 name("window");
@@ -368,6 +376,21 @@
     const int LOGTAG_SF_STOP_BOOTANIM = 60110;
     LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
                    ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
+
+    sp<LambdaMessage> bootFinished = new LambdaMessage([&]() {
+        mBootFinished = true;
+
+        readPersistentProperties();
+
+#ifdef USE_HWC2
+        sp<DisplayDevice> hw(getDisplayDevice(mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]));
+        if (hw->getWideColorSupport()) {
+            hw->setCompositionDataSpace(HAL_DATASPACE_V0_SRGB);
+            setActiveColorModeInternal(hw, HAL_COLOR_MODE_SRGB);
+        }
+#endif
+    });
+    postMessageAsync(bootFinished);
 }
 
 void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
@@ -526,11 +549,13 @@
     sp<VSyncSource::Callback> mCallback;
 };
 
+// Do not call property_set on main thread which will be blocked by init
+// Use StartPropertySetThread instead.
 void SurfaceFlinger::init() {
     ALOGI(  "SurfaceFlinger's main thread ready to run. "
             "Initializing graphics H/W...");
 
-    ALOGI("Phase offest NS: %" PRId64 "", vsyncPhaseOffsetNs);
+    ALOGI("Phase offset NS: %" PRId64 "", vsyncPhaseOffsetNs);
 
     { // Autolock scope
         Mutex::Autolock _l(mStateLock);
@@ -560,7 +585,8 @@
 
         // Get a RenderEngine for the given display / config (can't fail)
         mRenderEngine = RenderEngine::create(mEGLDisplay,
-                HAL_PIXEL_FORMAT_RGBA_8888);
+                HAL_PIXEL_FORMAT_RGBA_8888,
+                hasWideColorDisplay ? RenderEngine::WIDE_COLOR_SUPPORT : 0);
     }
 
     // Drop the state lock while we initialize the hardware composer. We drop
@@ -574,14 +600,6 @@
 
     Mutex::Autolock _l(mStateLock);
 
-    // Inform native graphics APIs whether the present timestamp is supported:
-    if (getHwComposer().hasCapability(
-            HWC2::Capability::PresentFenceIsNotReliable)) {
-        property_set(kTimestampProperty, "0");
-    } else {
-        property_set(kTimestampProperty, "1");
-    }
-
     if (useVrFlinger) {
         auto vrFlingerRequestDisplayCallback = [this] (bool requestDisplay) {
             ALOGI("VR request display mode: requestDisplay=%d", requestDisplay);
@@ -616,21 +634,36 @@
 
     mRenderEngine->primeCache();
 
-    mStartBootAnimThread = new StartBootAnimThread();
-    if (mStartBootAnimThread->Start() != NO_ERROR) {
-        ALOGE("Run StartBootAnimThread failed!");
+    // Inform native graphics APIs whether the present timestamp is supported:
+    if (getHwComposer().hasCapability(
+            HWC2::Capability::PresentFenceIsNotReliable)) {
+        mStartPropertySetThread = new StartPropertySetThread(false);
+    } else {
+        mStartPropertySetThread = new StartPropertySetThread(true);
+    }
+
+    if (mStartPropertySetThread->Start() != NO_ERROR) {
+        ALOGE("Run StartPropertySetThread failed!");
     }
 
     ALOGV("Done initializing");
 }
 
+void SurfaceFlinger::readPersistentProperties() {
+    char value[PROPERTY_VALUE_MAX];
+
+    property_get("persist.sys.sf.color_saturation", value, "1.0");
+    mSaturation = atof(value);
+    ALOGV("Saturation is set to %.2f", mSaturation);
+}
+
 void SurfaceFlinger::startBootAnim() {
     // Start boot animation service by setting a property mailbox
     // if property setting thread is already running, Start() will be just a NOP
-    mStartBootAnimThread->Start();
+    mStartPropertySetThread->Start();
     // Wait until property was set
-    if (mStartBootAnimThread->join() != NO_ERROR) {
-        ALOGE("Join StartBootAnimThread failed!");
+    if (mStartPropertySetThread->join() != NO_ERROR) {
+        ALOGE("Join StartPropertySetThread failed!");
     }
 }
 
@@ -1048,6 +1081,7 @@
 }
 
 void SurfaceFlinger::signalRefresh() {
+    mRefreshPending = true;
     mEventQueue.refresh();
 }
 
@@ -1190,11 +1224,8 @@
                                              token, fbs, producer, mRenderEngine->getEGLConfig(),
                                              hasWideColorModes && hasWideColorDisplay);
     mDisplays.add(token, hw);
-    android_color_mode defaultColorMode = HAL_COLOR_MODE_NATIVE;
-    if (hasWideColorModes && hasWideColorDisplay) {
-        defaultColorMode = HAL_COLOR_MODE_SRGB;
-    }
-    setActiveColorModeInternal(hw, defaultColorMode);
+    setActiveColorModeInternal(hw, HAL_COLOR_MODE_NATIVE);
+    hw->setCompositionDataSpace(HAL_DATASPACE_UNKNOWN);
 }
 
 void SurfaceFlinger::onHotplugReceived(HWComposer* composer, int32_t disp, bool connected) {
@@ -1248,17 +1279,14 @@
             enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable);
 }
 
-void SurfaceFlinger::clearHwcLayers(const LayerVector& layers) {
-    for (size_t i = 0; i < layers.size(); ++i) {
-        layers[i]->clearHwcLayers();
-    }
-}
-
 // Note: it is assumed the caller holds |mStateLock| when this is called
 void SurfaceFlinger::resetHwcLocked() {
     disableHardwareVsync(true);
     clearHwcLayers(mDrawingState.layersSortedByZ);
     clearHwcLayers(mCurrentState.layersSortedByZ);
+    for (size_t disp = 0; disp < mDisplays.size(); ++disp) {
+        clearHwcLayers(mDisplays[disp]->getVisibleLayersSortedByZ());
+    }
     // Clear the drawing state so that the logic inside of
     // handleTransactionLocked will fire. It will determine the delta between
     // mCurrentState and mDrawingState and re-apply all changes when we make the
@@ -1318,11 +1346,21 @@
     // parts of this class rely on the primary display always being available.
     createDefaultDisplayDevice();
 
-    // Reset the timing values to account for the period of the swapped in HWC
-    const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
-    const nsecs_t period = activeConfig->getVsyncPeriod();
-    mAnimFrameTracker.setDisplayRefreshPeriod(period);
-    setCompositorTimingSnapped(0, period, 0);
+    // Re-enable default display.
+    sp<LambdaMessage> requestMessage = new LambdaMessage([&]() {
+        sp<DisplayDevice> hw(getDisplayDevice(mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]));
+        setPowerModeInternal(hw, HWC_POWER_MODE_NORMAL);
+
+        // Reset the timing values to account for the period of the swapped in HWC
+        const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+        const nsecs_t period = activeConfig->getVsyncPeriod();
+        mAnimFrameTracker.setDisplayRefreshPeriod(period);
+
+        // Use phase of 0 since phase is not known.
+        // Use latency of 0, which will snap to the ideal latency.
+        setCompositorTimingSnapped(0, period, 0);
+    });
+    postMessageAsync(requestMessage);
 
     android_atomic_or(1, &mRepaintEverything);
     setTransactionFlags(eDisplayTransactionNeeded);
@@ -1383,6 +1421,8 @@
 void SurfaceFlinger::handleMessageRefresh() {
     ATRACE_CALL();
 
+    mRefreshPending = false;
+
     nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     preComposition(refreshStartTime);
@@ -1644,12 +1684,11 @@
             const Transform& tr(displayDevice->getTransform());
             const Rect bounds(displayDevice->getBounds());
             if (displayDevice->isDisplayOn()) {
-                computeVisibleRegions(
-                        displayDevice->getLayerStack(), dirtyRegion,
-                        opaqueRegion);
+                computeVisibleRegions(displayDevice, dirtyRegion, opaqueRegion);
 
                 mDrawingState.traverseInZOrder([&](Layer* layer) {
-                    if (layer->getLayerStack() == displayDevice->getLayerStack()) {
+                    if (layer->belongsToDisplay(displayDevice->getLayerStack(),
+                                displayDevice->isPrimary())) {
                         Region drawRegion(tr.transform(
                                 layer->visibleNonTransparentRegion));
                         drawRegion.andSelf(bounds);
@@ -1679,9 +1718,25 @@
     }
 }
 
+mat4 SurfaceFlinger::computeSaturationMatrix() const {
+    if (mSaturation == 1.0f) {
+        return mat4();
+    }
+
+    // Rec.709 luma coefficients
+    float3 luminance{0.213f, 0.715f, 0.072f};
+    luminance *= 1.0f - mSaturation;
+    return mat4(
+        vec4{luminance.r + mSaturation, luminance.r, luminance.r, 0.0f},
+        vec4{luminance.g, luminance.g + mSaturation, luminance.g, 0.0f},
+        vec4{luminance.b, luminance.b, luminance.b + mSaturation, 0.0f},
+        vec4{0.0f, 0.0f, 0.0f, 1.0f}
+    );
+}
+
 // pickColorMode translates a given dataspace into the best available color mode.
 // Currently only support sRGB and Display-P3.
-android_color_mode SurfaceFlinger::pickColorMode(android_dataspace dataSpace) {
+android_color_mode SurfaceFlinger::pickColorMode(android_dataspace dataSpace) const {
     switch (dataSpace) {
         // treat Unknown as regular SRGB buffer, since that's what the rest of the
         // system expects.
@@ -1704,11 +1759,19 @@
     }
 }
 
-android_dataspace SurfaceFlinger::bestTargetDataSpace(android_dataspace a, android_dataspace b) {
+android_dataspace SurfaceFlinger::bestTargetDataSpace(
+        android_dataspace a, android_dataspace b) const {
     // Only support sRGB and Display-P3 right now.
     if (a == HAL_DATASPACE_DISPLAY_P3 || b == HAL_DATASPACE_DISPLAY_P3) {
         return HAL_DATASPACE_DISPLAY_P3;
     }
+    if (a == HAL_DATASPACE_V0_SCRGB_LINEAR || b == HAL_DATASPACE_V0_SCRGB_LINEAR) {
+        return HAL_DATASPACE_DISPLAY_P3;
+    }
+    if (a == HAL_DATASPACE_V0_SCRGB || b == HAL_DATASPACE_V0_SCRGB) {
+        return HAL_DATASPACE_DISPLAY_P3;
+    }
+
     return HAL_DATASPACE_V0_SRGB;
 }
 
@@ -1776,7 +1839,7 @@
     }
 
 
-    mat4 colorMatrix = mColorMatrix * mDaltonizer();
+    mat4 colorMatrix = mColorMatrix * computeSaturationMatrix() * mDaltonizer();
 
     // Set the per-frame data
     for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
@@ -1807,7 +1870,12 @@
             }
             newColorMode = pickColorMode(newDataSpace);
 
-            setActiveColorModeInternal(displayDevice, newColorMode);
+            // We want the color mode of the boot animation to match that of the bootloader
+            // To achieve this we suppress color mode changes until after the boot animation
+            if (mBootFinished) {
+                setActiveColorModeInternal(displayDevice, newColorMode);
+                displayDevice->setCompositionDataSpace(newDataSpace);
+            }
         }
     }
 
@@ -2142,7 +2210,7 @@
                 disp.clear();
                 for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
                     sp<const DisplayDevice> hw(mDisplays[dpy]);
-                    if (hw->getLayerStack() == currentlayerStack) {
+                    if (layer->belongsToDisplay(hw->getLayerStack(), hw->isPrimary())) {
                         if (disp == NULL) {
                             disp = hw;
                         } else {
@@ -2191,7 +2259,7 @@
                 // TODO: we could cache the transformed region
                 Region visibleReg;
                 visibleReg.set(layer->computeScreenBounds());
-                invalidateLayerStack(layer->getLayerStack(), visibleReg);
+                invalidateLayerStack(layer, visibleReg);
             }
         });
     }
@@ -2240,7 +2308,7 @@
     mTransactionCV.broadcast();
 }
 
-void SurfaceFlinger::computeVisibleRegions(uint32_t layerStack,
+void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
         Region& outDirtyRegion, Region& outOpaqueRegion)
 {
     ATRACE_CALL();
@@ -2257,7 +2325,7 @@
         const Layer::State& s(layer->getDrawingState());
 
         // only consider the layers on the given layer stack
-        if (layer->getLayerStack() != layerStack)
+        if (!layer->belongsToDisplay(displayDevice->getLayerStack(), displayDevice->isPrimary()))
             return;
 
         /*
@@ -2372,11 +2440,10 @@
     outOpaqueRegion = aboveOpaqueLayers;
 }
 
-void SurfaceFlinger::invalidateLayerStack(uint32_t layerStack,
-        const Region& dirty) {
+void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty) {
     for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
         const sp<DisplayDevice>& hw(mDisplays[dpy]);
-        if (hw->getLayerStack() == layerStack) {
+        if (layer->belongsToDisplay(hw->getLayerStack(), hw->isPrimary())) {
             hw->dirtyRegion.orSelf(dirty);
         }
     }
@@ -2417,8 +2484,8 @@
     for (auto& layer : mLayersWithQueuedFrames) {
         const Region dirty(layer->latchBuffer(visibleRegions, latchTime));
         layer->useSurfaceDamage();
-        invalidateLayerStack(layer->getLayerStack(), dirty);
-        if (!dirty.isEmpty()) {
+        invalidateLayerStack(layer, dirty);
+        if (layer->isBufferLatched()) {
             newDataLatched = true;
         }
     }
@@ -2428,7 +2495,7 @@
     // If we will need to wake up at some time in the future to deal with a
     // queued frame that shouldn't be displayed during this vsync period, wake
     // up during the next vsync period to check again.
-    if (frameQueued && mLayersWithQueuedFrames.empty()) {
+    if (frameQueued && (mLayersWithQueuedFrames.empty() || !newDataLatched)) {
         signalLayerUpdate();
     }
 
@@ -2512,8 +2579,8 @@
         ALOGV("hasClientComposition");
 
 #ifdef USE_HWC2
-        mRenderEngine->setColorMode(displayDevice->getActiveColorMode());
         mRenderEngine->setWideColor(displayDevice->getWideColorSupport());
+        mRenderEngine->setColorMode(displayDevice->getActiveColorMode());
 #endif
         if (!displayDevice->makeCurrent(mEGLDisplay, mEGLContext)) {
             ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
@@ -2656,6 +2723,8 @@
     {
         Mutex::Autolock _l(mStateLock);
         if (mNumLayers >= MAX_LAYERS) {
+            ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers,
+                  MAX_LAYERS);
             return NO_MEMORY;
         }
         if (parent == nullptr) {
@@ -2792,10 +2861,12 @@
         }
     }
 
-    // If a synchronous transaction is explicitly requested without any changes,
-    // force a transaction anyway. This can be used as a flush mechanism for
-    // previous async transactions.
-    if (transactionFlags == 0 && (flags & eSynchronous)) {
+    // If a synchronous transaction is explicitly requested without any changes, force a transaction
+    // anyway. This can be used as a flush mechanism for previous async transactions.
+    // Empty animation transaction can be used to simulate back-pressure, so also force a
+    // transaction for empty animation transactions.
+    if (transactionFlags == 0 &&
+            ((flags & eSynchronous) || (flags & eAnimation))) {
         transactionFlags = eTransactionNeeded;
     }
 
@@ -3037,6 +3108,13 @@
         return result;
     }
 
+    // window type is WINDOW_TYPE_DONT_SCREENSHOT from SurfaceControl.java
+    // TODO b/64227542
+    if (windowType == 441731) {
+        windowType = 2024; // TYPE_NAVIGATION_BAR_PANEL
+        layer->setPrimaryDisplayOnly();
+    }
+
     layer->setInfo(windowType, ownerUid);
 
     result = addClientLayer(client, *handle, *gbp, layer, *parent);
@@ -3209,7 +3287,8 @@
     if (currentMode == HWC_POWER_MODE_OFF) {
         // Turn on the display
         getHwComposer().setPowerMode(type, mode);
-        if (type == DisplayDevice::DISPLAY_PRIMARY) {
+        if (type == DisplayDevice::DISPLAY_PRIMARY &&
+            mode != HWC_POWER_MODE_DOZE_SUSPEND) {
             // FIXME: eventthread only knows about the main display right now
             mEventThread->onScreenAcquired();
             resyncToHardwareVsync(true);
@@ -3241,7 +3320,25 @@
         getHwComposer().setPowerMode(type, mode);
         mVisibleRegionsDirty = true;
         // from this point on, SF will stop drawing on this display
+    } else if (mode == HWC_POWER_MODE_DOZE ||
+               mode == HWC_POWER_MODE_NORMAL) {
+        // Update display while dozing
+        getHwComposer().setPowerMode(type, mode);
+        if (type == DisplayDevice::DISPLAY_PRIMARY) {
+            // FIXME: eventthread only knows about the main display right now
+            mEventThread->onScreenAcquired();
+            resyncToHardwareVsync(true);
+        }
+    } else if (mode == HWC_POWER_MODE_DOZE_SUSPEND) {
+        // Leave display going to doze
+        if (type == DisplayDevice::DISPLAY_PRIMARY) {
+            disableHardwareVsync(true); // also cancels any in-progress resync
+            // FIXME: eventthread only knows about the main display right now
+            mEventThread->onScreenReleased();
+        }
+        getHwComposer().setPowerMode(type, mode);
     } else {
+        ALOGE("Attempting to set unknown power mode: %d\n", mode);
         getHwComposer().setPowerMode(type, mode);
     }
 }
@@ -3710,6 +3807,15 @@
      */
     const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
     alloc.dump(result);
+
+    /*
+     * Dump VrFlinger state if in use.
+     */
+    if (mVrFlingerRequestsDisplay && mVrFlinger) {
+        result.append("VrFlinger state:\n");
+        result.append(mVrFlinger->Dump().c_str());
+        result.append("\n");
+    }
 }
 
 const Vector< sp<Layer> >&
@@ -3808,10 +3914,11 @@
     status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags);
     if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {
         CHECK_INTERFACE(ISurfaceComposer, data, reply);
-        if (CC_UNLIKELY(!PermissionCache::checkCallingPermission(sHardwareTest))) {
-            IPCThreadState* ipc = IPCThreadState::self();
+        IPCThreadState* ipc = IPCThreadState::self();
+        const int uid = ipc->getCallingUid();
+        if (CC_UNLIKELY(uid != AID_SYSTEM
+                && !PermissionCache::checkCallingPermission(sHardwareTest))) {
             const int pid = ipc->getCallingPid();
-            const int uid = ipc->getCallingUid();
             ALOGE("Permission Denial: "
                     "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
             return PERMISSION_DENIED;
@@ -3896,9 +4003,7 @@
                 // apply a color matrix
                 n = data.readInt32();
                 if (n) {
-                    // color matrix is sent as mat3 matrix followed by vec3
-                    // offset, then packed into a mat4 where the last row is
-                    // the offset and extra values are 0
+                    // color matrix is sent as a column-major mat4 matrix
                     for (size_t i = 0 ; i < 4; i++) {
                         for (size_t j = 0; j < 4; j++) {
                             mColorMatrix[i][j] = data.readFloat();
@@ -3907,6 +4012,14 @@
                 } else {
                     mColorMatrix = mat4();
                 }
+
+                // Check that supplied matrix's last row is {0,0,0,1} so we can avoid
+                // the division by w in the fragment shader
+                float4 lastRow(transpose(mColorMatrix)[3]);
+                if (any(greaterThan(abs(lastRow - float4{0, 0, 0, 1}), float4{1e-4f}))) {
+                    ALOGE("The color transform's last row must be (0, 0, 0, 1)");
+                }
+
                 invalidateHwcGeometry();
                 repaintEverything();
                 return NO_ERROR;
@@ -3950,6 +4063,13 @@
                 mUseHwcVirtualDisplays = !n;
                 return NO_ERROR;
             }
+            case 1022: { // Set saturation boost
+                mSaturation = std::max(0.0f, std::min(data.readFloat(), 2.0f));
+
+                invalidateHwcGeometry();
+                repaintEverything();
+                return NO_ERROR;
+            }
         }
     }
     return err;
@@ -3960,128 +4080,88 @@
     signalTransaction();
 }
 
-// ---------------------------------------------------------------------------
-// Capture screen into an IGraphiBufferProducer
-// ---------------------------------------------------------------------------
+// Checks that the requested width and height are valid and updates them to the display dimensions
+// if they are set to 0
+static status_t updateDimensionsLocked(const sp<const DisplayDevice>& displayDevice,
+                                       Transform::orientation_flags rotation,
+                                       uint32_t* requestedWidth, uint32_t* requestedHeight) {
+    // get screen geometry
+    uint32_t displayWidth = displayDevice->getWidth();
+    uint32_t displayHeight = displayDevice->getHeight();
 
-/* The code below is here to handle b/8734824
- *
- * We create a IGraphicBufferProducer wrapper that forwards all calls
- * from the surfaceflinger thread to the calling binder thread, where they
- * are executed. This allows the calling thread in the calling process to be
- * reused and not depend on having "enough" binder threads to handle the
- * requests.
- */
-class GraphicProducerWrapper : public BBinder, public MessageHandler {
-    /* Parts of GraphicProducerWrapper are run on two different threads,
-     * communicating by sending messages via Looper but also by shared member
-     * data. Coherence maintenance is subtle and in places implicit (ugh).
-     *
-     * Don't rely on Looper's sendMessage/handleMessage providing
-     * release/acquire semantics for any data not actually in the Message.
-     * Data going from surfaceflinger to binder threads needs to be
-     * synchronized explicitly.
-     *
-     * Barrier open/wait do provide release/acquire semantics. This provides
-     * implicit synchronization for data coming back from binder to
-     * surfaceflinger threads.
-     */
-
-    sp<IGraphicBufferProducer> impl;
-    sp<Looper> looper;
-    status_t result;
-    bool exitPending;
-    bool exitRequested;
-    Barrier barrier;
-    uint32_t code;
-    Parcel const* data;
-    Parcel* reply;
-
-    enum {
-        MSG_API_CALL,
-        MSG_EXIT
-    };
-
-    /*
-     * Called on surfaceflinger thread. This is called by our "fake"
-     * BpGraphicBufferProducer. We package the data and reply Parcel and
-     * forward them to the binder thread.
-     */
-    virtual status_t transact(uint32_t code,
-            const Parcel& data, Parcel* reply, uint32_t /* flags */) {
-        this->code = code;
-        this->data = &data;
-        this->reply = reply;
-        if (exitPending) {
-            // if we've exited, we run the message synchronously right here.
-            // note (JH): as far as I can tell from looking at the code, this
-            // never actually happens. if it does, i'm not sure if it happens
-            // on the surfaceflinger or binder thread.
-            handleMessage(Message(MSG_API_CALL));
-        } else {
-            barrier.close();
-            // Prevent stores to this->{code, data, reply} from being
-            // reordered later than the construction of Message.
-            atomic_thread_fence(memory_order_release);
-            looper->sendMessage(this, Message(MSG_API_CALL));
-            barrier.wait();
-        }
-        return result;
+    if (rotation & Transform::ROT_90) {
+        std::swap(displayWidth, displayHeight);
     }
 
-    /*
-     * here we run on the binder thread. All we've got to do is
-     * call the real BpGraphicBufferProducer.
-     */
-    virtual void handleMessage(const Message& message) {
-        int what = message.what;
-        // Prevent reads below from happening before the read from Message
-        atomic_thread_fence(memory_order_acquire);
-        if (what == MSG_API_CALL) {
-            result = IInterface::asBinder(impl)->transact(code, data[0], reply);
-            barrier.open();
-        } else if (what == MSG_EXIT) {
-            exitRequested = true;
-        }
+    if ((*requestedWidth > displayWidth) || (*requestedHeight > displayHeight)) {
+        ALOGE("size mismatch (%d, %d) > (%d, %d)",
+                *requestedWidth, *requestedHeight, displayWidth, displayHeight);
+        return BAD_VALUE;
     }
 
+    if (*requestedWidth == 0) {
+        *requestedWidth = displayWidth;
+    }
+    if (*requestedHeight == 0) {
+        *requestedHeight = displayHeight;
+    }
+
+    return NO_ERROR;
+}
+
+// A simple RAII class to disconnect from an ANativeWindow* when it goes out of scope
+class WindowDisconnector {
 public:
-    explicit GraphicProducerWrapper(const sp<IGraphicBufferProducer>& impl)
-    :   impl(impl),
-        looper(new Looper(true)),
-        result(NO_ERROR),
-        exitPending(false),
-        exitRequested(false),
-        code(0),
-        data(NULL),
-        reply(NULL)
-    {}
-
-    // Binder thread
-    status_t waitForResponse() {
-        do {
-            looper->pollOnce(-1);
-        } while (!exitRequested);
-        return result;
+    WindowDisconnector(ANativeWindow* window, int api) : mWindow(window), mApi(api) {}
+    ~WindowDisconnector() {
+        native_window_api_disconnect(mWindow, mApi);
     }
 
-    // Client thread
-    void exit(status_t result) {
-        this->result = result;
-        exitPending = true;
-        // Ensure this->result is visible to the binder thread before it
-        // handles the message.
-        atomic_thread_fence(memory_order_release);
-        looper->sendMessage(this, Message(MSG_EXIT));
-    }
+private:
+    ANativeWindow* mWindow;
+    const int mApi;
 };
 
+static status_t getWindowBuffer(ANativeWindow* window, uint32_t requestedWidth,
+                                uint32_t requestedHeight, bool hasWideColorDisplay,
+                                bool renderEngineUsesWideColor, ANativeWindowBuffer** outBuffer) {
+    const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
+            GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
+
+    int err = 0;
+    err = native_window_set_buffers_dimensions(window, requestedWidth, requestedHeight);
+    err |= native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+    err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888);
+    err |= native_window_set_usage(window, usage);
+
+    if (hasWideColorDisplay) {
+        err |= native_window_set_buffers_data_space(window,
+                                                    renderEngineUsesWideColor
+                                                            ? HAL_DATASPACE_DISPLAY_P3
+                                                            : HAL_DATASPACE_V0_SRGB);
+    }
+
+    if (err != NO_ERROR) {
+        return BAD_VALUE;
+    }
+
+    /* TODO: Once we have the sync framework everywhere this can use
+     * server-side waits on the fence that dequeueBuffer returns.
+     */
+    err = native_window_dequeue_buffer_and_wait(window, outBuffer);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    return NO_ERROR;
+}
 
 status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
         const sp<IGraphicBufferProducer>& producer,
         Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
         int32_t minLayerZ, int32_t maxLayerZ,
         bool useIdentityTransform, ISurfaceComposer::Rotation rotation) {
+    ATRACE_CALL();
 
     if (CC_UNLIKELY(display == 0))
         return BAD_VALUE;
@@ -4115,65 +4195,95 @@
             break;
     }
 
-    class MessageCaptureScreen : public MessageBase {
-        SurfaceFlinger* flinger;
-        sp<IBinder> display;
-        sp<IGraphicBufferProducer> producer;
-        Rect sourceCrop;
-        uint32_t reqWidth, reqHeight;
-        uint32_t minLayerZ,maxLayerZ;
-        bool useIdentityTransform;
-        Transform::orientation_flags rotation;
-        status_t result;
-        bool isLocalScreenshot;
-    public:
-        MessageCaptureScreen(SurfaceFlinger* flinger,
-                const sp<IBinder>& display,
-                const sp<IGraphicBufferProducer>& producer,
-                Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-                int32_t minLayerZ, int32_t maxLayerZ,
-                bool useIdentityTransform,
-                Transform::orientation_flags rotation,
-                bool isLocalScreenshot)
-            : flinger(flinger), display(display), producer(producer),
-              sourceCrop(sourceCrop), reqWidth(reqWidth), reqHeight(reqHeight),
-              minLayerZ(minLayerZ), maxLayerZ(maxLayerZ),
-              useIdentityTransform(useIdentityTransform),
-              rotation(rotation), result(PERMISSION_DENIED),
-              isLocalScreenshot(isLocalScreenshot)
-        {
-        }
-        status_t getResult() const {
-            return result;
-        }
-        virtual bool handler() {
-            Mutex::Autolock _l(flinger->mStateLock);
-            sp<const DisplayDevice> hw(flinger->getDisplayDeviceLocked(display));
-            result = flinger->captureScreenImplLocked(hw, producer,
-                    sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
-                    useIdentityTransform, rotation, isLocalScreenshot);
-            static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result);
-            return true;
-        }
-    };
-
-    // this creates a "fake" BBinder which will serve as a "fake" remote
-    // binder to receive the marshaled calls and forward them to the
-    // real remote (a BpGraphicBufferProducer)
-    sp<GraphicProducerWrapper> wrapper = new GraphicProducerWrapper(producer);
-
-    // the asInterface() call below creates our "fake" BpGraphicBufferProducer
-    // which does the marshaling work forwards to our "fake remote" above.
-    sp<MessageBase> msg = new MessageCaptureScreen(this,
-            display, IGraphicBufferProducer::asInterface( wrapper ),
-            sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
-            useIdentityTransform, rotationFlags, isLocalScreenshot);
-
-    status_t res = postMessageAsync(msg);
-    if (res == NO_ERROR) {
-        res = wrapper->waitForResponse();
+    { // Autolock scope
+        Mutex::Autolock lock(mStateLock);
+        sp<const DisplayDevice> displayDevice(getDisplayDeviceLocked(display));
+        updateDimensionsLocked(displayDevice, rotationFlags, &reqWidth, &reqHeight);
     }
-    return res;
+
+    // create a surface (because we're a producer, and we need to
+    // dequeue/queue a buffer)
+    sp<Surface> surface = new Surface(producer, false);
+
+    // Put the screenshot Surface into async mode so that
+    // Layer::headFenceHasSignaled will always return true and we'll latch the
+    // first buffer regardless of whether or not its acquire fence has
+    // signaled. This is needed to avoid a race condition in the rotation
+    // animation. See b/30209608
+    surface->setAsyncMode(true);
+
+    ANativeWindow* window = surface.get();
+
+    status_t result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
+    if (result != NO_ERROR) {
+        return result;
+    }
+    WindowDisconnector disconnector(window, NATIVE_WINDOW_API_EGL);
+
+    ANativeWindowBuffer* buffer = nullptr;
+    result = getWindowBuffer(window, reqWidth, reqHeight, hasWideColorDisplay,
+                                      getRenderEngine().usesWideColor(), &buffer);
+    if (result != NO_ERROR) {
+        return result;
+    }
+
+    // This mutex protects syncFd and captureResult for communication of the return values from the
+    // main thread back to this Binder thread
+    std::mutex captureMutex;
+    std::condition_variable captureCondition;
+    std::unique_lock<std::mutex> captureLock(captureMutex);
+    int syncFd = -1;
+    std::optional<status_t> captureResult;
+
+    sp<LambdaMessage> message = new LambdaMessage([&]() {
+        // If there is a refresh pending, bug out early and tell the binder thread to try again
+        // after the refresh.
+        if (mRefreshPending) {
+            ATRACE_NAME("Skipping screenshot for now");
+            std::unique_lock<std::mutex> captureLock(captureMutex);
+            captureResult = std::make_optional<status_t>(EAGAIN);
+            captureCondition.notify_one();
+            return;
+        }
+
+        status_t result = NO_ERROR;
+        int fd = -1;
+        {
+            Mutex::Autolock _l(mStateLock);
+            sp<const DisplayDevice> device(getDisplayDeviceLocked(display));
+            result = captureScreenImplLocked(device, buffer, sourceCrop, reqWidth, reqHeight,
+                                             minLayerZ, maxLayerZ, useIdentityTransform,
+                                             rotationFlags, isLocalScreenshot, &fd);
+        }
+
+        {
+            std::unique_lock<std::mutex> captureLock(captureMutex);
+            syncFd = fd;
+            captureResult = std::make_optional<status_t>(result);
+            captureCondition.notify_one();
+        }
+    });
+
+    result = postMessageAsync(message);
+    if (result == NO_ERROR) {
+        captureCondition.wait(captureLock, [&]() { return captureResult; });
+        while (*captureResult == EAGAIN) {
+            captureResult.reset();
+            result = postMessageAsync(message);
+            if (result != NO_ERROR) {
+                return result;
+            }
+            captureCondition.wait(captureLock, [&]() { return captureResult; });
+        }
+        result = *captureResult;
+    }
+
+    if (result == NO_ERROR) {
+        // queueBuffer takes ownership of syncFd
+        result = window->queueBuffer(window, buffer, syncFd);
+    }
+
+    return result;
 }
 
 
@@ -4213,6 +4323,11 @@
         ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, hw_h);
     }
 
+#ifdef USE_HWC2
+     engine.setWideColor(hw->getWideColorSupport());
+     engine.setColorMode(hw->getActiveColorMode());
+#endif
+
     // make sure to clear all GL error flags
     engine.checkErrors();
 
@@ -4227,7 +4342,7 @@
     // We loop through the first level of layers without traversing,
     // as we need to interpret min/max layer Z in the top level Z space.
     for (const auto& layer : mDrawingState.layersSortedByZ) {
-        if (layer->getLayerStack() != hw->getLayerStack()) {
+        if (!layer->belongsToDisplay(hw->getLayerStack(), false)) {
             continue;
         }
         const Layer::State& state(layer->getDrawingState());
@@ -4247,38 +4362,39 @@
     hw->setViewportAndProjection();
 }
 
+// A simple RAII class that holds an EGLImage and destroys it either:
+//   a) When the destroy() method is called
+//   b) When the object goes out of scope
+class ImageHolder {
+public:
+    ImageHolder(EGLDisplay display, EGLImageKHR image) : mDisplay(display), mImage(image) {}
+    ~ImageHolder() { destroy(); }
 
-status_t SurfaceFlinger::captureScreenImplLocked(
-        const sp<const DisplayDevice>& hw,
-        const sp<IGraphicBufferProducer>& producer,
-        Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-        int32_t minLayerZ, int32_t maxLayerZ,
-        bool useIdentityTransform, Transform::orientation_flags rotation,
-        bool isLocalScreenshot)
-{
+    void destroy() {
+        if (mImage != EGL_NO_IMAGE_KHR) {
+            eglDestroyImageKHR(mDisplay, mImage);
+            mImage = EGL_NO_IMAGE_KHR;
+        }
+    }
+
+private:
+    const EGLDisplay mDisplay;
+    EGLImageKHR mImage;
+};
+
+status_t SurfaceFlinger::captureScreenImplLocked(const sp<const DisplayDevice>& hw,
+                                                 ANativeWindowBuffer* buffer, Rect sourceCrop,
+                                                 uint32_t reqWidth, uint32_t reqHeight,
+                                                 int32_t minLayerZ, int32_t maxLayerZ,
+                                                 bool useIdentityTransform,
+                                                 Transform::orientation_flags rotation,
+                                                 bool isLocalScreenshot, int* outSyncFd) {
     ATRACE_CALL();
 
-    // get screen geometry
-    uint32_t hw_w = hw->getWidth();
-    uint32_t hw_h = hw->getHeight();
-
-    if (rotation & Transform::ROT_90) {
-        std::swap(hw_w, hw_h);
-    }
-
-    if ((reqWidth > hw_w) || (reqHeight > hw_h)) {
-        ALOGE("size mismatch (%d, %d) > (%d, %d)",
-                reqWidth, reqHeight, hw_w, hw_h);
-        return BAD_VALUE;
-    }
-
-    reqWidth  = (!reqWidth)  ? hw_w : reqWidth;
-    reqHeight = (!reqHeight) ? hw_h : reqHeight;
-
     bool secureLayerIsVisible = false;
     for (const auto& layer : mDrawingState.layersSortedByZ) {
         const Layer::State& state(layer->getDrawingState());
-        if ((layer->getLayerStack() != hw->getLayerStack()) ||
+        if (!layer->belongsToDisplay(hw->getLayerStack(), false) ||
                 (state.z < minLayerZ || state.z > maxLayerZ)) {
             continue;
         }
@@ -4293,123 +4409,84 @@
         return PERMISSION_DENIED;
     }
 
-    // create a surface (because we're a producer, and we need to
-    // dequeue/queue a buffer)
-    sp<Surface> sur = new Surface(producer, false);
-
-    // Put the screenshot Surface into async mode so that
-    // Layer::headFenceHasSignaled will always return true and we'll latch the
-    // first buffer regardless of whether or not its acquire fence has
-    // signaled. This is needed to avoid a race condition in the rotation
-    // animation. See b/30209608
-    sur->setAsyncMode(true);
-
-    ANativeWindow* window = sur.get();
-
-    status_t result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
-    if (result == NO_ERROR) {
-        uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
-                        GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
-
-        int err = 0;
-        err = native_window_set_buffers_dimensions(window, reqWidth, reqHeight);
-        err |= native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
-        err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888);
-        err |= native_window_set_usage(window, usage);
-
-        if (err == NO_ERROR) {
-            ANativeWindowBuffer* buffer;
-            /* TODO: Once we have the sync framework everywhere this can use
-             * server-side waits on the fence that dequeueBuffer returns.
-             */
-            result = native_window_dequeue_buffer_and_wait(window,  &buffer);
-            if (result == NO_ERROR) {
-                int syncFd = -1;
-                // create an EGLImage from the buffer so we can later
-                // turn it into a texture
-                EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT,
-                        EGL_NATIVE_BUFFER_ANDROID, buffer, NULL);
-                if (image != EGL_NO_IMAGE_KHR) {
-                    // this binds the given EGLImage as a framebuffer for the
-                    // duration of this scope.
-                    RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image);
-                    if (imageBond.getStatus() == NO_ERROR) {
-                        // this will in fact render into our dequeued buffer
-                        // via an FBO, which means we didn't have to create
-                        // an EGLSurface and therefore we're not
-                        // dependent on the context's EGLConfig.
-                        renderScreenImplLocked(
-                            hw, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, true,
-                            useIdentityTransform, rotation);
-
-                        // Attempt to create a sync khr object that can produce a sync point. If that
-                        // isn't available, create a non-dupable sync object in the fallback path and
-                        // wait on it directly.
-                        EGLSyncKHR sync;
-                        if (!DEBUG_SCREENSHOTS) {
-                           sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
-                           // native fence fd will not be populated until flush() is done.
-                           getRenderEngine().flush();
-                        } else {
-                            sync = EGL_NO_SYNC_KHR;
-                        }
-                        if (sync != EGL_NO_SYNC_KHR) {
-                            // get the sync fd
-                            syncFd = eglDupNativeFenceFDANDROID(mEGLDisplay, sync);
-                            if (syncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
-                                ALOGW("captureScreen: failed to dup sync khr object");
-                                syncFd = -1;
-                            }
-                            eglDestroySyncKHR(mEGLDisplay, sync);
-                        } else {
-                            // fallback path
-                            sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, NULL);
-                            if (sync != EGL_NO_SYNC_KHR) {
-                                EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync,
-                                    EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, 2000000000 /*2 sec*/);
-                                EGLint eglErr = eglGetError();
-                                if (result == EGL_TIMEOUT_EXPIRED_KHR) {
-                                    ALOGW("captureScreen: fence wait timed out");
-                                } else {
-                                    ALOGW_IF(eglErr != EGL_SUCCESS,
-                                            "captureScreen: error waiting on EGL fence: %#x", eglErr);
-                                }
-                                eglDestroySyncKHR(mEGLDisplay, sync);
-                            } else {
-                                ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
-                            }
-                        }
-                        if (DEBUG_SCREENSHOTS) {
-                            uint32_t* pixels = new uint32_t[reqWidth*reqHeight];
-                            getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels);
-                            checkScreenshot(reqWidth, reqHeight, reqWidth, pixels,
-                                    hw, minLayerZ, maxLayerZ);
-                            delete [] pixels;
-                        }
-
-                    } 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;
-                }
-                if (buffer) {
-                    // queueBuffer takes ownership of syncFd
-                    result = window->queueBuffer(window, buffer, syncFd);
-                }
-            }
-        } else {
-            result = BAD_VALUE;
-        }
-        native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+    int syncFd = -1;
+    // create an EGLImage from the buffer so we can later
+    // turn it into a texture
+    EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT,
+            EGL_NATIVE_BUFFER_ANDROID, buffer, NULL);
+    if (image == EGL_NO_IMAGE_KHR) {
+        return BAD_VALUE;
     }
 
-    return result;
+    // This will automatically destroy the image if we return before calling its destroy method
+    ImageHolder imageHolder(mEGLDisplay, image);
+
+    // this binds the given EGLImage as a framebuffer for the
+    // duration of this scope.
+    RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image);
+    if (imageBond.getStatus() != NO_ERROR) {
+        ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES error while taking screenshot");
+        return INVALID_OPERATION;
+    }
+
+    // this will in fact render into our dequeued buffer
+    // via an FBO, which means we didn't have to create
+    // an EGLSurface and therefore we're not
+    // dependent on the context's EGLConfig.
+    renderScreenImplLocked(
+        hw, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, true,
+        useIdentityTransform, rotation);
+
+    // Attempt to create a sync khr object that can produce a sync point. If that
+    // isn't available, create a non-dupable sync object in the fallback path and
+    // wait on it directly.
+    EGLSyncKHR sync = EGL_NO_SYNC_KHR;
+    if (!DEBUG_SCREENSHOTS) {
+       sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
+       // native fence fd will not be populated until flush() is done.
+       getRenderEngine().flush();
+    }
+
+    if (sync != EGL_NO_SYNC_KHR) {
+        // get the sync fd
+        syncFd = eglDupNativeFenceFDANDROID(mEGLDisplay, sync);
+        if (syncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+            ALOGW("captureScreen: failed to dup sync khr object");
+            syncFd = -1;
+        }
+        eglDestroySyncKHR(mEGLDisplay, sync);
+    } else {
+        // fallback path
+        sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, NULL);
+        if (sync != EGL_NO_SYNC_KHR) {
+            EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync,
+                EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, 2000000000 /*2 sec*/);
+            EGLint eglErr = eglGetError();
+            if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+                ALOGW("captureScreen: fence wait timed out");
+            } else {
+                ALOGW_IF(eglErr != EGL_SUCCESS,
+                        "captureScreen: error waiting on EGL fence: %#x", eglErr);
+            }
+            eglDestroySyncKHR(mEGLDisplay, sync);
+        } else {
+            ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
+        }
+    }
+    *outSyncFd = syncFd;
+
+    if (DEBUG_SCREENSHOTS) {
+        uint32_t* pixels = new uint32_t[reqWidth*reqHeight];
+        getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels);
+        checkScreenshot(reqWidth, reqHeight, reqWidth, pixels,
+                hw, minLayerZ, maxLayerZ);
+        delete [] pixels;
+    }
+
+    // destroy our image
+    imageHolder.destroy();
+
+    return NO_ERROR;
 }
 
 void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr,
@@ -4428,7 +4505,7 @@
         size_t i = 0;
         for (const auto& layer : mDrawingState.layersSortedByZ) {
             const Layer::State& state(layer->getDrawingState());
-            if (layer->getLayerStack() == hw->getLayerStack() && state.z >= minLayerZ &&
+            if (layer->belongsToDisplay(hw->getLayerStack(), false) && state.z >= minLayerZ &&
                     state.z <= maxLayerZ) {
                 layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
                     ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%.3f",
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 9239538..acfad46 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -58,7 +58,7 @@
 #include "LayerVector.h"
 #include "MessageQueue.h"
 #include "SurfaceInterceptor.h"
-#include "StartBootAnimThread.h"
+#include "StartPropertySetThread.h"
 
 #include "DisplayHardware/HWComposer.h"
 #include "Effects/Daltonizer.h"
@@ -227,7 +227,6 @@
     enum { LOG_FRAME_STATS_PERIOD =  30*60*60 };
 
     static const size_t MAX_LAYERS = 4096;
-    static constexpr const char* kTimestampProperty = "service.sf.present_timestamp";
 
     // We're reference counted, never destroy SurfaceFlinger directly
     virtual ~SurfaceFlinger();
@@ -417,6 +416,14 @@
             int32_t minLayerZ, int32_t maxLayerZ,
             bool yswap, bool useIdentityTransform, Transform::orientation_flags rotation);
 
+#ifdef USE_HWC2
+    status_t captureScreenImplLocked(const sp<const DisplayDevice>& device,
+                                     ANativeWindowBuffer* buffer, Rect sourceCrop,
+                                     uint32_t reqWidth, uint32_t reqHeight, int32_t minLayerZ,
+                                     int32_t maxLayerZ, bool useIdentityTransform,
+                                     Transform::orientation_flags rotation, bool isLocalScreenshot,
+                                     int* outSyncFd);
+#else
     status_t captureScreenImplLocked(
             const sp<const DisplayDevice>& hw,
             const sp<IGraphicBufferProducer>& producer,
@@ -424,8 +431,14 @@
             int32_t minLayerZ, int32_t maxLayerZ,
             bool useIdentityTransform, Transform::orientation_flags rotation,
             bool isLocalScreenshot);
+#endif
 
-    sp<StartBootAnimThread> mStartBootAnimThread = nullptr;
+    sp<StartPropertySetThread> mStartPropertySetThread = nullptr;
+
+    /* ------------------------------------------------------------------------
+     * Properties
+     */
+    void readPersistentProperties();
 
     /* ------------------------------------------------------------------------
      * EGL
@@ -481,7 +494,7 @@
 
     // mark a region of a layer stack dirty. this updates the dirty
     // region of all screens presenting this layer stack.
-    void invalidateLayerStack(uint32_t layerStack, const Region& dirty);
+    void invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty);
 
 #ifndef USE_HWC2
     int32_t allocateHwcDisplayId(DisplayDevice::DisplayType type);
@@ -497,7 +510,7 @@
      * Compositing
      */
     void invalidateHwcGeometry();
-    void computeVisibleRegions(uint32_t layerStack,
+    void computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
             Region& dirtyRegion, Region& opaqueRegion);
 
     void preComposition(nsecs_t refreshStartTime);
@@ -512,8 +525,10 @@
 
     // Given a dataSpace, returns the appropriate color_mode to use
     // to display that dataSpace.
-    android_color_mode pickColorMode(android_dataspace dataSpace);
-    android_dataspace bestTargetDataSpace(android_dataspace a, android_dataspace b);
+    android_color_mode pickColorMode(android_dataspace dataSpace) const;
+    android_dataspace bestTargetDataSpace(android_dataspace a, android_dataspace b) const;
+
+    mat4 computeSaturationMatrix() const;
 
     void setUpHWComposer();
     void doComposition();
@@ -575,7 +590,12 @@
     /* ------------------------------------------------------------------------
      * VrFlinger
      */
-    void clearHwcLayers(const LayerVector& layers);
+    template<typename T>
+    void clearHwcLayers(const T& layers) {
+        for (size_t i = 0; i < layers.size(); ++i) {
+            layers[i]->clearHwcLayers();
+        }
+    }
     void resetHwcLocked();
 
     // Check to see if we should handoff to vr flinger.
@@ -693,6 +713,8 @@
     };
     std::queue<CompositePresentTime> mCompositePresentTimes;
 
+    std::atomic<bool> mRefreshPending{false};
+
     /* ------------------------------------------------------------------------
      * Feature prototyping
      */
@@ -748,7 +770,9 @@
     std::atomic<bool> mVrFlingerRequestsDisplay;
     static bool useVrFlinger;
 #endif
-    };
+
+    float mSaturation = 1.0f;
+};
 }; // namespace android
 
 #endif // ANDROID_SURFACE_FLINGER_H
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 0904fab..247d80b 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -320,8 +320,8 @@
 
 void SurfaceFlinger::bootFinished()
 {
-    if (mStartBootAnimThread->join() != NO_ERROR) {
-        ALOGE("Join StartBootAnimThread failed!");
+    if (mStartPropertySetThread->join() != NO_ERROR) {
+        ALOGE("Join StartPropertySetThread failed!");
     }
     const nsecs_t now = systemTime();
     const nsecs_t duration = now - mBootTime;
@@ -501,6 +501,8 @@
     sp<VSyncSource::Callback> mCallback;
 };
 
+// Do not call property_set on main thread which will be blocked by init
+// Use StartPropertySetThread instead.
 void SurfaceFlinger::init() {
     ALOGI(  "SurfaceFlinger's main thread ready to run. "
             "Initializing graphics H/W...");
@@ -536,7 +538,8 @@
             *static_cast<HWComposer::EventHandler *>(this));
 
     // get a RenderEngine for the given display / config (can't fail)
-    mRenderEngine = RenderEngine::create(mEGLDisplay, mHwc->getVisualID());
+    mRenderEngine = RenderEngine::create(mEGLDisplay,
+            mHwc->getVisualID(), 0);
 
     // retrieve the EGL context that was selected/created
     mEGLContext = mRenderEngine->getEGLContext();
@@ -544,9 +547,6 @@
     LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
             "couldn't create EGLContext");
 
-    // Inform native graphics APIs that the present timestamp is NOT supported:
-    property_set(kTimestampProperty, "0");
-
     // initialize our non-virtual displays
     for (size_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
         DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i);
@@ -599,9 +599,10 @@
 
     mRenderEngine->primeCache();
 
-    mStartBootAnimThread = new StartBootAnimThread();
-    if (mStartBootAnimThread->Start() != NO_ERROR) {
-        ALOGE("Run StartBootAnimThread failed!");
+    // Inform native graphics APIs that the present timestamp is NOT supported:
+    mStartPropertySetThread = new StartPropertySetThread(false);
+    if (mStartPropertySetThread->Start() != NO_ERROR) {
+        ALOGE("Run StartPropertySetThread failed!");
     }
 
     ALOGV("Done initializing");
@@ -615,10 +616,10 @@
 void SurfaceFlinger::startBootAnim() {
     // Start boot animation service by setting a property mailbox
     // if property setting thread is already running, Start() will be just a NOP
-    mStartBootAnimThread->Start();
+    mStartPropertySetThread->Start();
     // Wait until property was set
-    if (mStartBootAnimThread->join() != NO_ERROR) {
-        ALOGE("Join StartBootAnimThread failed!");
+    if (mStartPropertySetThread->join() != NO_ERROR) {
+        ALOGE("Join StartPropertySetThread failed!");
     }
 }
 
@@ -1360,8 +1361,7 @@
             const Transform& tr(hw->getTransform());
             const Rect bounds(hw->getBounds());
             if (hw->isDisplayOn()) {
-                computeVisibleRegions(hw->getLayerStack(), dirtyRegion,
-                        opaqueRegion);
+                computeVisibleRegions(hw, dirtyRegion, opaqueRegion);
 
                 mDrawingState.traverseInZOrder([&](Layer* layer) {
                     if (layer->getLayerStack() == hw->getLayerStack()) {
@@ -1862,7 +1862,7 @@
                 // TODO: we could cache the transformed region
                 Region visibleReg;
                 visibleReg.set(layer->computeScreenBounds());
-                invalidateLayerStack(layer->getLayerStack(), visibleReg);
+                invalidateLayerStack(layer, visibleReg);
             }
         });
     }
@@ -1923,7 +1923,7 @@
     mTransactionCV.broadcast();
 }
 
-void SurfaceFlinger::computeVisibleRegions(uint32_t layerStack,
+void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
         Region& outDirtyRegion, Region& outOpaqueRegion)
 {
     ATRACE_CALL();
@@ -1939,7 +1939,7 @@
         const Layer::State& s(layer->getDrawingState());
 
         // only consider the layers on the given layer stack
-        if (layer->getLayerStack() != layerStack)
+        if (layer->getLayerStack() != displayDevice->getLayerStack())
             return;
 
         /*
@@ -2054,8 +2054,8 @@
     outOpaqueRegion = aboveOpaqueLayers;
 }
 
-void SurfaceFlinger::invalidateLayerStack(uint32_t layerStack,
-        const Region& dirty) {
+void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty) {
+    uint32_t layerStack = layer->getLayerStack();
     for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
         const sp<DisplayDevice>& hw(mDisplays[dpy]);
         if (hw->getLayerStack() == layerStack) {
@@ -2098,7 +2098,7 @@
         Layer* layer = layersWithQueuedFrames[i];
         const Region dirty(layer->latchBuffer(visibleRegions, latchTime));
         layer->useSurfaceDamage();
-        invalidateLayerStack(layer->getLayerStack(), dirty);
+        invalidateLayerStack(layer, dirty);
     }
 
     mVisibleRegionsDirty |= visibleRegions;
@@ -2870,7 +2870,8 @@
     if (currentMode == HWC_POWER_MODE_OFF) {
         // Turn on the display
         getHwComposer().setPowerMode(type, mode);
-        if (type == DisplayDevice::DISPLAY_PRIMARY) {
+        if (type == DisplayDevice::DISPLAY_PRIMARY &&
+            mode != HWC_POWER_MODE_DOZE_SUSPEND) {
             // FIXME: eventthread only knows about the main display right now
             mEventThread->onScreenAcquired();
             resyncToHardwareVsync(true);
@@ -2902,7 +2903,25 @@
         getHwComposer().setPowerMode(type, mode);
         mVisibleRegionsDirty = true;
         // from this point on, SF will stop drawing on this display
+    } else if (mode == HWC_POWER_MODE_DOZE ||
+               mode == HWC_POWER_MODE_NORMAL) {
+        // Update display while dozing
+        getHwComposer().setPowerMode(type, mode);
+        if (type == DisplayDevice::DISPLAY_PRIMARY) {
+            // FIXME: eventthread only knows about the main display right now
+            mEventThread->onScreenAcquired();
+            resyncToHardwareVsync(true);
+        }
+    } else if (mode == HWC_POWER_MODE_DOZE_SUSPEND) {
+        // Leave display going to doze
+        if (type == DisplayDevice::DISPLAY_PRIMARY) {
+            disableHardwareVsync(true); // also cancels any in-progress resync
+            // FIXME: eventthread only knows about the main display right now
+            mEventThread->onScreenReleased();
+        }
+        getHwComposer().setPowerMode(type, mode);
     } else {
+        ALOGE("Attempting to set unknown power mode: %d\n", mode);
         getHwComposer().setPowerMode(type, mode);
     }
 }
diff --git a/services/surfaceflinger/tests/Android.mk b/services/surfaceflinger/tests/Android.mk
index 16041da..43e22a0 100644
--- a/services/surfaceflinger/tests/Android.mk
+++ b/services/surfaceflinger/tests/Android.mk
@@ -4,7 +4,7 @@
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
 LOCAL_MODULE := SurfaceFlinger_test
-
+LOCAL_COMPATIBILITY_SUITE := device-tests
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_SRC_FILES := \
diff --git a/services/surfaceflinger/tests/AndroidTest.xml b/services/surfaceflinger/tests/AndroidTest.xml
new file mode 100644
index 0000000..8315037
--- /dev/null
+++ b/services/surfaceflinger/tests/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<configuration description="Config for SurfaceFlinger_test">
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="SurfaceFlinger_test->/data/local/tmp/SurfaceFlinger_test" />
+    </target_preparer>
+    <option name="test-suite-tag" value="apct" />
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="SurfaceFlinger_test" />
+    </test>
+</configuration>
diff --git a/services/surfaceflinger/tests/vsync/Android.mk b/services/surfaceflinger/tests/vsync/Android.mk
index 9181760..8e41617 100644
--- a/services/surfaceflinger/tests/vsync/Android.mk
+++ b/services/surfaceflinger/tests/vsync/Android.mk
@@ -15,4 +15,6 @@
 
 LOCAL_MODULE_TAGS := tests
 
+LOCAL_CFLAGS := -Werror
+
 include $(BUILD_EXECUTABLE)
diff --git a/services/surfaceflinger/tests/vsync/vsync.cpp b/services/surfaceflinger/tests/vsync/vsync.cpp
index aa72c79..a1b45e6 100644
--- a/services/surfaceflinger/tests/vsync/vsync.cpp
+++ b/services/surfaceflinger/tests/vsync/vsync.cpp
@@ -20,7 +20,7 @@
 
 using namespace android;
 
-int receiver(int fd, int events, void* data)
+int receiver(int /*fd*/, int /*events*/, void* data)
 {
     DisplayEventReceiver* q = (DisplayEventReceiver*)data;
 
@@ -47,7 +47,7 @@
     return 1;
 }
 
-int main(int argc, char** argv)
+int main(int /*argc*/, char** /*argv*/)
 {
     DisplayEventReceiver myDisplayEvent;
 
diff --git a/services/surfaceflinger/tests/waitforvsync/Android.mk b/services/surfaceflinger/tests/waitforvsync/Android.mk
index c25f5ab..932d2be 100644
--- a/services/surfaceflinger/tests/waitforvsync/Android.mk
+++ b/services/surfaceflinger/tests/waitforvsync/Android.mk
@@ -11,4 +11,6 @@
 
 LOCAL_MODULE_TAGS := tests
 
+LOCAL_CFLAGS := -Werror
+
 include $(BUILD_EXECUTABLE)
diff --git a/services/surfaceflinger/tests/waitforvsync/waitforvsync.cpp b/services/surfaceflinger/tests/waitforvsync/waitforvsync.cpp
index b88b04a..65eaae5 100644
--- a/services/surfaceflinger/tests/waitforvsync/waitforvsync.cpp
+++ b/services/surfaceflinger/tests/waitforvsync/waitforvsync.cpp
@@ -29,7 +29,7 @@
 #define FBIO_WAITFORVSYNC   _IOW('F', 0x20, __u32)
 #endif
 
-int main(int argc, char** argv) {
+int main(int /*argc*/, char** /*argv*/) {
     int fd = open("/dev/graphics/fb0", O_RDWR);
     if (fd >= 0) {
         do {
diff --git a/services/vr/bufferhubd/buffer_hub.cpp b/services/vr/bufferhubd/buffer_hub.cpp
index d27f274..26843c9 100644
--- a/services/vr/bufferhubd/buffer_hub.cpp
+++ b/services/vr/bufferhubd/buffer_hub.cpp
@@ -382,7 +382,7 @@
 }
 
 Status<QueueInfo> BufferHubService::OnCreateProducerQueue(
-    pdx::Message& message, size_t meta_size_bytes,
+    pdx::Message& message, const ProducerQueueConfig& producer_config,
     const UsagePolicy& usage_policy) {
   // Use the producer channel id as the global queue id.
   const int queue_id = message.GetChannelId();
@@ -396,11 +396,11 @@
     return ErrorStatus(EALREADY);
   }
 
-  auto status = ProducerQueueChannel::Create(this, queue_id, meta_size_bytes,
+  auto status = ProducerQueueChannel::Create(this, queue_id, producer_config,
                                              usage_policy);
   if (status) {
     message.SetChannel(status.take());
-    return {{meta_size_bytes, queue_id}};
+    return {{producer_config, queue_id}};
   } else {
     ALOGE("BufferHubService::OnCreateBuffer: Failed to create producer!!");
     return status.error_status();
diff --git a/services/vr/bufferhubd/buffer_hub.h b/services/vr/bufferhubd/buffer_hub.h
index 3bc2635..b0df11f 100644
--- a/services/vr/bufferhubd/buffer_hub.h
+++ b/services/vr/bufferhubd/buffer_hub.h
@@ -166,9 +166,9 @@
                                              size_t meta_size_bytes);
   pdx::Status<void> OnGetPersistentBuffer(pdx::Message& message,
                                           const std::string& name);
-  pdx::Status<QueueInfo> OnCreateProducerQueue(pdx::Message& message,
-                                               size_t meta_size_bytes,
-                                               const UsagePolicy& usage_policy);
+  pdx::Status<QueueInfo> OnCreateProducerQueue(
+      pdx::Message& message, const ProducerQueueConfig& producer_config,
+      const UsagePolicy& usage_policy);
 
   BufferHubService(const BufferHubService&) = delete;
   void operator=(const BufferHubService&) = delete;
diff --git a/services/vr/bufferhubd/consumer_channel.cpp b/services/vr/bufferhubd/consumer_channel.cpp
index 08b2790..ac6896a 100644
--- a/services/vr/bufferhubd/consumer_channel.cpp
+++ b/services/vr/bufferhubd/consumer_channel.cpp
@@ -8,9 +8,9 @@
 #include <private/dvr/bufferhub_rpc.h>
 #include "producer_channel.h"
 
-using android::pdx::ErrorStatus;
 using android::pdx::BorrowedHandle;
 using android::pdx::Channel;
+using android::pdx::ErrorStatus;
 using android::pdx::Message;
 using android::pdx::Status;
 using android::pdx::rpc::DispatchRemoteMethod;
@@ -22,8 +22,6 @@
                                  int channel_id,
                                  const std::shared_ptr<Channel> producer)
     : BufferHubChannel(service, buffer_id, channel_id, kConsumerType),
-      handled_(true),
-      ignored_(false),
       producer_(producer) {
   GetProducer()->AddConsumer(this);
 }
@@ -34,7 +32,7 @@
            channel_id(), buffer_id());
 
   if (auto producer = GetProducer()) {
-    if (!handled_)  // Producer is waiting for our Release.
+    if (!released_)  // Producer is waiting for our Release.
       producer->OnConsumerIgnored();
     producer->RemoveConsumer(this);
   }
@@ -108,15 +106,20 @@
   if (!producer)
     return ErrorStatus(EPIPE);
 
-  if (ignored_ || handled_) {
+  if (acquired_ || released_) {
     ALOGE(
         "ConsumerChannel::OnConsumerAcquire: Acquire when not posted: "
-        "ignored=%d handled=%d channel_id=%d buffer_id=%d",
-        ignored_, handled_, message.GetChannelId(), producer->buffer_id());
+        "ignored=%d acquired=%d released=%d channel_id=%d buffer_id=%d",
+        ignored_, acquired_, released_, message.GetChannelId(),
+        producer->buffer_id());
     return ErrorStatus(EBUSY);
   } else {
-    ClearAvailable();
-    return producer->OnConsumerAcquire(message, metadata_size);
+    auto status = producer->OnConsumerAcquire(message, metadata_size);
+    if (status) {
+      ClearAvailable();
+      acquired_ = true;
+    }
+    return status;
   }
 }
 
@@ -127,17 +130,21 @@
   if (!producer)
     return ErrorStatus(EPIPE);
 
-  if (ignored_ || handled_) {
+  if (!acquired_ || released_) {
     ALOGE(
         "ConsumerChannel::OnConsumerRelease: Release when not acquired: "
-        "ignored=%d handled=%d channel_id=%d buffer_id=%d",
-        ignored_, handled_, message.GetChannelId(), producer->buffer_id());
+        "ignored=%d acquired=%d released=%d channel_id=%d buffer_id=%d",
+        ignored_, acquired_, released_, message.GetChannelId(),
+        producer->buffer_id());
     return ErrorStatus(EBUSY);
   } else {
-    ClearAvailable();
     auto status =
         producer->OnConsumerRelease(message, std::move(release_fence));
-    handled_ = !!status;
+    if (status) {
+      ClearAvailable();
+      acquired_ = false;
+      released_ = true;
+    }
     return status;
   }
 }
@@ -149,12 +156,13 @@
     return ErrorStatus(EPIPE);
 
   ignored_ = ignored;
-  if (ignored_ && !handled_) {
+  if (ignored_ && acquired_) {
     // Update the producer if ignore is set after the consumer acquires the
     // buffer.
     ClearAvailable();
     producer->OnConsumerIgnored();
-    handled_ = false;
+    acquired_ = false;
+    released_ = true;
   }
 
   return {};
@@ -162,10 +170,12 @@
 
 bool ConsumerChannel::OnProducerPosted() {
   if (ignored_) {
-    handled_ = true;
+    acquired_ = false;
+    released_ = true;
     return false;
   } else {
-    handled_ = false;
+    acquired_ = false;
+    released_ = false;
     SignalAvailable();
     return true;
   }
diff --git a/services/vr/bufferhubd/consumer_channel.h b/services/vr/bufferhubd/consumer_channel.h
index d84055c..208a002 100644
--- a/services/vr/bufferhubd/consumer_channel.h
+++ b/services/vr/bufferhubd/consumer_channel.h
@@ -38,8 +38,9 @@
                                       LocalFence release_fence);
   pdx::Status<void> OnConsumerSetIgnore(Message& message, bool ignore);
 
-  bool handled_;  // True if we have processed RELEASE.
-  bool ignored_;  // True if we are ignoring events.
+  bool acquired_{false};
+  bool released_{true};
+  bool ignored_{false};  // True if we are ignoring events.
   std::weak_ptr<Channel> producer_;
 
   ConsumerChannel(const ConsumerChannel&) = delete;
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index b9984a0..b2db795 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -122,7 +122,7 @@
 }
 
 Status<NativeBufferHandle<BorrowedHandle>> ProducerChannel::OnGetBuffer(
-    Message& message) {
+    Message& /*message*/) {
   ATRACE_NAME("ProducerChannel::OnGetBuffer");
   ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d", buffer_id());
   return {NativeBufferHandle<BorrowedHandle>(buffer_, buffer_id())};
@@ -204,7 +204,7 @@
   return {};
 }
 
-Status<LocalFence> ProducerChannel::OnProducerGain(Message& message) {
+Status<LocalFence> ProducerChannel::OnProducerGain(Message& /*message*/) {
   ATRACE_NAME("ProducerChannel::OnGain");
   ALOGD_IF(TRACE, "ProducerChannel::OnGain: buffer_id=%d", buffer_id());
   if (producer_owns_) {
@@ -224,7 +224,7 @@
 }
 
 Status<std::pair<BorrowedFence, BufferWrapper<std::uint8_t*>>>
-ProducerChannel::OnConsumerAcquire(Message& message,
+ProducerChannel::OnConsumerAcquire(Message& /*message*/,
                                    std::size_t metadata_size) {
   ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
   ALOGD_IF(TRACE, "ProducerChannel::OnConsumerAcquire: buffer_id=%d",
diff --git a/services/vr/bufferhubd/producer_queue_channel.cpp b/services/vr/bufferhubd/producer_queue_channel.cpp
index 886e621..b8bb728 100644
--- a/services/vr/bufferhubd/producer_queue_channel.cpp
+++ b/services/vr/bufferhubd/producer_queue_channel.cpp
@@ -16,11 +16,11 @@
 
 ProducerQueueChannel::ProducerQueueChannel(BufferHubService* service,
                                            int channel_id,
-                                           size_t meta_size_bytes,
+                                           const ProducerQueueConfig& config,
                                            const UsagePolicy& usage_policy,
                                            int* error)
     : BufferHubChannel(service, channel_id, channel_id, kProducerQueueType),
-      meta_size_bytes_(meta_size_bytes),
+      config_(config),
       usage_policy_(usage_policy),
       capacity_(0) {
   *error = 0;
@@ -35,8 +35,8 @@
 
 /* static */
 Status<std::shared_ptr<ProducerQueueChannel>> ProducerQueueChannel::Create(
-    BufferHubService* service, int channel_id, size_t meta_size_bytes,
-    const UsagePolicy& usage_policy) {
+    BufferHubService* service, int channel_id,
+    const ProducerQueueConfig& config, const UsagePolicy& usage_policy) {
   // Configuration between |usage_deny_set_mask| and |usage_deny_clear_mask|
   // should be mutually exclusive.
   if ((usage_policy.usage_deny_set_mask & usage_policy.usage_deny_clear_mask)) {
@@ -50,7 +50,7 @@
 
   int error = 0;
   std::shared_ptr<ProducerQueueChannel> producer(new ProducerQueueChannel(
-      service, channel_id, meta_size_bytes, usage_policy, &error));
+      service, channel_id, config, usage_policy, &error));
   if (error < 0)
     return ErrorStatus(-error);
   else
@@ -76,9 +76,9 @@
           message);
       return true;
 
-    case BufferHubRPC::ProducerQueueDetachBuffer::Opcode:
-      DispatchRemoteMethod<BufferHubRPC::ProducerQueueDetachBuffer>(
-          *this, &ProducerQueueChannel::OnProducerQueueDetachBuffer, message);
+    case BufferHubRPC::ProducerQueueRemoveBuffer::Opcode:
+      DispatchRemoteMethod<BufferHubRPC::ProducerQueueRemoveBuffer>(
+          *this, &ProducerQueueChannel::OnProducerQueueRemoveBuffer, message);
       return true;
 
     default:
@@ -134,7 +134,7 @@
 }
 
 Status<QueueInfo> ProducerQueueChannel::OnGetQueueInfo(Message&) {
-  return {{meta_size_bytes_, buffer_id()}};
+  return {{config_, buffer_id()}};
 }
 
 Status<std::vector<std::pair<RemoteChannelHandle, size_t>>>
@@ -222,7 +222,7 @@
 
   auto producer_channel_status =
       ProducerChannel::Create(service(), buffer_id, width, height, layer_count,
-                              format, usage, meta_size_bytes_);
+                              format, usage, config_.meta_size_bytes);
   if (!producer_channel_status) {
     ALOGE(
         "ProducerQueueChannel::AllocateBuffer: Failed to create producer "
@@ -276,11 +276,11 @@
   return {{std::move(buffer_handle), slot}};
 }
 
-Status<void> ProducerQueueChannel::OnProducerQueueDetachBuffer(
+Status<void> ProducerQueueChannel::OnProducerQueueRemoveBuffer(
     Message& /*message*/, size_t slot) {
   if (buffers_[slot].expired()) {
     ALOGE(
-        "ProducerQueueChannel::OnProducerQueueDetachBuffer: trying to detach "
+        "ProducerQueueChannel::OnProducerQueueRemoveBuffer: trying to remove "
         "an invalid buffer producer at slot %zu",
         slot);
     return ErrorStatus(EINVAL);
@@ -288,7 +288,7 @@
 
   if (capacity_ == 0) {
     ALOGE(
-        "ProducerQueueChannel::OnProducerQueueDetachBuffer: trying to detach a "
+        "ProducerQueueChannel::OnProducerQueueRemoveBuffer: trying to remove a "
         "buffer producer while the queue's capacity is already zero.");
     return ErrorStatus(EINVAL);
   }
diff --git a/services/vr/bufferhubd/producer_queue_channel.h b/services/vr/bufferhubd/producer_queue_channel.h
index 28c74cd..fd519c5 100644
--- a/services/vr/bufferhubd/producer_queue_channel.h
+++ b/services/vr/bufferhubd/producer_queue_channel.h
@@ -12,8 +12,8 @@
 class ProducerQueueChannel : public BufferHubChannel {
  public:
   static pdx::Status<std::shared_ptr<ProducerQueueChannel>> Create(
-      BufferHubService* service, int channel_id, size_t meta_size_bytes,
-      const UsagePolicy& usage_policy);
+      BufferHubService* service, int channel_id,
+      const ProducerQueueConfig& config, const UsagePolicy& usage_policy);
   ~ProducerQueueChannel() override;
 
   bool HandleMessage(pdx::Message& message) override;
@@ -40,7 +40,7 @@
 
   // Detach a BufferHubProducer indicated by |slot|. Note that the buffer must
   // be in Gain'ed state for the producer queue to detach.
-  pdx::Status<void> OnProducerQueueDetachBuffer(pdx::Message& message,
+  pdx::Status<void> OnProducerQueueRemoveBuffer(pdx::Message& message,
                                                 size_t slot);
 
   void AddConsumer(ConsumerQueueChannel* channel);
@@ -48,8 +48,8 @@
 
  private:
   ProducerQueueChannel(BufferHubService* service, int channel_id,
-                       size_t meta_size_bytes, const UsagePolicy& usage_policy,
-                       int* error);
+                       const ProducerQueueConfig& config,
+                       const UsagePolicy& usage_policy, int* error);
 
   // Allocate one single producer buffer by |OnProducerQueueAllocateBuffers|.
   // Note that the newly created buffer's file handle will be pushed to client
@@ -60,10 +60,9 @@
       pdx::Message& message, uint32_t width, uint32_t height,
       uint32_t layer_count, uint32_t format, uint64_t usage);
 
-  // Size of the meta data associated with all the buffers allocated from the
-  // queue. Now we assume the metadata size is immutable once the queue is
-  // created.
-  size_t meta_size_bytes_;
+  // The producer queue's configuration. Now we assume the configuration is
+  // immutable once the queue is created.
+  ProducerQueueConfig config_;
 
   // A set of variables to control what |usage| bits can this ProducerQueue
   // allocate.
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 5cb201d..9201520 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -7,6 +7,7 @@
   ],
 
   static_libs: [
+    "libbroadcastring",
     "libhwcomposer-client",
     "libdisplay",
     "libbufferhubqueue",
diff --git a/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl b/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl
index 5fd5c36..be1ec5b 100644
--- a/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl
+++ b/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl
@@ -17,4 +17,9 @@
    * Registers a callback used to receive frame notifications.
    */
   void registerObserver(in IVrComposerCallback callback);
+
+  /**
+   * Clears a previously registered frame notification callback.
+   */
+  void clearObserver();
 }
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.cpp b/services/vr/hardware_composer/impl/vr_composer_client.cpp
index ae54e56..c31417b 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.cpp
+++ b/services/vr/hardware_composer/impl/vr_composer_client.cpp
@@ -24,26 +24,63 @@
 
 namespace android {
 namespace dvr {
+namespace {
 
 using android::hardware::graphics::common::V1_0::PixelFormat;
 using android::frameworks::vr::composer::V1_0::IVrComposerClient;
 
-VrComposerClient::VrComposerClient(dvr::VrHwc& hal)
+class ComposerClientImpl : public ComposerClient {
+ public:
+  ComposerClientImpl(android::dvr::VrHwc& hal);
+  virtual ~ComposerClientImpl();
+
+ private:
+  class VrCommandReader : public ComposerClient::CommandReader {
+   public:
+    VrCommandReader(ComposerClientImpl& client);
+    ~VrCommandReader() override;
+
+    bool parseCommand(IComposerClient::Command command,
+                      uint16_t length) override;
+
+   private:
+    bool parseSetLayerInfo(uint16_t length);
+    bool parseSetClientTargetMetadata(uint16_t length);
+    bool parseSetLayerBufferMetadata(uint16_t length);
+
+    IVrComposerClient::BufferMetadata readBufferMetadata();
+
+    ComposerClientImpl& mVrClient;
+    android::dvr::VrHwc& mVrHal;
+
+    VrCommandReader(const VrCommandReader&) = delete;
+    void operator=(const VrCommandReader&) = delete;
+  };
+
+  std::unique_ptr<CommandReader> createCommandReader() override;
+
+  dvr::VrHwc& mVrHal;
+
+  ComposerClientImpl(const ComposerClientImpl&) = delete;
+  void operator=(const ComposerClientImpl&) = delete;
+};
+
+ComposerClientImpl::ComposerClientImpl(android::dvr::VrHwc& hal)
     : ComposerClient(hal), mVrHal(hal) {}
 
-VrComposerClient::~VrComposerClient() {}
+ComposerClientImpl::~ComposerClientImpl() {}
 
 std::unique_ptr<ComposerClient::CommandReader>
-VrComposerClient::createCommandReader() {
+ComposerClientImpl::createCommandReader() {
   return std::unique_ptr<CommandReader>(new VrCommandReader(*this));
 }
 
-VrComposerClient::VrCommandReader::VrCommandReader(VrComposerClient& client)
+ComposerClientImpl::VrCommandReader::VrCommandReader(ComposerClientImpl& client)
     : CommandReader(client), mVrClient(client), mVrHal(client.mVrHal) {}
 
-VrComposerClient::VrCommandReader::~VrCommandReader() {}
+ComposerClientImpl::VrCommandReader::~VrCommandReader() {}
 
-bool VrComposerClient::VrCommandReader::parseCommand(
+bool ComposerClientImpl::VrCommandReader::parseCommand(
     IComposerClient::Command command, uint16_t length) {
   IVrComposerClient::VrCommand vrCommand =
       static_cast<IVrComposerClient::VrCommand>(command);
@@ -59,7 +96,7 @@
   }
 }
 
-bool VrComposerClient::VrCommandReader::parseSetLayerInfo(uint16_t length) {
+bool ComposerClientImpl::VrCommandReader::parseSetLayerInfo(uint16_t length) {
   if (length != 2) {
     return false;
   }
@@ -72,7 +109,7 @@
   return true;
 }
 
-bool VrComposerClient::VrCommandReader::parseSetClientTargetMetadata(
+bool ComposerClientImpl::VrCommandReader::parseSetClientTargetMetadata(
     uint16_t length) {
   if (length != 7)
     return false;
@@ -84,7 +121,7 @@
   return true;
 }
 
-bool VrComposerClient::VrCommandReader::parseSetLayerBufferMetadata(
+bool ComposerClientImpl::VrCommandReader::parseSetLayerBufferMetadata(
     uint16_t length) {
   if (length != 7)
     return false;
@@ -98,7 +135,7 @@
 }
 
 IVrComposerClient::BufferMetadata
-VrComposerClient::VrCommandReader::readBufferMetadata() {
+ComposerClientImpl::VrCommandReader::readBufferMetadata() {
   IVrComposerClient::BufferMetadata metadata = {
     .width = read(),
     .height = read(),
@@ -110,5 +147,132 @@
   return metadata;
 }
 
+}  // namespace
+
+VrComposerClient::VrComposerClient(dvr::VrHwc& hal)
+    : client_(new ComposerClientImpl(hal)) {
+  client_->initialize();
+}
+
+VrComposerClient::~VrComposerClient() {}
+
+void VrComposerClient::onHotplug(Display display,
+    IComposerCallback::Connection connected) {
+  client_->onHotplug(display, connected);
+}
+
+Return<void> VrComposerClient::registerCallback(
+    const sp<IComposerCallback>& callback) {
+  return client_->registerCallback(callback);
+}
+
+Return<uint32_t> VrComposerClient::getMaxVirtualDisplayCount() {
+  return client_->getMaxVirtualDisplayCount();
+}
+
+Return<void> VrComposerClient::createVirtualDisplay(uint32_t width,
+    uint32_t height, PixelFormat formatHint, uint32_t outputBufferSlotCount,
+    createVirtualDisplay_cb hidl_cb) {
+  return client_->createVirtualDisplay(
+      width, height, formatHint, outputBufferSlotCount, hidl_cb);
+}
+
+Return<Error> VrComposerClient::destroyVirtualDisplay(Display display) {
+  return client_->destroyVirtualDisplay(display);
+}
+
+Return<void> VrComposerClient::createLayer(Display display,
+    uint32_t bufferSlotCount, createLayer_cb hidl_cb) {
+  return client_->createLayer(display, bufferSlotCount, hidl_cb);
+}
+
+Return<Error> VrComposerClient::destroyLayer(Display display, Layer layer) {
+  return client_->destroyLayer(display, layer);
+}
+
+Return<void> VrComposerClient::getActiveConfig(Display display,
+    getActiveConfig_cb hidl_cb) {
+  return client_->getActiveConfig(display, hidl_cb);
+}
+
+Return<Error> VrComposerClient::getClientTargetSupport(Display display,
+    uint32_t width, uint32_t height, PixelFormat format, Dataspace dataspace) {
+  return client_->getClientTargetSupport(display, width, height, format,
+                                         dataspace);
+}
+
+Return<void> VrComposerClient::getColorModes(Display display,
+    getColorModes_cb hidl_cb) {
+  return client_->getColorModes(display, hidl_cb);
+}
+
+Return<void> VrComposerClient::getDisplayAttribute(Display display,
+    Config config, Attribute attribute, getDisplayAttribute_cb hidl_cb) {
+  return client_->getDisplayAttribute(display, config, attribute, hidl_cb);
+}
+
+Return<void> VrComposerClient::getDisplayConfigs(Display display,
+    getDisplayConfigs_cb hidl_cb) {
+  return client_->getDisplayConfigs(display, hidl_cb);
+}
+
+Return<void> VrComposerClient::getDisplayName(Display display,
+    getDisplayName_cb hidl_cb) {
+  return client_->getDisplayName(display, hidl_cb);
+}
+
+Return<void> VrComposerClient::getDisplayType(Display display,
+    getDisplayType_cb hidl_cb) {
+  return client_->getDisplayType(display, hidl_cb);
+}
+
+Return<void> VrComposerClient::getDozeSupport(
+    Display display, getDozeSupport_cb hidl_cb) {
+  return client_->getDozeSupport(display, hidl_cb);
+}
+
+Return<void> VrComposerClient::getHdrCapabilities(
+    Display display, getHdrCapabilities_cb hidl_cb) {
+  return client_->getHdrCapabilities(display, hidl_cb);
+}
+
+Return<Error> VrComposerClient::setActiveConfig(Display display,
+    Config config) {
+  return client_->setActiveConfig(display, config);
+}
+
+Return<Error> VrComposerClient::setColorMode(Display display, ColorMode mode) {
+  return client_->setColorMode(display, mode);
+}
+
+Return<Error> VrComposerClient::setPowerMode(Display display, PowerMode mode) {
+  return client_->setPowerMode(display, mode);
+}
+
+Return<Error> VrComposerClient::setVsyncEnabled(Display display,
+    Vsync enabled) {
+  return client_->setVsyncEnabled(display, enabled);
+}
+
+Return<Error> VrComposerClient::setClientTargetSlotCount(
+    Display display, uint32_t clientTargetSlotCount) {
+  return client_->setClientTargetSlotCount(display, clientTargetSlotCount);
+}
+
+Return<Error> VrComposerClient::setInputCommandQueue(
+    const hardware::MQDescriptorSync<uint32_t>& descriptor) {
+  return client_->setInputCommandQueue(descriptor);
+}
+
+Return<void> VrComposerClient::getOutputCommandQueue(
+    getOutputCommandQueue_cb hidl_cb) {
+  return client_->getOutputCommandQueue(hidl_cb);
+}
+
+Return<void> VrComposerClient::executeCommands(uint32_t inLength,
+    const hidl_vec<hidl_handle>& inHandles, executeCommands_cb hidl_cb) {
+  return client_->executeCommands(inLength, inHandles, hidl_cb);
+}
+
 }  // namespace dvr
 }  // namespace android
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.h b/services/vr/hardware_composer/impl/vr_composer_client.h
index 1236be9..f492230 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.h
+++ b/services/vr/hardware_composer/impl/vr_composer_client.h
@@ -29,37 +29,59 @@
 using hardware::graphics::common::V1_0::PixelFormat;
 using hardware::graphics::composer::V2_1::implementation::ComposerClient;
 
-class VrComposerClient : public ComposerClient {
+class VrComposerClient : public IVrComposerClient {
  public:
   VrComposerClient(android::dvr::VrHwc& hal);
   virtual ~VrComposerClient();
 
+  void onHotplug(Display display, IComposerCallback::Connection connected);
+
+  // IComposerClient
+  Return<void> registerCallback(const sp<IComposerCallback>& callback) override;
+  Return<uint32_t> getMaxVirtualDisplayCount() override;
+  Return<void> createVirtualDisplay(
+      uint32_t width, uint32_t height, PixelFormat formatHint,
+      uint32_t outputBufferSlotCount, createVirtualDisplay_cb hidl_cb) override;
+  Return<Error> destroyVirtualDisplay(Display display) override;
+  Return<void> createLayer(Display display, uint32_t bufferSlotCount,
+                           createLayer_cb hidl_cb) override;
+  Return<Error> destroyLayer(Display display, Layer layer) override;
+  Return<void> getActiveConfig(Display display,
+                               getActiveConfig_cb hidl_cb) override;
+  Return<Error> getClientTargetSupport(
+      Display display, uint32_t width, uint32_t height, PixelFormat format,
+      Dataspace dataspace) override;
+  Return<void> getColorModes(Display display,
+                             getColorModes_cb hidl_cb) override;
+  Return<void> getDisplayAttribute(
+      Display display, Config config, Attribute attribute,
+      getDisplayAttribute_cb hidl_cb) override;
+  Return<void> getDisplayConfigs(Display display,
+                                 getDisplayConfigs_cb hidl_cb) override;
+  Return<void> getDisplayName(Display display,
+                              getDisplayName_cb hidl_cb) override;
+  Return<void> getDisplayType(Display display,
+                              getDisplayType_cb hidl_cb) override;
+  Return<void> getDozeSupport(Display display,
+                              getDozeSupport_cb hidl_cb) override;
+  Return<void> getHdrCapabilities(Display display,
+                                  getHdrCapabilities_cb hidl_cb) override;
+  Return<Error> setActiveConfig(Display display, Config config) override;
+  Return<Error> setColorMode(Display display, ColorMode mode) override;
+  Return<Error> setPowerMode(Display display, PowerMode mode) override;
+  Return<Error> setVsyncEnabled(Display display, Vsync enabled) override;
+  Return<Error> setClientTargetSlotCount(
+      Display display, uint32_t clientTargetSlotCount) override;
+  Return<Error> setInputCommandQueue(
+      const hardware::MQDescriptorSync<uint32_t>& descriptor) override;
+  Return<void> getOutputCommandQueue(
+      getOutputCommandQueue_cb hidl_cb) override;
+  Return<void> executeCommands(
+      uint32_t inLength, const hidl_vec<hidl_handle>& inHandles,
+      executeCommands_cb hidl_cb) override;
+
  private:
-  class VrCommandReader : public ComposerClient::CommandReader {
-   public:
-    VrCommandReader(VrComposerClient& client);
-    ~VrCommandReader() override;
-
-    bool parseCommand(IComposerClient::Command command,
-                      uint16_t length) override;
-
-   private:
-    bool parseSetLayerInfo(uint16_t length);
-    bool parseSetClientTargetMetadata(uint16_t length);
-    bool parseSetLayerBufferMetadata(uint16_t length);
-
-    IVrComposerClient::BufferMetadata readBufferMetadata();
-
-    VrComposerClient& mVrClient;
-    android::dvr::VrHwc& mVrHal;
-
-    VrCommandReader(const VrCommandReader&) = delete;
-    void operator=(const VrCommandReader&) = delete;
-  };
-
-  std::unique_ptr<CommandReader> createCommandReader() override;
-
-  dvr::VrHwc& mVrHal;
+  std::unique_ptr<ComposerClient> client_;
 
   VrComposerClient(const VrComposerClient&) = delete;
   void operator=(const VrComposerClient&) = delete;
diff --git a/services/vr/hardware_composer/impl/vr_hwc.cpp b/services/vr/hardware_composer/impl/vr_hwc.cpp
index 5d51827..861114d 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.cpp
+++ b/services/vr/hardware_composer/impl/vr_hwc.cpp
@@ -15,6 +15,7 @@
  */
 #include "impl/vr_hwc.h"
 
+#include <cutils/properties.h>
 #include <private/dvr/display_client.h>
 #include <ui/Fence.h>
 
@@ -336,11 +337,30 @@
       *outValue = display_ptr->height();
       break;
     case IComposerClient::Attribute::VSYNC_PERIOD:
-      *outValue = 1000 * 1000 * 1000 / 30;  // 30fps
+      {
+        int error = 0;
+        auto display_client = display::DisplayClient::Create(&error);
+        if (!display_client) {
+          ALOGE("Could not connect to display service : %s(%d)",
+                strerror(error), error);
+          // Return a default value of 30 fps
+          *outValue = 1000 * 1000 * 1000 / 30;
+        } else {
+          auto metrics = display_client->GetDisplayMetrics();
+          *outValue = metrics.get().vsync_period_ns;
+        }
+      }
       break;
     case IComposerClient::Attribute::DPI_X:
     case IComposerClient::Attribute::DPI_Y:
-      *outValue = 300 * 1000;  // 300dpi
+      {
+        constexpr int32_t kDefaultDPI = 300;
+        int32_t dpi = property_get_int32("ro.vr.hwc.dpi", kDefaultDPI);
+        if (dpi <= 0) {
+          dpi = kDefaultDPI;
+        }
+        *outValue = 1000 * dpi;
+      }
       break;
     default:
       return Error::BAD_PARAMETER;
@@ -820,7 +840,6 @@
   sp<VrComposerClient> client;
   if (client_ == nullptr) {
     client = new VrComposerClient(*this);
-    client->initialize();
   } else {
     ALOGE("Already have a client");
     status = Error::NO_RESOURCES;
@@ -852,12 +871,5 @@
   return iter == displays_.end() ? nullptr : iter->second.get();
 }
 
-ComposerView* GetComposerViewFromIComposer(
-    hardware::graphics::composer::V2_1::IComposer* composer) {
-  return static_cast<VrHwc*>(composer);
-}
-
-IComposer* HIDL_FETCH_IComposer(const char*) { return new VrHwc(); }
-
 }  // namespace dvr
 }  // namespace android
diff --git a/services/vr/hardware_composer/impl/vr_hwc.h b/services/vr/hardware_composer/impl/vr_hwc.h
index df04208..523cda3 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.h
+++ b/services/vr/hardware_composer/impl/vr_hwc.h
@@ -309,13 +309,6 @@
   void operator=(const VrHwc&) = delete;
 };
 
-
-ComposerView* GetComposerViewFromIComposer(
-    hardware::graphics::composer::V2_1::IComposer* composer);
-
-hardware::graphics::composer::V2_1::IComposer* HIDL_FETCH_IComposer(
-    const char* name);
-
 }  // namespace dvr
 }  // namespace android
 
diff --git a/services/vr/hardware_composer/vr_composer.cpp b/services/vr/hardware_composer/vr_composer.cpp
index c45fbf4..36a313a 100644
--- a/services/vr/hardware_composer/vr_composer.cpp
+++ b/services/vr/hardware_composer/vr_composer.cpp
@@ -42,6 +42,12 @@
   return binder::Status::ok();
 }
 
+binder::Status VrComposer::clearObserver() {
+  std::lock_guard<std::mutex> guard(mutex_);
+  callback_ = nullptr;
+  return binder::Status::ok();
+}
+
 base::unique_fd VrComposer::OnNewFrame(const ComposerView::Frame& frame) {
   std::lock_guard<std::mutex> guard(mutex_);
 
diff --git a/services/vr/hardware_composer/vr_composer.h b/services/vr/hardware_composer/vr_composer.h
index 93d1f2b..7b580c6 100644
--- a/services/vr/hardware_composer/vr_composer.h
+++ b/services/vr/hardware_composer/vr_composer.h
@@ -27,6 +27,8 @@
   binder::Status registerObserver(
       const sp<IVrComposerCallback>& callback) override;
 
+  binder::Status clearObserver() override;
+
   // ComposerView::Observer:
   base::unique_fd OnNewFrame(const ComposerView::Frame& frame) override;
 
diff --git a/services/vr/hardware_composer/vr_hardware_composer_service.cpp b/services/vr/hardware_composer/vr_hardware_composer_service.cpp
index f980220..e36b0ae 100644
--- a/services/vr/hardware_composer/vr_hardware_composer_service.cpp
+++ b/services/vr/hardware_composer/vr_hardware_composer_service.cpp
@@ -26,22 +26,18 @@
 
   // Register the hwbinder HWC HAL service used by SurfaceFlinger while in VR
   // mode.
-  const char instance[] = "vr";
-  android::sp<IComposer> service =
-      android::dvr::HIDL_FETCH_IComposer(instance);
+  android::sp<android::dvr::VrHwc> service = new android::dvr::VrHwc();
 
   LOG_ALWAYS_FATAL_IF(!service.get(), "Failed to get service");
   LOG_ALWAYS_FATAL_IF(service->isRemote(), "Service is remote");
 
+  const char instance[] = "vr";
   LOG_ALWAYS_FATAL_IF(service->registerAsService(instance) != android::OK,
                       "Failed to register service");
 
   android::sp<android::dvr::VrComposer> composer =
       new android::dvr::VrComposer();
-
-  android::dvr::ComposerView* composer_view =
-      android::dvr::GetComposerViewFromIComposer(service.get());
-  composer_view->RegisterObserver(composer.get());
+  service->RegisterObserver(composer.get());
 
   android::sp<android::IServiceManager> sm(android::defaultServiceManager());
 
@@ -56,7 +52,7 @@
   android::hardware::ProcessState::self()->startThreadPool();
   android::hardware::IPCThreadState::self()->joinThreadPool();
 
-  composer_view->UnregisterObserver(composer.get());
+  service->UnregisterObserver(composer.get());
 
   return 0;
 }
diff --git a/services/vr/performanced/Android.mk b/services/vr/performanced/Android.mk
index 6256e90..dbc66f1 100644
--- a/services/vr/performanced/Android.mk
+++ b/services/vr/performanced/Android.mk
@@ -23,8 +23,10 @@
 staticLibraries := \
 	libperformance \
 	libpdx_default_transport \
+	libvr_manager
 
 sharedLibraries := \
+	libbinder \
 	libbase \
 	libcutils \
 	liblog \
diff --git a/services/vr/performanced/cpu_set.cpp b/services/vr/performanced/cpu_set.cpp
index 1a3723f..1a7264c 100644
--- a/services/vr/performanced/cpu_set.cpp
+++ b/services/vr/performanced/cpu_set.cpp
@@ -15,6 +15,9 @@
 #include "task.h"
 #include "unique_file.h"
 
+using android::pdx::ErrorStatus;
+using android::pdx::Status;
+
 namespace {
 
 constexpr int kDirectoryFlags = O_RDONLY | O_DIRECTORY | O_CLOEXEC;
@@ -176,11 +179,11 @@
                task_id, task.name().c_str(), target_set.c_str(),
                task.thread_group_id(), task.parent_process_id());
 
-      const int ret = target->AttachTask(task_id);
-      ALOGW_IF(ret < 0 && ret != -EINVAL,
+      auto status = target->AttachTask(task_id);
+      ALOGW_IF(!status && status.error() != EINVAL,
                "CpuSetManager::MoveUnboundTasks: Failed to attach task_id=%d "
                "to cpuset=%s: %s",
-               task_id, target_set.c_str(), strerror(-ret));
+               task_id, target_set.c_str(), status.GetErrorMessage().c_str());
     } else {
       ALOGD_IF(TRACE,
                "CpuSet::MoveUnboundTasks: Skipping task_id=%d name=%s cpus=%s.",
@@ -233,7 +236,7 @@
   return fp;
 }
 
-int CpuSet::AttachTask(pid_t task_id) const {
+Status<void> CpuSet::AttachTask(pid_t task_id) const {
   auto file = OpenFile("tasks", O_RDWR);
   if (file.get() >= 0) {
     std::ostringstream stream;
@@ -241,11 +244,15 @@
     std::string value = stream.str();
 
     const bool ret = base::WriteStringToFd(value, file.get());
-    return !ret ? -errno : 0;
+    if (!ret)
+      return ErrorStatus(errno);
+    else
+      return {};
   } else {
+    const int error = errno;
     ALOGE("CpuSet::AttachTask: Failed to open %s/tasks: %s", path_.c_str(),
-          strerror(errno));
-    return -errno;
+          strerror(error));
+    return ErrorStatus(error);
   }
 }
 
diff --git a/services/vr/performanced/cpu_set.h b/services/vr/performanced/cpu_set.h
index fcf280a..6879272 100644
--- a/services/vr/performanced/cpu_set.h
+++ b/services/vr/performanced/cpu_set.h
@@ -11,6 +11,8 @@
 
 #include <android-base/unique_fd.h>
 
+#include <pdx/status.h>
+
 #include "unique_file.h"
 
 namespace android {
@@ -28,7 +30,7 @@
 
   std::string GetCpuList() const;
 
-  int AttachTask(pid_t task_id) const;
+  pdx::Status<void> AttachTask(pid_t task_id) const;
   std::vector<pid_t> GetTasks() const;
 
  private:
diff --git a/services/vr/performanced/performance_service.cpp b/services/vr/performanced/performance_service.cpp
index 955c661..4b9fbe0 100644
--- a/services/vr/performanced/performance_service.cpp
+++ b/services/vr/performanced/performance_service.cpp
@@ -8,14 +8,20 @@
 #include <pdx/rpc/argument_encoder.h>
 #include <pdx/rpc/message_buffer.h>
 #include <pdx/rpc/remote_method.h>
+#include <private/android_filesystem_config.h>
 #include <private/dvr/performance_rpc.h>
+#include <private/dvr/trusted_uids.h>
 
 #include "task.h"
 
 // This prctl is only available in Android kernels.
 #define PR_SET_TIMERSLACK_PID 41
 
+using android::dvr::IsTrustedUid;
+using android::dvr::Task;
+using android::pdx::ErrorStatus;
 using android::pdx::Message;
+using android::pdx::Status;
 using android::pdx::rpc::DispatchRemoteMethod;
 using android::pdx::default_transport::Endpoint;
 
@@ -26,6 +32,68 @@
 constexpr unsigned long kTimerSlackForegroundNs = 50000;
 constexpr unsigned long kTimerSlackBackgroundNs = 40000000;
 
+// Expands the given parameter pack expression using an initializer list to
+// guarantee ordering and a comma expression to guarantee even void expressions
+// are valid elements of the initializer list.
+#define EXPAND_PACK(...) \
+  std::initializer_list<int> { (__VA_ARGS__, 0)... }
+
+// Returns true if the sender's euid matches any of the uids in |UIDs|.
+template <uid_t... UIDs>
+struct UserId {
+  static bool Check(const Message& sender, const Task&) {
+    const uid_t uid = sender.GetEffectiveUserId();
+    bool allow = false;
+    EXPAND_PACK(allow |= (uid == UIDs));
+    return allow;
+  }
+};
+
+// Returns true if the sender's egid matches any of the gids in |GIDs|.
+template <gid_t... GIDs>
+struct GroupId {
+  static bool Check(const Message& sender, const Task&) {
+    const gid_t gid = sender.GetEffectiveGroupId();
+    bool allow = false;
+    EXPAND_PACK(allow |= (gid == GIDs));
+    return allow;
+  }
+};
+
+// Returns true if the sender's euid is trusted according to VR manager service.
+struct Trusted {
+  static bool Check(const Message& sender, const Task&) {
+    return IsTrustedUid(sender.GetEffectiveUserId());
+  }
+};
+
+// Returns returns true if the task belongs to the sending process.
+struct SameProcess {
+  static bool Check(const Message& sender, const Task& task) {
+    return sender.GetProcessId() == task.thread_group_id();
+  }
+};
+
+// Returns true if any of the checks in |Allows| pass, false otherwise.
+template <typename... Allows>
+struct CheckOr {
+  static bool Check(const Message& sender, const Task& task) {
+    bool allow = false;
+    EXPAND_PACK(allow |= Allows::Check(sender, task));
+    return allow;
+  }
+};
+
+// Returns true if all of the checks in |Allows| pass, false otherwise.
+template <typename... Allows>
+struct CheckAnd {
+  static bool Check(const Message& sender, const Task& task) {
+    bool allow = true;
+    EXPAND_PACK(allow &= Allows::Check(sender, task));
+    return allow;
+  }
+};
+
 }  // anonymous namespace
 
 namespace android {
@@ -48,43 +116,79 @@
   const int fifo_low = sched_fifo_min_priority_;
   const int fifo_medium = sched_fifo_min_priority_ + fifo_range / 5;
 
-  // TODO(eieio): Make this configurable on the command line.
+  // TODO(eieio): Make this configurable on the command line or config file.
   cpuset_.MoveUnboundTasks("/kernel");
 
+  // TODO(eieio): Replace this witha device-specific config file. This is just a
+  // hack for now to put some form of permission logic in place while a longer
+  // term solution is developed.
+  using AllowRootSystem =
+      CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM>,
+                                    GroupId<AID_SYSTEM>>>;
+  using AllowRootSystemGraphics =
+      CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM, AID_GRAPHICS>,
+                                    GroupId<AID_SYSTEM, AID_GRAPHICS>>>;
+  using AllowRootSystemAudio =
+      CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM, AID_AUDIO>,
+                                    GroupId<AID_SYSTEM, AID_AUDIO>>>;
+  using AllowRootSystemTrusted = CheckOr<Trusted, UserId<AID_ROOT, AID_SYSTEM>,
+                                        GroupId<AID_SYSTEM>>;
+
+  partition_permission_check_ = AllowRootSystemTrusted::Check;
+
   // Setup the scheduler classes.
+  // TODO(eieio): Replace this with a device-specific config file.
   scheduler_classes_ = {
       {"audio:low",
        {.timer_slack = kTimerSlackForegroundNs,
         .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
-        .priority = fifo_medium}},
+        .priority = fifo_medium,
+        .permission_check = AllowRootSystemAudio::Check}},
       {"audio:high",
        {.timer_slack = kTimerSlackForegroundNs,
         .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
-        .priority = fifo_medium + 3}},
+        .priority = fifo_medium + 3,
+        .permission_check = AllowRootSystemAudio::Check}},
       {"graphics",
        {.timer_slack = kTimerSlackForegroundNs,
         .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
-        .priority = fifo_medium}},
+        .priority = fifo_medium,
+        .permission_check = AllowRootSystemGraphics::Check}},
       {"graphics:low",
        {.timer_slack = kTimerSlackForegroundNs,
         .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
-        .priority = fifo_medium}},
+        .priority = fifo_medium,
+        .permission_check = AllowRootSystemGraphics::Check}},
       {"graphics:high",
        {.timer_slack = kTimerSlackForegroundNs,
         .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
-        .priority = fifo_medium + 2}},
+        .priority = fifo_medium + 2,
+        .permission_check = AllowRootSystemGraphics::Check}},
       {"sensors",
        {.timer_slack = kTimerSlackForegroundNs,
         .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
-        .priority = fifo_low}},
+        .priority = fifo_low,
+        .permission_check = AllowRootSystem::Check}},
       {"sensors:low",
        {.timer_slack = kTimerSlackForegroundNs,
         .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
-        .priority = fifo_low}},
+        .priority = fifo_low,
+        .permission_check = AllowRootSystem::Check}},
       {"sensors:high",
        {.timer_slack = kTimerSlackForegroundNs,
         .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
-        .priority = fifo_low + 1}},
+        .priority = fifo_low + 1,
+        .permission_check = AllowRootSystem::Check}},
+      {"vr:system:arp",
+       {.timer_slack = kTimerSlackForegroundNs,
+        .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
+        .priority = fifo_medium + 2,
+        .permission_check = AllowRootSystemTrusted::Check}},
+      {"vr:app:render",
+       {.timer_slack = kTimerSlackForegroundNs,
+        .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
+        .priority = fifo_medium + 1,
+        .permission_check = AllowRootSystemTrusted::Check}},
       {"normal",
        {.timer_slack = kTimerSlackForegroundNs,
         .scheduler_policy = SCHED_NORMAL,
@@ -113,67 +217,94 @@
   return cpuset_.DumpState();
 }
 
-int PerformanceService::OnSetCpuPartition(Message& message, pid_t task_id,
-                                          const std::string& partition) {
+Status<void> PerformanceService::OnSetSchedulerPolicy(
+    Message& message, pid_t task_id, const std::string& scheduler_policy) {
+  // Forward to scheduler class handler for now. In the future this method will
+  // subsume the others by unifying both scheduler class and cpu partiton into a
+  // single policy concept.
+  ALOGI(
+      "PerformanceService::OnSetSchedulerPolicy: task_id=%d "
+      "scheduler_policy=%s",
+      task_id, scheduler_policy.c_str());
+  return OnSetSchedulerClass(message, task_id, scheduler_policy);
+}
+
+Status<void> PerformanceService::OnSetCpuPartition(
+    Message& message, pid_t task_id, const std::string& partition) {
   Task task(task_id);
   if (!task || task.thread_group_id() != message.GetProcessId())
-    return -EINVAL;
+    return ErrorStatus(EINVAL);
+
+  // Temporary permission check.
+  // TODO(eieio): Replace this with a configuration file.
+  if (partition_permission_check_ &&
+      !partition_permission_check_(message, task)) {
+    return ErrorStatus(EINVAL);
+  }
 
   auto target_set = cpuset_.Lookup(partition);
   if (!target_set)
-    return -ENOENT;
+    return ErrorStatus(ENOENT);
 
-  const auto attach_error = target_set->AttachTask(task_id);
-  if (attach_error)
-    return attach_error;
+  auto attach_status = target_set->AttachTask(task_id);
+  if (!attach_status)
+    return attach_status;
 
-  return 0;
+  return {};
 }
 
-int PerformanceService::OnSetSchedulerClass(
+Status<void> PerformanceService::OnSetSchedulerClass(
     Message& message, pid_t task_id, const std::string& scheduler_class) {
-  // Make sure the task id is valid and belongs to the sending process.
   Task task(task_id);
-  if (!task || task.thread_group_id() != message.GetProcessId())
-    return -EINVAL;
+  if (!task)
+    return ErrorStatus(EINVAL);
 
-  struct sched_param param;
-
-  // TODO(eieio): Apply rules based on the requesting process. Applications are
-  // only allowed one audio thread that runs at SCHED_FIFO. System services can
-  // have more than one.
   auto search = scheduler_classes_.find(scheduler_class);
   if (search != scheduler_classes_.end()) {
     auto config = search->second;
+
+    // Make sure the sending process is allowed to make the requested change to
+    // this task.
+    if (!config.IsAllowed(message, task))
+      return ErrorStatus(EINVAL);
+
+    struct sched_param param;
     param.sched_priority = config.priority;
+
     sched_setscheduler(task_id, config.scheduler_policy, &param);
     prctl(PR_SET_TIMERSLACK_PID, config.timer_slack, task_id);
     ALOGI("PerformanceService::OnSetSchedulerClass: Set task=%d to class=%s.",
           task_id, scheduler_class.c_str());
-    return 0;
+    return {};
   } else {
     ALOGE(
         "PerformanceService::OnSetSchedulerClass: Invalid class=%s requested "
         "by task=%d.",
         scheduler_class.c_str(), task_id);
-    return -EINVAL;
+    return ErrorStatus(EINVAL);
   }
 }
 
-std::string PerformanceService::OnGetCpuPartition(Message& message,
-                                                  pid_t task_id) {
+Status<std::string> PerformanceService::OnGetCpuPartition(Message& message,
+                                                          pid_t task_id) {
   // Make sure the task id is valid and belongs to the sending process.
   Task task(task_id);
   if (!task || task.thread_group_id() != message.GetProcessId())
-    REPLY_ERROR_RETURN(message, EINVAL, "");
+    return ErrorStatus(EINVAL);
 
   return task.GetCpuSetPath();
 }
 
-pdx::Status<void> PerformanceService::HandleMessage(Message& message) {
+Status<void> PerformanceService::HandleMessage(Message& message) {
+  ALOGD_IF(TRACE, "PerformanceService::HandleMessage: op=%d", message.GetOp());
   switch (message.GetOp()) {
+    case PerformanceRPC::SetSchedulerPolicy::Opcode:
+      DispatchRemoteMethod<PerformanceRPC::SetSchedulerPolicy>(
+          *this, &PerformanceService::OnSetSchedulerPolicy, message);
+      return {};
+
     case PerformanceRPC::SetCpuPartition::Opcode:
-      DispatchRemoteMethod<PerformanceRPC::SetSchedulerClass>(
+      DispatchRemoteMethod<PerformanceRPC::SetCpuPartition>(
           *this, &PerformanceService::OnSetCpuPartition, message);
       return {};
 
diff --git a/services/vr/performanced/performance_service.h b/services/vr/performanced/performance_service.h
index 34abba7..b28d94a 100644
--- a/services/vr/performanced/performance_service.h
+++ b/services/vr/performanced/performance_service.h
@@ -1,12 +1,14 @@
 #ifndef ANDROID_DVR_PERFORMANCED_PERFORMANCE_SERVICE_H_
 #define ANDROID_DVR_PERFORMANCED_PERFORMANCE_SERVICE_H_
 
+#include <functional>
 #include <string>
 #include <unordered_map>
 
 #include <pdx/service.h>
 
 #include "cpu_set.h"
+#include "task.h"
 
 namespace android {
 namespace dvr {
@@ -27,11 +29,15 @@
 
   PerformanceService();
 
-  int OnSetCpuPartition(pdx::Message& message, pid_t task_id,
-                        const std::string& partition);
-  int OnSetSchedulerClass(pdx::Message& message, pid_t task_id,
-                          const std::string& scheduler_class);
-  std::string OnGetCpuPartition(pdx::Message& message, pid_t task_id);
+  pdx::Status<void> OnSetSchedulerPolicy(pdx::Message& message, pid_t task_id,
+                                         const std::string& scheduler_class);
+
+  pdx::Status<void> OnSetCpuPartition(pdx::Message& message, pid_t task_id,
+                                      const std::string& partition);
+  pdx::Status<void> OnSetSchedulerClass(pdx::Message& message, pid_t task_id,
+                                        const std::string& scheduler_class);
+  pdx::Status<std::string> OnGetCpuPartition(pdx::Message& message,
+                                             pid_t task_id);
 
   CpuSetManager cpuset_;
 
@@ -43,10 +49,27 @@
     unsigned long timer_slack;
     int scheduler_policy;
     int priority;
+    std::function<bool(const pdx::Message& message, const Task& task)>
+        permission_check;
+
+    // Check the permisison of the given task to use this scheduler class. If a
+    // permission check function is not set then operations are only allowed on
+    // tasks in the sender's process.
+    bool IsAllowed(const pdx::Message& sender, const Task& task) const {
+      if (permission_check)
+        return permission_check(sender, task);
+      else if (!task || task.thread_group_id() != sender.GetProcessId())
+        return false;
+      else
+        return true;
+    }
   };
 
   std::unordered_map<std::string, SchedulerClassConfig> scheduler_classes_;
 
+  std::function<bool(const pdx::Message& message, const Task& task)>
+      partition_permission_check_;
+
   PerformanceService(const PerformanceService&) = delete;
   void operator=(const PerformanceService&) = delete;
 };
diff --git a/services/vr/performanced/performance_service_tests.cpp b/services/vr/performanced/performance_service_tests.cpp
index b526082..274a1b3 100644
--- a/services/vr/performanced/performance_service_tests.cpp
+++ b/services/vr/performanced/performance_service_tests.cpp
@@ -1,12 +1,22 @@
 #include <errno.h>
 #include <sched.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include <condition_variable>
+#include <cstdlib>
 #include <mutex>
 #include <thread>
 
 #include <dvr/performance_client_api.h>
 #include <gtest/gtest.h>
+#include <private/android_filesystem_config.h>
+
+namespace {
+
+const char kTrustedUidEnvironmentVariable[] = "GTEST_TRUSTED_UID";
+
+}  // anonymous namespace
 
 TEST(DISABLED_PerformanceTest, SetCpuPartition) {
   int error;
@@ -86,6 +96,27 @@
   EXPECT_EQ(-EINVAL, error);
 }
 
+// This API mirrors SetSchedulerClass for now. Replace with with a more specific
+// test once the policy API is fully implemented.
+TEST(PerformanceTest, SetSchedulerPolicy) {
+  int error;
+
+  error = dvrSetSchedulerPolicy(0, "background");
+  EXPECT_EQ(0, error);
+  EXPECT_EQ(SCHED_BATCH, sched_getscheduler(0));
+
+  error = dvrSetSchedulerPolicy(0, "audio:low");
+  EXPECT_EQ(0, error);
+  EXPECT_EQ(SCHED_FIFO | SCHED_RESET_ON_FORK, sched_getscheduler(0));
+
+  error = dvrSetSchedulerPolicy(0, "normal");
+  EXPECT_EQ(0, error);
+  EXPECT_EQ(SCHED_NORMAL, sched_getscheduler(0));
+
+  error = dvrSetSchedulerPolicy(0, "foobar");
+  EXPECT_EQ(-EINVAL, error);
+}
+
 TEST(PerformanceTest, SchedulerClassResetOnFork) {
   int error;
 
@@ -135,3 +166,284 @@
   error = dvrGetCpuPartition(0, nullptr, sizeof(partition));
   EXPECT_EQ(-EINVAL, error);
 }
+
+TEST(PerformanceTest, Permissions) {
+  int error;
+
+  const int original_uid = getuid();
+  const int original_gid = getgid();
+  int trusted_uid = -1;
+
+  // See if the environment variable GTEST_TRUSTED_UID is set. If it is enable
+  // testing the ActivityManager trusted uid permission checks using that uid.
+  const char* trusted_uid_env = std::getenv(kTrustedUidEnvironmentVariable);
+  if (trusted_uid_env)
+    trusted_uid = std::atoi(trusted_uid_env);
+
+  ASSERT_EQ(AID_ROOT, original_uid)
+      << "This test must run as root to function correctly!";
+
+  // Test unprivileged policies on a task that does not belong to this process.
+  // Use the init process (task_id=1) as the target.
+  error = dvrSetSchedulerPolicy(1, "batch");
+  EXPECT_EQ(-EINVAL, error);
+  error = dvrSetSchedulerPolicy(1, "background");
+  EXPECT_EQ(-EINVAL, error);
+  error = dvrSetSchedulerPolicy(1, "foreground");
+  EXPECT_EQ(-EINVAL, error);
+  error = dvrSetSchedulerPolicy(1, "normal");
+  EXPECT_EQ(-EINVAL, error);
+
+  // Switch the uid/gid to an id that should not have permission to access any
+  // privileged actions.
+  ASSERT_EQ(0, setresgid(AID_NOBODY, AID_NOBODY, -1))
+      << "Failed to set gid: " << strerror(errno);
+  ASSERT_EQ(0, setresuid(AID_NOBODY, AID_NOBODY, -1))
+      << "Failed to set uid: " << strerror(errno);
+
+  // Unprivileged policies.
+  error = dvrSetSchedulerPolicy(0, "batch");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "background");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "foreground");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "normal");
+  EXPECT_EQ(0, error);
+
+  // Privileged policies.
+  error = dvrSetSchedulerPolicy(0, "audio:low");
+  EXPECT_EQ(-EINVAL, error);
+  error = dvrSetSchedulerPolicy(0, "audio:high");
+  EXPECT_EQ(-EINVAL, error);
+  error = dvrSetSchedulerPolicy(0, "graphics");
+  EXPECT_EQ(-EINVAL, error);
+  error = dvrSetSchedulerPolicy(0, "graphics:low");
+  EXPECT_EQ(-EINVAL, error);
+  error = dvrSetSchedulerPolicy(0, "graphics:high");
+  EXPECT_EQ(-EINVAL, error);
+  error = dvrSetSchedulerPolicy(0, "sensors");
+  EXPECT_EQ(-EINVAL, error);
+  error = dvrSetSchedulerPolicy(0, "sensors:low");
+  EXPECT_EQ(-EINVAL, error);
+  error = dvrSetSchedulerPolicy(0, "sensors:high");
+  EXPECT_EQ(-EINVAL, error);
+  error = dvrSetSchedulerPolicy(0, "vr:system:arp");
+  EXPECT_EQ(-EINVAL, error);
+  error = dvrSetSchedulerPolicy(0, "vr:app:render");
+  EXPECT_EQ(-EINVAL, error);
+
+  // uid=AID_SYSTEM / gid=AID_NOBODY
+  ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
+      << "Failed to restore uid: " << strerror(errno);
+  ASSERT_EQ(0, setresuid(AID_SYSTEM, AID_SYSTEM, -1))
+      << "Failed to set uid: " << strerror(errno);
+
+  // Unprivileged policies.
+  error = dvrSetSchedulerPolicy(0, "batch");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "background");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "foreground");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "normal");
+  EXPECT_EQ(0, error);
+
+  // Privileged policies.
+  error = dvrSetSchedulerPolicy(0, "audio:low");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "audio:high");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "graphics");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "graphics:low");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "graphics:high");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "sensors");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "sensors:low");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "sensors:high");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "vr:system:arp");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "vr:app:render");
+  EXPECT_EQ(0, error);
+
+  // uid=AID_NOBODY / gid=AID_SYSTEM
+  ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
+      << "Failed to restore uid: " << strerror(errno);
+  ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
+      << "Failed to restore gid: " << strerror(errno);
+  ASSERT_EQ(0, setresgid(AID_SYSTEM, AID_SYSTEM, -1))
+      << "Failed to set gid: " << strerror(errno);
+  ASSERT_EQ(0, setresuid(AID_SYSTEM, AID_NOBODY, -1))
+      << "Failed to set uid: " << strerror(errno);
+
+  // Unprivileged policies.
+  error = dvrSetSchedulerPolicy(0, "batch");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "background");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "foreground");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "normal");
+  EXPECT_EQ(0, error);
+
+  // Privileged policies.
+  error = dvrSetSchedulerPolicy(0, "audio:low");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "audio:high");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "graphics");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "graphics:low");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "graphics:high");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "sensors");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "sensors:low");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "sensors:high");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "vr:system:arp");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "vr:app:render");
+  EXPECT_EQ(0, error);
+
+  // uid=AID_GRAPHICS / gid=AID_NOBODY
+  ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
+      << "Failed to restore uid: " << strerror(errno);
+  ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
+      << "Failed to restore gid: " << strerror(errno);
+  ASSERT_EQ(0, setresgid(AID_NOBODY, AID_NOBODY, -1))
+      << "Failed to set gid: " << strerror(errno);
+  ASSERT_EQ(0, setresuid(AID_GRAPHICS, AID_GRAPHICS, -1))
+      << "Failed to set uid: " << strerror(errno);
+
+  // Unprivileged policies.
+  error = dvrSetSchedulerPolicy(0, "batch");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "background");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "foreground");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "normal");
+  EXPECT_EQ(0, error);
+
+  // Privileged policies.
+  error = dvrSetSchedulerPolicy(0, "audio:low");
+  EXPECT_EQ(-EINVAL, error);
+  error = dvrSetSchedulerPolicy(0, "audio:high");
+  EXPECT_EQ(-EINVAL, error);
+  error = dvrSetSchedulerPolicy(0, "graphics");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "graphics:low");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "graphics:high");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "sensors");
+  EXPECT_EQ(-EINVAL, error);
+  error = dvrSetSchedulerPolicy(0, "sensors:low");
+  EXPECT_EQ(-EINVAL, error);
+  error = dvrSetSchedulerPolicy(0, "sensors:high");
+  EXPECT_EQ(-EINVAL, error);
+  error = dvrSetSchedulerPolicy(0, "vr:system:arp");
+  EXPECT_EQ(-EINVAL, error);
+  error = dvrSetSchedulerPolicy(0, "vr:app:render");
+  EXPECT_EQ(-EINVAL, error);
+
+  // uid=AID_NOBODY / gid=AID_GRAPHICS
+  ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
+      << "Failed to restore uid: " << strerror(errno);
+  ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
+      << "Failed to restore gid: " << strerror(errno);
+  ASSERT_EQ(0, setresgid(AID_GRAPHICS, AID_GRAPHICS, -1))
+      << "Failed to set gid: " << strerror(errno);
+  ASSERT_EQ(0, setresuid(AID_NOBODY, AID_NOBODY, -1))
+      << "Failed to set uid: " << strerror(errno);
+
+  // Unprivileged policies.
+  error = dvrSetSchedulerPolicy(0, "batch");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "background");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "foreground");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "normal");
+  EXPECT_EQ(0, error);
+
+  // Privileged policies.
+  error = dvrSetSchedulerPolicy(0, "audio:low");
+  EXPECT_EQ(-EINVAL, error);
+  error = dvrSetSchedulerPolicy(0, "audio:high");
+  EXPECT_EQ(-EINVAL, error);
+  error = dvrSetSchedulerPolicy(0, "graphics");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "graphics:low");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "graphics:high");
+  EXPECT_EQ(0, error);
+  error = dvrSetSchedulerPolicy(0, "sensors");
+  EXPECT_EQ(-EINVAL, error);
+  error = dvrSetSchedulerPolicy(0, "sensors:low");
+  EXPECT_EQ(-EINVAL, error);
+  error = dvrSetSchedulerPolicy(0, "sensors:high");
+  EXPECT_EQ(-EINVAL, error);
+  error = dvrSetSchedulerPolicy(0, "vr:system:arp");
+  EXPECT_EQ(-EINVAL, error);
+  error = dvrSetSchedulerPolicy(0, "vr:app:render");
+  EXPECT_EQ(-EINVAL, error);
+
+  if (trusted_uid != -1) {
+    // uid=<trusted uid> / gid=AID_NOBODY
+    ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
+        << "Failed to restore uid: " << strerror(errno);
+    ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
+        << "Failed to restore gid: " << strerror(errno);
+    ASSERT_EQ(0, setresgid(AID_NOBODY, AID_NOBODY, -1))
+        << "Failed to set gid: " << strerror(errno);
+    ASSERT_EQ(0, setresuid(trusted_uid, trusted_uid, -1))
+        << "Failed to set uid: " << strerror(errno);
+
+    // Unprivileged policies.
+    error = dvrSetSchedulerPolicy(0, "batch");
+    EXPECT_EQ(0, error);
+    error = dvrSetSchedulerPolicy(0, "background");
+    EXPECT_EQ(0, error);
+    error = dvrSetSchedulerPolicy(0, "foreground");
+    EXPECT_EQ(0, error);
+    error = dvrSetSchedulerPolicy(0, "normal");
+    EXPECT_EQ(0, error);
+
+    // Privileged policies.
+    error = dvrSetSchedulerPolicy(0, "audio:low");
+    EXPECT_EQ(-EINVAL, error);
+    error = dvrSetSchedulerPolicy(0, "audio:high");
+    EXPECT_EQ(-EINVAL, error);
+    error = dvrSetSchedulerPolicy(0, "graphics");
+    EXPECT_EQ(0, error);
+    error = dvrSetSchedulerPolicy(0, "graphics:low");
+    EXPECT_EQ(0, error);
+    error = dvrSetSchedulerPolicy(0, "graphics:high");
+    EXPECT_EQ(0, error);
+    error = dvrSetSchedulerPolicy(0, "sensors");
+    EXPECT_EQ(-EINVAL, error);
+    error = dvrSetSchedulerPolicy(0, "sensors:low");
+    EXPECT_EQ(-EINVAL, error);
+    error = dvrSetSchedulerPolicy(0, "sensors:high");
+    EXPECT_EQ(-EINVAL, error);
+    error = dvrSetSchedulerPolicy(0, "vr:system:arp");
+    EXPECT_EQ(0, error);
+    error = dvrSetSchedulerPolicy(0, "vr:app:render");
+    EXPECT_EQ(0, error);
+  }
+
+  // Restore original effective uid/gid.
+  ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
+      << "Failed to restore gid: " << strerror(errno);
+  ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
+      << "Failed to restore uid: " << strerror(errno);
+}
diff --git a/services/vr/virtual_touchpad/Android.bp b/services/vr/virtual_touchpad/Android.bp
index 3d5dfb2..6b11ce3 100644
--- a/services/vr/virtual_touchpad/Android.bp
+++ b/services/vr/virtual_touchpad/Android.bp
@@ -13,10 +13,15 @@
     "libutils",
 ]
 
+header_libraries = [
+    "libdvr_headers"
+]
+
 cc_library {
     srcs: src,
     export_include_dirs: ["include"],
     shared_libs: shared_libs,
+    header_libs: header_libraries,
     cppflags: ["-std=c++11"],
     cflags: ["-DLOG_TAG=\"VrVirtualTouchpad\""],
     name: "libvirtualtouchpad",
@@ -28,9 +33,6 @@
 test_static_libs = [
     "libcutils",
     "libvirtualtouchpad",
-]
-
-test_shared_libs = [
     "libbase",
     "liblog",
     "libutils",
@@ -41,7 +43,7 @@
 cc_test {
     srcs: test_src_files,
     static_libs: test_static_libs,
-    shared_libs: test_shared_libs,
+    header_libs: header_libraries,
     cppflags = [
         "-std=c++11",
     ],
@@ -77,6 +79,7 @@
     srcs: service_src,
     static_libs: service_static_libs,
     shared_libs: service_shared_libs,
+    header_libs: header_libraries,
     cppflags: ["-std=c++11"],
     cflags: [
         "-DLOG_TAG=\"VrVirtualTouchpad\"",
@@ -107,6 +110,7 @@
 cc_library {
     srcs: client_src,
     shared_libs: client_shared_libs,
+    header_libs: header_libraries,
     cppflags: ["-std=c++11"],
     cflags: ["-DLOG_TAG=\"VirtualTouchpadClient\""],
     host_ldlibs: ["-llog"],
diff --git a/services/vr/virtual_touchpad/DvrVirtualTouchpadClient.cpp b/services/vr/virtual_touchpad/DvrVirtualTouchpadClient.cpp
index eb152ed..3ab77a7 100644
--- a/services/vr/virtual_touchpad/DvrVirtualTouchpadClient.cpp
+++ b/services/vr/virtual_touchpad/DvrVirtualTouchpadClient.cpp
@@ -40,6 +40,11 @@
   return FromC(client)->ButtonState(touchpad, buttons);
 }
 
+int dvrVirtualTouchpadScroll(DvrVirtualTouchpad* client, int touchpad, float x,
+                             float y) {
+  return FromC(client)->Scroll(touchpad, x, y);
+}
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/services/vr/virtual_touchpad/EvdevInjector.cpp b/services/vr/virtual_touchpad/EvdevInjector.cpp
index a4ccdd0..7fad379 100644
--- a/services/vr/virtual_touchpad/EvdevInjector.cpp
+++ b/services/vr/virtual_touchpad/EvdevInjector.cpp
@@ -168,6 +168,25 @@
   return ConfigureAbs(ABS_MT_SLOT, 0, slots, 0, 0);
 }
 
+int EvdevInjector::ConfigureRel(uint16_t rel_type) {
+  ALOGV("ConfigureRel 0x%" PRIX16 "", rel_type);
+  if (rel_type < 0 || rel_type >= REL_CNT) {
+    ALOGE("EV_REL type 0x%" PRIX16 " out of range [0,0x%X)", rel_type, REL_CNT);
+    return Error(ERROR_REL_RANGE);
+  }
+  if (const int status = RequireState(State::CONFIGURING)) {
+    return status;
+  }
+  if (const int status = EnableEventType(EV_REL)) {
+    return status;
+  }
+  if (const int status = uinput_->IoctlSetInt(UI_SET_RELBIT, rel_type)) {
+    ALOGE("failed to enable EV_REL 0x%" PRIX16 "", rel_type);
+    return Error(status);
+  }
+  return 0;
+}
+
 int EvdevInjector::ConfigureEnd() {
   ALOGV("ConfigureEnd:");
   ALOGV("  name=\"%s\"", uidev_.name);
@@ -236,6 +255,10 @@
   return Send(EV_ABS, code, value);
 }
 
+int EvdevInjector::SendRel(uint16_t code, int32_t value) {
+  return Send(EV_REL, code, value);
+}
+
 int EvdevInjector::SendMultiTouchSlot(int32_t slot) {
   if (latest_slot_ != slot) {
     if (const int status = SendAbs(ABS_MT_SLOT, slot)) {
diff --git a/services/vr/virtual_touchpad/EvdevInjector.h b/services/vr/virtual_touchpad/EvdevInjector.h
index c69dbef..e87c959 100644
--- a/services/vr/virtual_touchpad/EvdevInjector.h
+++ b/services/vr/virtual_touchpad/EvdevInjector.h
@@ -30,6 +30,7 @@
     ERROR_KEY_RANGE = -3,       // |KEY_*|/|BTN_*| code out of range.
     ERROR_ABS_RANGE = -4,       // |ABS_*| code out of range.
     ERROR_SEQUENCING = -5,      // Configure/Send out of order.
+    ERROR_REL_RANGE = -6,       // |REL_*| code out of range.
   };
 
   // Key event |value| is not defined in <linux/input.h>.
@@ -87,6 +88,10 @@
   // Configure multitouch coordinate range.
   int ConfigureMultiTouchXY(int32_t x0, int32_t y0, int32_t x1, int32_t y1);
 
+  // Configure a relative axis.
+  // @param rel_type One of the |REL_*| constants from <linux/input.h>.
+  int ConfigureRel(uint16_t rel_type);
+
   // Complete configuration and create the input device.
   int ConfigureEnd();
 
@@ -96,6 +101,7 @@
   int SendSynReport();
   int SendKey(uint16_t code, int32_t value);
   int SendAbs(uint16_t code, int32_t value);
+  int SendRel(uint16_t code, int32_t value);
   int SendMultiTouchSlot(int32_t slot);
   int SendMultiTouchXY(int32_t slot, int32_t id, int32_t x, int32_t y);
   int SendMultiTouchLift(int32_t slot);
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp b/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp
index c7c8184..00e4ce6 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp
@@ -60,6 +60,13 @@
     return service_->buttonState(touchpad, buttons).transactionError();
   }
 
+  status_t Scroll(int touchpad, float x, float y) override {
+    if (service_ == nullptr) {
+      return NO_INIT;
+    }
+    return service_->scroll(touchpad, x, y).transactionError();
+  }
+
   void dumpInternal(String8& result) override {
     result.append("[virtual touchpad]\n");
     result.appendFormat("connected = %s\n\n",
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
index f0bdcd9..bcfdad3 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
@@ -28,6 +28,12 @@
 static constexpr int32_t kHeight = 0x10000;
 static constexpr int32_t kSlots = 2;
 
+static constexpr float kScrollScale = 100.0f;
+
+int32_t scale_relative_scroll(float x) {
+  return kScrollScale * x;
+}
+
 }  // anonymous namespace
 
 std::unique_ptr<VirtualTouchpad> VirtualTouchpadEvdev::Create() {
@@ -66,6 +72,8 @@
     touchpad.injector->ConfigureInputProperty(INPUT_PROP_DIRECT);
     touchpad.injector->ConfigureMultiTouchXY(0, 0, kWidth - 1, kHeight - 1);
     touchpad.injector->ConfigureAbsSlots(kSlots);
+    touchpad.injector->ConfigureRel(REL_WHEEL);
+    touchpad.injector->ConfigureRel(REL_HWHEEL);
     touchpad.injector->ConfigureKey(BTN_TOUCH);
     touchpad.injector->ConfigureKey(BTN_BACK);
     touchpad.injector->ConfigureEnd();
@@ -86,9 +94,6 @@
   if (touchpad_id < 0 || touchpad_id >= kTouchpads) {
     return EINVAL;
   }
-  if ((x < 0.0f) || (x >= 1.0f) || (y < 0.0f) || (y >= 1.0f)) {
-    return EINVAL;
-  }
   int32_t device_x = x * kWidth;
   int32_t device_y = y * kHeight;
   Touchpad& touchpad = touchpad_[touchpad_id];
@@ -162,6 +167,33 @@
   return touchpad.injector->GetError();
 }
 
+int VirtualTouchpadEvdev::Scroll(int touchpad_id, float x, float y) {
+  if (touchpad_id < 0 || touchpad_id >= kTouchpads) {
+    return EINVAL;
+  }
+  if ((x < -1.0f) || (x > 1.0f) || (y < -1.0f) || (y > 1.0f)) {
+    return EINVAL;
+  }
+  Touchpad& touchpad = touchpad_[touchpad_id];
+  if (!touchpad.injector) {
+    return EvdevInjector::ERROR_SEQUENCING;
+  }
+  touchpad.injector->ResetError();
+  const int32_t scaled_x = scale_relative_scroll(x);
+  const int32_t scaled_y = scale_relative_scroll(y);
+  ALOGV("(%f,%f) -> (%" PRId32 ",%" PRId32 ")", x, y, scaled_x, scaled_y);
+  if (scaled_x) {
+    touchpad.injector->SendRel(REL_HWHEEL, scaled_x);
+  }
+  if (scaled_y) {
+    touchpad.injector->SendRel(REL_WHEEL, scaled_y);
+  }
+  if (scaled_x || scaled_y) {
+    touchpad.injector->SendSynReport();
+  }
+  return touchpad.injector->GetError();
+}
+
 void VirtualTouchpadEvdev::dumpInternal(String8& result) {
   for (int i = 0; i < kTouchpads; ++i) {
     const auto& touchpad = touchpad_[i];
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
index 2fb8ff3..c9578bf 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
+++ b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
@@ -21,6 +21,7 @@
   status_t Detach() override;
   status_t Touch(int touchpad, float x, float y, float pressure) override;
   status_t ButtonState(int touchpad, int buttons) override;
+  status_t Scroll(int touchpad, float x, float y) override;
   void dumpInternal(String8& result) override;
 
  protected:
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
index 81edd32..523f890 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
@@ -87,6 +87,16 @@
   return binder::Status::ok();
 }
 
+binder::Status VirtualTouchpadService::scroll(int touchpad, float x, float y) {
+  if (!CheckPermissions()) {
+    return binder::Status::fromStatusT(PERMISSION_DENIED);
+  }
+  if (const status_t error = touchpad_->Scroll(touchpad, x, y)) {
+    return binder::Status::fromStatusT(error);
+  }
+  return binder::Status::ok();
+}
+
 status_t VirtualTouchpadService::dump(
     int fd, const Vector<String16>& args[[gnu::unused]]) {
   String8 result;
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.h b/services/vr/virtual_touchpad/VirtualTouchpadService.h
index cf236f9..2c46209 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadService.h
+++ b/services/vr/virtual_touchpad/VirtualTouchpadService.h
@@ -23,6 +23,7 @@
   binder::Status detach() override;
   binder::Status touch(int touchpad, float x, float y, float pressure) override;
   binder::Status buttonState(int touchpad, int buttons) override;
+  binder::Status scroll(int touchpad, float x, float y) override;
 
   // Implements BBinder::dump().
   status_t dump(int fd, const Vector<String16>& args) override;
diff --git a/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl b/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl
index 9cfb186..256203c 100644
--- a/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl
+++ b/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl
@@ -34,4 +34,15 @@
    * @param buttons A union of MotionEvent BUTTON_* values.
    */
   void buttonState(int touchpad, int buttons) = 3;
+
+  /**
+   * Generate a simulated scroll event.
+   *
+   * @param touchpad Selects touchpad.
+   * @param x Horizontal scroll increment.
+   * @param y Vertical scroll increment.
+   *
+   * Scroll values are in the range [-1.0, 1.0].
+   */
+  void scroll(int touchpad, float x, float y) = 4;
 }
diff --git a/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-0.idc b/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-0.idc
new file mode 100644
index 0000000..205e8b9
--- /dev/null
+++ b/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-0.idc
@@ -0,0 +1,26 @@
+# Copyright (C) 2017 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.
+
+#
+# Virtual touchpad for the primary display
+device.internal = 1
+
+touch.deviceType = touchScreen
+
+# Have input flinger treat injected scroll events like a G1 ball
+# rather than the default mouse wheel, because the latter requires
+# a visible pointer for targeting.
+device.type = rotaryEncoder
+device.res = 1.0e+2
+device.scalingFactor = 1.0e-2
diff --git a/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-1.idc b/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-1.idc
new file mode 100644
index 0000000..d9714e0
--- /dev/null
+++ b/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-1.idc
@@ -0,0 +1,31 @@
+# Copyright (C) 2017 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.
+
+#
+# Virtual touchpad for the VR virtual display
+device.internal = 1
+
+touch.deviceType = touchScreen
+
+# Have input flinger treat injected scroll events like a G1 ball
+# rather than the default mouse wheel, because the latter requires
+# a visible pointer for targeting.
+device.type = rotaryEncoder
+device.res = 1.0e+2
+device.scalingFactor = 1.0e-2
+
+# This displayID matches the unique ID of the virtual display created for VR.
+# This will indicate to input flinger than it should link this input device
+# with the virtual display.
+touch.displayId = virtual:android:277f1a09-b88d-4d1e-8716-796f114d080b
diff --git a/services/vr/virtual_touchpad/include/VirtualTouchpad.h b/services/vr/virtual_touchpad/include/VirtualTouchpad.h
index da3a0b7..99b72fc 100644
--- a/services/vr/virtual_touchpad/include/VirtualTouchpad.h
+++ b/services/vr/virtual_touchpad/include/VirtualTouchpad.h
@@ -61,6 +61,16 @@
   //
   virtual status_t ButtonState(int touchpad, int buttons) = 0;
 
+  // Generate a simulated scroll event.
+  //
+  // @param touchpad Touchpad selector index.
+  // @param x Horizontal scroll increment.
+  // @param y Vertical scroll increment.
+  //            Values must be in the range [-1.0, 1.0].
+  // @returns OK on success.
+  //
+  virtual status_t Scroll(int touchpad, float x, float y) = 0;
+
   // Report state for 'dumpsys'.
   virtual void dumpInternal(String8& result) = 0;
 
diff --git a/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h b/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h
index 23fb9f8..7d73f06 100644
--- a/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h
+++ b/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h
@@ -17,6 +17,7 @@
   status_t Detach() override;
   status_t Touch(int touchpad, float x, float y, float pressure) override;
   status_t ButtonState(int touchpad, int buttons) override;
+  status_t Scroll(int touchpad, float x, float y) override;
   void dumpInternal(String8& result) override;
 
  protected:
diff --git a/services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h b/services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h
index 08cca1b..09fb1cc 100644
--- a/services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h
+++ b/services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h
@@ -1,17 +1,14 @@
 #ifndef ANDROID_DVR_VIRTUAL_TOUCHPAD_C_CLIENT_H
 #define ANDROID_DVR_VIRTUAL_TOUCHPAD_C_CLIENT_H
 
+#include <dvr/dvr_api.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 typedef struct DvrVirtualTouchpad DvrVirtualTouchpad;
 
-enum {
-  DVR_VIRTUAL_TOUCHPAD_PRIMARY = 0,
-  DVR_VIRTUAL_TOUCHPAD_VIRTUAL = 1,
-};
-
 // Creates a new virtual touchpad client.
 //
 // @return Pointer to the created virtual touchpad client; nullptr on failure.
@@ -64,6 +61,17 @@
 int dvrVirtualTouchpadButtonState(DvrVirtualTouchpad* client, int touchpad,
                                   int buttons);
 
+// Generate a simulated scroll event.
+//
+// @param client Pointer to the virtual touchpad client.
+// @param touchpad Selects touchpad.
+// @param x Horizontal scroll increment.
+// @param y Vertical scroll increment.
+// @return Zero on success, status_t-style error code on failure.
+//
+int dvrVirtualTouchpadScroll(DvrVirtualTouchpad* client, int touchpad, float x,
+                             float y);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
index 564bcd7..b19b018 100644
--- a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
+++ b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
@@ -169,6 +169,11 @@
     expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_POSITION_Y);
     // From ConfigureAbsSlots(kSlots):
     expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_SLOT);
+    // From ConfigureRel(REL_WHEEL):
+    expect.IoctlSetInt(UI_SET_EVBIT, EV_REL);
+    expect.IoctlSetInt(UI_SET_RELBIT, REL_WHEEL);
+    // From ConfigureRel(REL_HWHEEL):
+    expect.IoctlSetInt(UI_SET_RELBIT, REL_HWHEEL);
     // From ConfigureKey(BTN_TOUCH):
     expect.IoctlSetInt(UI_SET_EVBIT, EV_KEY);
     expect.IoctlSetInt(UI_SET_KEYBIT, BTN_TOUCH);
diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
index a19fcf1..11161c6 100644
--- a/vulkan/api/vulkan.api
+++ b/vulkan/api/vulkan.api
@@ -28,7 +28,7 @@
 // API version (major.minor.patch)
 define VERSION_MAJOR 1
 define VERSION_MINOR 0
-define VERSION_PATCH 46
+define VERSION_PATCH 49
 
 // API limits
 define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256
@@ -320,7 +320,7 @@
 @extension("VK_KHR_shared_presentable_image") define VK_KHR_SHARED_PRESENTABLE_IMAGE_SPEC_VERSION 1
 @extension("VK_KHR_shared_presentable_image") define VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME "VK_KHR_shared_presentable_image"
 
-// 119
+// 120
 @extension("VK_KHR_get_surface_capabilities2") define VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION 1
 @extension("VK_KHR_get_surface_capabilities2") define VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME "VK_KHR_get_surface_capabilities2"
 
@@ -409,7 +409,7 @@
     //@extension("VK_KHR_swapchain") // 2
     VK_IMAGE_LAYOUT_PRESENT_SRC_KHR                         = 1000001002,
 
-    //@extension("VK_KHR_shared_presentable_image")
+    //@extension("VK_KHR_shared_presentable_image") // 112
     VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR                      = 1000111000,
 }
 
@@ -1005,9 +1005,6 @@
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHX  = 1000071002,
     VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHX            = 1000071003,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHX         = 1000071004,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHX          = 1000071005,
-    VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHX             = 1000071006,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHX   = 1000071007,
 
     //@extension("VK_KHX_external_memory") // 73
     VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHX    = 1000072000,
@@ -1086,10 +1083,10 @@
     //@extension("VK_EXT_hdr_metadata") // 106
     VK_STRUCTURE_TYPE_HDR_METADATA_EXT                          = 1000105000,
 
-    //@extension("VK_KHR_shared_presentable_image") // 111
+    //@extension("VK_KHR_shared_presentable_image") // 112
     VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR   = 1000111000,
 
-    //@extension("VK_KHR_get_surface_capabilities2") // 119
+    //@extension("VK_KHR_get_surface_capabilities2") // 120
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR        = 1000119000,
     VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR                = 1000119001,
     VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR                      = 1000119002,
@@ -1179,6 +1176,55 @@
     VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT                  = 1000099000,
 }
 
+enum VkObjectType {
+    VK_OBJECT_TYPE_UNKNOWN                                  = 0,
+    VK_OBJECT_TYPE_INSTANCE                                 = 1,
+    VK_OBJECT_TYPE_PHYSICAL_DEVICE                          = 2,
+    VK_OBJECT_TYPE_DEVICE                                   = 3,
+    VK_OBJECT_TYPE_QUEUE                                    = 4,
+    VK_OBJECT_TYPE_SEMAPHORE                                = 5,
+    VK_OBJECT_TYPE_COMMAND_BUFFER                           = 6,
+    VK_OBJECT_TYPE_FENCE                                    = 7,
+    VK_OBJECT_TYPE_DEVICE_MEMORY                            = 8,
+    VK_OBJECT_TYPE_BUFFER                                   = 9,
+    VK_OBJECT_TYPE_IMAGE                                    = 10,
+    VK_OBJECT_TYPE_EVENT                                    = 11,
+    VK_OBJECT_TYPE_QUERY_POOL                               = 12,
+    VK_OBJECT_TYPE_BUFFER_VIEW                              = 13,
+    VK_OBJECT_TYPE_IMAGE_VIEW                               = 14,
+    VK_OBJECT_TYPE_SHADER_MODULE                            = 15,
+    VK_OBJECT_TYPE_PIPELINE_CACHE                           = 16,
+    VK_OBJECT_TYPE_PIPELINE_LAYOUT                          = 17,
+    VK_OBJECT_TYPE_RENDER_PASS                              = 18,
+    VK_OBJECT_TYPE_PIPELINE                                 = 19,
+    VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT                    = 20,
+    VK_OBJECT_TYPE_SAMPLER                                  = 21,
+    VK_OBJECT_TYPE_DESCRIPTOR_POOL                          = 22,
+    VK_OBJECT_TYPE_DESCRIPTOR_SET                           = 23,
+    VK_OBJECT_TYPE_FRAMEBUFFER                              = 24,
+    VK_OBJECT_TYPE_COMMAND_POOL                             = 25,
+
+    //@extension("VK_KHR_surface") // 1
+    VK_OBJECT_TYPE_SURFACE_KHR                              = 1000000000,
+
+    //@extension("VK_KHR_swapchain") // 2
+    VK_OBJECT_TYPE_SWAPCHAIN_KHR                            = 1000001000,
+
+    //@extension("VK_KHR_display") // 3
+    VK_OBJECT_TYPE_DISPLAY_KHR                              = 1000002000,
+    VK_OBJECT_TYPE_DISPLAY_MODE_KHR                         = 1000002001,
+
+    //@extension("VK_KHR_debug_report") // 12
+    VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT                = 1000011000,
+
+    //@extension("VK_KHR_descriptor_update_template") // 86
+    VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR           = 1000085000,
+
+    //@extension("VK_NVX_device_generated_commands") // 87
+    VK_OBJECT_TYPE_OBJECT_TABLE_NVX                         = 1000086000,
+    VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX             = 1000086001,
+}
+
 @extension("VK_KHR_surface") // 1
 enum VkPresentModeKHR {
     VK_PRESENT_MODE_IMMEDIATE_KHR                           = 0x00000000,
@@ -1186,7 +1232,7 @@
     VK_PRESENT_MODE_FIFO_KHR                                = 0x00000002,
     VK_PRESENT_MODE_FIFO_RELAXED_KHR                        = 0x00000003,
 
-    //@extension("VK_KHR_shared_presentable_image")
+    //@extension("VK_KHR_shared_presentable_image") // 112
     VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR               = 1000111000,
     VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR           = 1000111001,
 }
@@ -1209,6 +1255,7 @@
     VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT                      = 1000104011,
     VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT                   = 1000104012,
     VK_COLOR_SPACE_PASS_THROUGH_EXT                         = 1000104013,
+    VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT              = 1000104014,
 }
 
 @extension("VK_EXT_debug_report") // 12
@@ -4261,28 +4308,28 @@
     f32                                             maxFrameAverageLightLevel
 }
 
-@extension("VK_KHR_shared_presentable_image") // 111
+@extension("VK_KHR_shared_presentable_image") // 112
 class VkSharedPresentSurfaceCapabilitiesKHR {
     VkStructureType                                 sType
     const void*                                     pNext
     VkImageUsageFlags                               sharedPresentSupportedUsageFlags
 }
 
-@extension("VK_KHR_get_surface_capabilities2") // 119
+@extension("VK_KHR_get_surface_capabilities2") // 120
 class VkPhysicalDeviceSurfaceInfo2KHR {
     VkStructureType                                 sType
     const void*                                     pNext
     VkSurfaceKHR                                    surface
 }
 
-@extension("VK_KHR_get_surface_capabilities2") // 119
+@extension("VK_KHR_get_surface_capabilities2") // 120
 class VkSurfaceCapabilities2KHR {
     VkStructureType                                 sType
     void*                                           pNext
     VkSurfaceCapabilitiesKHR                        surfaceCapabilities
 }
 
-@extension("VK_KHR_get_surface_capabilities2") // 119
+@extension("VK_KHR_get_surface_capabilities2") // 120
 class VkSurfaceFormat2KHR {
     VkStructureType                                 sType
     void*                                           pNext
@@ -7462,7 +7509,7 @@
     return ?
 }
 
-@extension("VK_KHR_get_surface_capabilities2") // 119
+@extension("VK_KHR_get_surface_capabilities2") // 120
 cmd VkResult vkGetPhysicalDeviceSurfaceCapabilities2KHR(
         VkPhysicalDevice                            physicalDevice,
         const VkPhysicalDeviceSurfaceInfo2KHR*      pSurfaceInfo,
@@ -7470,7 +7517,7 @@
     return ?
 }
 
-@extension("VK_KHR_get_surface_capabilities2") // 119
+@extension("VK_KHR_get_surface_capabilities2") // 120
 cmd VkResult vkGetPhysicalDeviceSurfaceFormats2KHR(
         VkPhysicalDevice                            physicalDevice,
         const VkPhysicalDeviceSurfaceInfo2KHR*      pSurfaceInfo,
diff --git a/vulkan/include/vulkan/vk_android_native_buffer.h b/vulkan/include/vulkan/vk_android_native_buffer.h
index 43a9a9c..d3e5f0f 100644
--- a/vulkan/include/vulkan/vk_android_native_buffer.h
+++ b/vulkan/include/vulkan/vk_android_native_buffer.h
@@ -17,7 +17,7 @@
 #ifndef __VK_ANDROID_NATIVE_BUFFER_H__
 #define __VK_ANDROID_NATIVE_BUFFER_H__
 
-#include <system/window.h>
+#include <cutils/native_handle.h>
 #include <vulkan/vulkan.h>
 
 #ifdef __cplusplus
diff --git a/vulkan/include/vulkan/vulkan.h b/vulkan/include/vulkan/vulkan.h
index 67eba86..f0209d6 100644
--- a/vulkan/include/vulkan/vulkan.h
+++ b/vulkan/include/vulkan/vulkan.h
@@ -43,11 +43,11 @@
 #define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff)
 #define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff)
 // Version of this file
-#define VK_HEADER_VERSION 46
+#define VK_HEADER_VERSION 49
 
 
 #define VK_NULL_HANDLE 0
-
+        
 
 
 #define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;
@@ -60,7 +60,7 @@
         #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;
 #endif
 #endif
-
+        
 
 
 typedef uint32_t VkFlags;
@@ -261,9 +261,6 @@
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHX = 1000071002,
     VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHX = 1000071003,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHX = 1000071004,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHX = 1000071005,
-    VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHX = 1000071006,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHX = 1000071007,
     VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHX = 1000072000,
     VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHX = 1000072001,
     VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHX = 1000072002,
@@ -901,6 +898,47 @@
     VK_SUBPASS_CONTENTS_MAX_ENUM = 0x7FFFFFFF
 } VkSubpassContents;
 
+typedef enum VkObjectType {
+    VK_OBJECT_TYPE_UNKNOWN = 0,
+    VK_OBJECT_TYPE_INSTANCE = 1,
+    VK_OBJECT_TYPE_PHYSICAL_DEVICE = 2,
+    VK_OBJECT_TYPE_DEVICE = 3,
+    VK_OBJECT_TYPE_QUEUE = 4,
+    VK_OBJECT_TYPE_SEMAPHORE = 5,
+    VK_OBJECT_TYPE_COMMAND_BUFFER = 6,
+    VK_OBJECT_TYPE_FENCE = 7,
+    VK_OBJECT_TYPE_DEVICE_MEMORY = 8,
+    VK_OBJECT_TYPE_BUFFER = 9,
+    VK_OBJECT_TYPE_IMAGE = 10,
+    VK_OBJECT_TYPE_EVENT = 11,
+    VK_OBJECT_TYPE_QUERY_POOL = 12,
+    VK_OBJECT_TYPE_BUFFER_VIEW = 13,
+    VK_OBJECT_TYPE_IMAGE_VIEW = 14,
+    VK_OBJECT_TYPE_SHADER_MODULE = 15,
+    VK_OBJECT_TYPE_PIPELINE_CACHE = 16,
+    VK_OBJECT_TYPE_PIPELINE_LAYOUT = 17,
+    VK_OBJECT_TYPE_RENDER_PASS = 18,
+    VK_OBJECT_TYPE_PIPELINE = 19,
+    VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT = 20,
+    VK_OBJECT_TYPE_SAMPLER = 21,
+    VK_OBJECT_TYPE_DESCRIPTOR_POOL = 22,
+    VK_OBJECT_TYPE_DESCRIPTOR_SET = 23,
+    VK_OBJECT_TYPE_FRAMEBUFFER = 24,
+    VK_OBJECT_TYPE_COMMAND_POOL = 25,
+    VK_OBJECT_TYPE_SURFACE_KHR = 1000000000,
+    VK_OBJECT_TYPE_SWAPCHAIN_KHR = 1000001000,
+    VK_OBJECT_TYPE_DISPLAY_KHR = 1000002000,
+    VK_OBJECT_TYPE_DISPLAY_MODE_KHR = 1000002001,
+    VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT = 1000011000,
+    VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR = 1000085000,
+    VK_OBJECT_TYPE_OBJECT_TABLE_NVX = 1000086000,
+    VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX = 1000086001,
+    VK_OBJECT_TYPE_BEGIN_RANGE = VK_OBJECT_TYPE_UNKNOWN,
+    VK_OBJECT_TYPE_END_RANGE = VK_OBJECT_TYPE_COMMAND_POOL,
+    VK_OBJECT_TYPE_RANGE_SIZE = (VK_OBJECT_TYPE_COMMAND_POOL - VK_OBJECT_TYPE_UNKNOWN + 1),
+    VK_OBJECT_TYPE_MAX_ENUM = 0x7FFFFFFF
+} VkObjectType;
+
 typedef VkFlags VkInstanceCreateFlags;
 
 typedef enum VkFormatFeatureFlagBits {
@@ -3317,6 +3355,7 @@
     VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011,
     VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012,
     VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013,
+    VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT = 1000104014,
     VK_COLOR_SPACE_BEGIN_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
     VK_COLOR_SPACE_END_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
     VK_COLOR_SPACE_RANGE_SIZE_KHR = (VK_COLOR_SPACE_SRGB_NONLINEAR_KHR - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR + 1),
@@ -4107,6 +4146,64 @@
     const void*                                 pData);
 #endif
 
+#define VK_KHR_shared_presentable_image 1
+#define VK_KHR_SHARED_PRESENTABLE_IMAGE_SPEC_VERSION 1
+#define VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME "VK_KHR_shared_presentable_image"
+
+typedef struct VkSharedPresentSurfaceCapabilitiesKHR {
+    VkStructureType      sType;
+    void*                pNext;
+    VkImageUsageFlags    sharedPresentSupportedUsageFlags;
+} VkSharedPresentSurfaceCapabilitiesKHR;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainStatusKHR)(VkDevice device, VkSwapchainKHR swapchain);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainStatusKHR(
+    VkDevice                                    device,
+    VkSwapchainKHR                              swapchain);
+#endif
+
+#define VK_KHR_get_surface_capabilities2 1
+#define VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION 1
+#define VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME "VK_KHR_get_surface_capabilities2"
+
+typedef struct VkPhysicalDeviceSurfaceInfo2KHR {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkSurfaceKHR       surface;
+} VkPhysicalDeviceSurfaceInfo2KHR;
+
+typedef struct VkSurfaceCapabilities2KHR {
+    VkStructureType             sType;
+    void*                       pNext;
+    VkSurfaceCapabilitiesKHR    surfaceCapabilities;
+} VkSurfaceCapabilities2KHR;
+
+typedef struct VkSurfaceFormat2KHR {
+    VkStructureType       sType;
+    void*                 pNext;
+    VkSurfaceFormatKHR    surfaceFormat;
+} VkSurfaceFormat2KHR;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, VkSurfaceCapabilities2KHR* pSurfaceCapabilities);
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceFormats2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, uint32_t* pSurfaceFormatCount, VkSurfaceFormat2KHR* pSurfaceFormats);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilities2KHR(
+    VkPhysicalDevice                            physicalDevice,
+    const VkPhysicalDeviceSurfaceInfo2KHR*      pSurfaceInfo,
+    VkSurfaceCapabilities2KHR*                  pSurfaceCapabilities);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormats2KHR(
+    VkPhysicalDevice                            physicalDevice,
+    const VkPhysicalDeviceSurfaceInfo2KHR*      pSurfaceInfo,
+    uint32_t*                                   pSurfaceFormatCount,
+    VkSurfaceFormat2KHR*                        pSurfaceFormats);
+#endif
+
 #define VK_EXT_debug_report 1
 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT)
 
@@ -5733,7 +5830,7 @@
 #endif
 
 #define VK_EXT_swapchain_colorspace 1
-#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 2
+#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 3
 #define VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace"
 
 
@@ -5770,66 +5867,6 @@
     const VkHdrMetadataEXT*                     pMetadata);
 #endif
 
-#define VK_KHR_shared_presentable_image 1
-#define VK_KHR_SHARED_PRESENTABLE_IMAGE_SPEC_VERSION 1
-#define VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME "VK_KHR_shared_presentable_image"
-
-typedef struct VkSharedPresentSurfaceCapabilitiesKHR {
-    VkStructureType      sType;
-    void*                pNext;
-    VkImageUsageFlags    sharedPresentSupportedUsageFlags;
-} VkSharedPresentSurfaceCapabilitiesKHR;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainStatusKHR)(VkDevice device, VkSwapchainKHR swapchain);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainStatusKHR(
-    VkDevice                                    device,
-    VkSwapchainKHR                              swapchain);
-#endif
-
-#define VK_KHR_get_surface_capabilities2 1
-#define VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION 1
-#define VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME "VK_KHR_get_surface_capabilities2"
-
-typedef struct VkPhysicalDeviceSurfaceInfo2KHR {
-    VkStructureType    sType;
-    const void*        pNext;
-    VkSurfaceKHR       surface;
-} VkPhysicalDeviceSurfaceInfo2KHR;
-
-typedef struct VkSurfaceCapabilities2KHR {
-    VkStructureType             sType;
-    void*                       pNext;
-    VkSurfaceCapabilitiesKHR    surfaceCapabilities;
-} VkSurfaceCapabilities2KHR;
-
-typedef struct VkSurfaceFormat2KHR {
-    VkStructureType       sType;
-    void*                 pNext;
-    VkSurfaceFormatKHR    surfaceFormat;
-} VkSurfaceFormat2KHR;
-
-
-typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, VkSurfaceCapabilities2KHR* pSurfaceCapabilities);
-typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceFormats2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, uint32_t* pSurfaceFormatCount, VkSurfaceFormat2KHR* pSurfaceFormats);
-
-#ifndef VK_NO_PROTOTYPES
-VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilities2KHR(
-    VkPhysicalDevice                            physicalDevice,
-    const VkPhysicalDeviceSurfaceInfo2KHR*      pSurfaceInfo,
-    VkSurfaceCapabilities2KHR*                  pSurfaceCapabilities);
-
-VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormats2KHR(
-    VkPhysicalDevice                            physicalDevice,
-    const VkPhysicalDeviceSurfaceInfo2KHR*      pSurfaceInfo,
-    uint32_t*                                   pSurfaceFormatCount,
-    VkSurfaceFormat2KHR*                        pSurfaceFormats);
-#endif
-
-
-
 #ifdef VK_USE_PLATFORM_IOS_MVK
 #define VK_MVK_ios_surface 1
 #define VK_MVK_IOS_SURFACE_SPEC_VERSION   2
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 6149894..5f9b357 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -75,6 +75,7 @@
         "libbase",
         "liblog",
         "libui",
+        "libgraphicsenv",
         "libutils",
         "libcutils",
         "libz",
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 6f425f5..947a2f7 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -28,9 +28,11 @@
 
 #include <android/dlext.h>
 #include <cutils/properties.h>
-#include <ui/GraphicsEnv.h>
+#include <graphicsenv/GraphicsEnv.h>
 #include <utils/Vector.h>
 
+#include "android-base/properties.h"
+
 #include "driver.h"
 #include "stubhal.h"
 
@@ -822,9 +824,9 @@
 
     // conditionally add VK_GOOGLE_display_timing if present timestamps are
     // supported by the driver:
-    char timestamp_property[PROPERTY_VALUE_MAX];
-    property_get("service.sf.present_timestamp", timestamp_property, "1");
-    if (strcmp(timestamp_property, "1") == 0) {
+    const std::string timestamp_property("service.sf.present_timestamp");
+    android::base::WaitForPropertyCreation(timestamp_property);
+    if (android::base::GetBoolProperty(timestamp_property, true)) {
         loader_extensions.push_back({
                 VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME,
                 VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION});
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index e2c8c06..a346c0a 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -22,6 +22,7 @@
 #include <sync/sync.h>
 #include <utils/StrongPointer.h>
 #include <utils/Vector.h>
+#include <system/window.h>
 
 #include "driver.h"
 
@@ -429,6 +430,8 @@
             return HAL_DATASPACE_DISPLAY_P3;
         case VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT:
             return HAL_DATASPACE_V0_SCRGB_LINEAR;
+        case VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT:
+            return HAL_DATASPACE_V0_SCRGB;
         case VK_COLOR_SPACE_DCI_P3_LINEAR_EXT:
             return HAL_DATASPACE_DCI_P3_LINEAR;
         case VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT:
@@ -639,6 +642,8 @@
     const VkSurfaceFormatKHR kWideColorFormats[] = {
         {VK_FORMAT_R16G16B16A16_SFLOAT,
          VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT},
+        {VK_FORMAT_R16G16B16A16_SFLOAT,
+         VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT},
         {VK_FORMAT_A2R10G10B10_UNORM_PACK32,
          VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT},
     };
@@ -1014,7 +1019,7 @@
             return VK_ERROR_SURFACE_LOST_KHR;
         }
     }
-    err = native_window_set_usage(surface.window.get(), gralloc_usage);
+    err = native_window_set_usage(surface.window.get(), uint64_t(gralloc_usage));
     if (err != 0) {
         // TODO(jessehall): Improve error reporting. Can we enumerate possible
         // errors and translate them to valid Vulkan result codes?
@@ -1091,8 +1096,8 @@
         image_native_buffer.handle = img.buffer->handle;
         image_native_buffer.stride = img.buffer->stride;
         image_native_buffer.format = img.buffer->format;
-        image_native_buffer.usage = img.buffer->usage;
-        android_convertGralloc0To1Usage(img.buffer->usage,
+        image_native_buffer.usage = int(img.buffer->usage);
+        android_convertGralloc0To1Usage(int(img.buffer->usage),
             &image_native_buffer.usage2.producer,
             &image_native_buffer.usage2.consumer);