Merge "media: mechanism to set/get vendor-extension configs for OMX component"
diff --git a/cmds/atrace/Android.bp b/cmds/atrace/Android.bp
index 225de20..69ed416 100644
--- a/cmds/atrace/Android.bp
+++ b/cmds/atrace/Android.bp
@@ -16,9 +16,6 @@
         "libz",
         "libbase",
     ],
-    static_libs: [
-        "libpdx_default_transport",
-    ],
 
     init_rc: ["atrace.rc"],
 }
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 14eff03..05e1615 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -18,7 +18,6 @@
 
 #include <errno.h>
 #include <fcntl.h>
-#include <ftw.h>
 #include <getopt.h>
 #include <inttypes.h>
 #include <signal.h>
@@ -42,7 +41,6 @@
 #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>
@@ -50,7 +48,6 @@
 #include <android-base/file.h>
 
 using namespace android;
-using pdx::default_transport::ServiceUtility;
 
 using std::string;
 #define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
@@ -568,46 +565,6 @@
     }
 }
 
-// Sends the sysprop_change message to the service at fpath, so it re-reads its
-// system properties. Returns 0 on success or a negated errno code on failure.
-static int pokeOnePDXService(const char *fpath, const struct stat * /*sb*/,
-                             int typeflag, struct FTW * /*ftwbuf*/)
-{
-    const bool kIgnoreErrors = true;
-
-    if (typeflag == FTW_F) {
-        int error;
-        auto utility = ServiceUtility::Create(fpath, &error);
-        if (!utility) {
-            if (error != -ECONNREFUSED) {
-                ALOGE("pokeOnePDXService: Failed to open %s, %s.", fpath,
-                      strerror(-error));
-            }
-            return kIgnoreErrors ? 0 : error;
-        }
-
-        auto status = utility->ReloadSystemProperties();
-        if (!status) {
-            ALOGE("pokeOnePDXService: Failed to send sysprop change to %s, "
-                  "error %d, %s.", fpath, status.error(),
-                  status.GetErrorMessage().c_str());
-            return kIgnoreErrors ? 0 : -status.error();
-        }
-    }
-
-    return 0;
-}
-
-// Pokes all the PDX processes in the system to get them to re-read
-// their system properties. Returns true on success, false on failure.
-static bool pokePDXServices()
-{
-    const int kMaxDepth = 16;
-    const int result = nftw(ServiceUtility::GetRootEndpointPath().c_str(),
-                            pokeOnePDXService, kMaxDepth, FTW_PHYS);
-    return result == 0 ? true : false;
-}
-
 // Set the trace tags that userland tracing uses, and poke the running
 // processes to pick up the new value.
 static bool setTagsProperty(uint64_t tags)
@@ -851,7 +808,6 @@
     ok &= setAppCmdlineProperty(&packageList[0]);
     ok &= pokeBinderServices();
     pokeHalServices();
-    ok &= pokePDXServices();
 
     // 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.
@@ -889,7 +845,6 @@
     setTagsProperty(0);
     clearAppProperties();
     pokeBinderServices();
-    pokePDXServices();
 
     // Set the options back to their defaults.
     setTraceOverwriteEnable(true);
diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk
index d1e94ed..a407ea2 100644
--- a/cmds/dumpstate/Android.mk
+++ b/cmds/dumpstate/Android.mk
@@ -16,6 +16,7 @@
         utils.cpp
 COMMON_SHARED_LIBRARIES := \
         android.hardware.dumpstate@1.0 \
+        android.hidl.manager@1.0 \
         libhidlbase \
         libbase \
         libbinder \
@@ -93,10 +94,6 @@
 # ==========#
 include $(CLEAR_VARS)
 
-ifdef BOARD_WLAN_DEVICE
-LOCAL_CFLAGS := -DFWDUMP_$(BOARD_WLAN_DEVICE)
-endif
-
 LOCAL_SRC_FILES := $(COMMON_SRC_FILES) \
         DumpstateService.cpp \
         dumpstate.cpp
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index 5430956..efe0466 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -97,6 +97,8 @@
     dprintf(fd, "now: %ld\n", ds_.now_);
     dprintf(fd, "is_zipping: %s\n", ds_.IsZipping() ? "true" : "false");
     dprintf(fd, "listener: %s\n", ds_.listener_name_.c_str());
+    dprintf(fd, "notification title: %s\n", ds_.notification_title.c_str());
+    dprintf(fd, "notification description: %s\n", ds_.notification_description.c_str());
 
     return NO_ERROR;
 }
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 1cf00f5..f898b90 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -116,6 +116,8 @@
 static constexpr char PROPERTY_EXTRA_OPTIONS[] = "dumpstate.options";
 static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id";
 static constexpr char PROPERTY_VERSION[] = "dumpstate.version";
+static constexpr char PROPERTY_EXTRA_TITLE[] = "dumpstate.options.title";
+static constexpr char PROPERTY_EXTRA_DESCRIPTION[] = "dumpstate.options.description";
 
 static const CommandOptions AS_ROOT_20 = CommandOptions::WithTimeout(20).AsRoot().Build();
 
@@ -1037,26 +1039,11 @@
     RunCommand("WIFI NETWORKS", {"wpa_cli", "IFNAME=wlan0", "list_networks"},
                CommandOptions::WithTimeout(20).Build());
 
-#ifdef FWDUMP_bcmdhd
-    RunCommand("ND OFFLOAD TABLE", {WLUTIL, "nd_hostip"}, CommandOptions::AS_ROOT);
-
-    RunCommand("DUMP WIFI INTERNAL COUNTERS (1)", {WLUTIL, "counters"}, AS_ROOT_20);
-
-    RunCommand("ND OFFLOAD STATUS (1)", {WLUTIL, "nd_status"}, CommandOptions::AS_ROOT);
-
-#endif
     DumpFile("INTERRUPTS (1)", "/proc/interrupts");
 
     RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
                CommandOptions::WithTimeout(10).Build());
 
-#ifdef FWDUMP_bcmdhd
-    RunCommand("DUMP WIFI STATUS", {"dhdutil", "-i", "wlan0", "dump"}, AS_ROOT_20);
-
-    RunCommand("DUMP WIFI INTERNAL COUNTERS (2)", {WLUTIL, "counters"}, AS_ROOT_20);
-
-    RunCommand("ND OFFLOAD STATUS (2)", {WLUTIL, "nd_status"}, CommandOptions::AS_ROOT);
-#endif
     DumpFile("INTERRUPTS (2)", "/proc/interrupts");
 
     RunCommand("SYSTEM PROPERTIES", {"getprop"});
@@ -1452,6 +1439,20 @@
         android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
     }
 
+    ds.notification_title = android::base::GetProperty(PROPERTY_EXTRA_TITLE, "");
+    if (!ds.notification_title.empty()) {
+        // Reset the property
+        android::base::SetProperty(PROPERTY_EXTRA_TITLE, "");
+
+        ds.notification_description = android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
+        if (!ds.notification_description.empty()) {
+            // Reset the property
+            android::base::SetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
+        }
+        MYLOGD("notification (title:  %s, description: %s)\n",
+               ds.notification_title.c_str(), ds.notification_description.c_str());
+    }
+
     if ((do_zip_file || do_add_date || ds.update_progress_ || do_broadcast) && !use_outfile) {
         ExitOnInvalidArgs();
     }
@@ -1536,7 +1537,7 @@
     if (is_redirecting) {
         ds.bugreport_dir_ = dirname(use_outfile);
         std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
-        std::string device_name = android::base::GetProperty("ro.product.device", "UNKNOWN_DEVICE");
+        std::string device_name = android::base::GetProperty("ro.product.name", "UNKNOWN_DEVICE");
         ds.base_name_ = android::base::StringPrintf("%s-%s-%s", basename(use_outfile),
                                                     device_name.c_str(), build_id.c_str());
         if (do_add_date) {
@@ -1814,6 +1815,16 @@
                 am_args.push_back("android.intent.extra.SCREENSHOT");
                 am_args.push_back(ds.screenshot_path_);
             }
+            if (!ds.notification_title.empty()) {
+                am_args.push_back("--es");
+                am_args.push_back("android.intent.extra.TITLE");
+                am_args.push_back(ds.notification_title);
+                if (!ds.notification_description.empty()) {
+                    am_args.push_back("--es");
+                    am_args.push_back("android.intent.extra.DESCRIPTION");
+                    am_args.push_back(ds.notification_description);
+                }
+            }
             if (is_remote_mode) {
                 am_args.push_back("--es");
                 am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 7fcb980..f02303b 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -333,6 +333,10 @@
     android::sp<android::os::IDumpstateListener> listener_;
     std::string listener_name_;
 
+    // Notification title and description
+    std::string notification_title;
+    std::string notification_description;
+
   private:
     // Used by GetInstance() only.
     Dumpstate(const std::string& version = VERSION_CURRENT);
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 4655d33..cc4144a 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -38,6 +38,7 @@
 #include <time.h>
 #include <unistd.h>
 
+#include <set>
 #include <string>
 #include <vector>
 
@@ -45,6 +46,7 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
 #include <cutils/properties.h>
 #include <cutils/sockets.h>
 #include <debuggerd/client.h>
@@ -58,6 +60,8 @@
 using android::os::dumpstate::DumpFileToFd;
 using android::os::dumpstate::PropertiesHelper;
 
+// Keep in sync with
+// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
 static const int TRACE_DUMP_TIMEOUT_MS = 10000; // 10 seconds
 
 /* Most simple commands have 10 as timeout, so 5 is a good estimate */
@@ -76,7 +80,6 @@
         "/system/bin/audioserver",
         "/system/bin/cameraserver",
         "/system/bin/drmserver",
-        "/system/bin/mediacodec",     // media.codec
         "/system/bin/mediadrmserver",
         "/system/bin/mediaextractor", // media.extractor
         "/system/bin/mediaserver",
@@ -86,6 +89,16 @@
         NULL,
 };
 
+/* list of hal interface to dump containing process during native dumps */
+static const char* hal_interfaces_to_dump[] {
+        "android.hardware.audio@2.0::IDevicesFactory",
+        "android.hardware.bluetooth@1.0::IBluetoothHci",
+        "android.hardware.camera.provider@2.4::ICameraProvider",
+        "android.hardware.vr@1.0::IVr",
+        "android.hardware.media.omx@1.0::IOmx",
+        NULL,
+};
+
 // Reasonable value for max stats.
 static const int STATS_MAX_N_RUNS = 1000;
 static const long STATS_MAX_AVERAGE = 100000;
@@ -791,6 +804,15 @@
     _redirect_to_file(redirect, path, O_APPEND);
 }
 
+static bool should_dump_hal_interface(const char* interface) {
+    for (const char** i = hal_interfaces_to_dump; *i; i++) {
+        if (!strcmp(*i, interface)) {
+            return true;
+        }
+    }
+    return false;
+}
+
 static bool should_dump_native_traces(const char* path) {
     for (const char** p = native_processes_to_dump; *p; p++) {
         if (!strcmp(*p, path)) {
@@ -800,6 +822,35 @@
     return false;
 }
 
+std::set<int> get_interesting_hal_pids() {
+    using android::hidl::manager::V1_0::IServiceManager;
+    using android::sp;
+    using android::hardware::Return;
+
+    sp<IServiceManager> manager = IServiceManager::getService();
+    std::set<int> pids;
+
+    Return<void> ret = manager->debugDump([&](auto& hals) {
+        for (const auto &info : hals) {
+            if (info.pid == static_cast<int>(IServiceManager::PidConstant::NO_PID)) {
+                continue;
+            }
+
+            if (!should_dump_hal_interface(info.interfaceName)) {
+                continue;
+            }
+
+            pids.insert(info.pid);
+        }
+    });
+
+    if (!ret.isOk()) {
+        MYLOGE("Could not get list of HAL PIDs: %s\n", ret.description().c_str());
+    }
+
+    return pids; // whether it was okay or not
+}
+
 /* dump Dalvik and native stack traces, return the trace file location (NULL if none) */
 const char *dump_traces() {
     DurationReporter duration_reporter("DUMP TRACES");
@@ -834,6 +885,7 @@
     /* Variables below must be initialized before 'goto' statements */
     int dalvik_found = 0;
     int ifd, wfd = -1;
+    std::set<int> hal_pids = get_interesting_hal_pids();
 
     /* walk /proc and kill -QUIT all Dalvik processes */
     DIR *proc = opendir("/proc");
@@ -908,7 +960,8 @@
                 dprintf(fd, "[dump dalvik stack %d: %.3fs elapsed]\n", pid,
                         (float)(Nanotime() - start) / NANOS_PER_SEC);
             }
-        } else if (should_dump_native_traces(data)) {
+        } else if (should_dump_native_traces(data) ||
+                   hal_pids.find(pid) != hal_pids.end()) {
             /* dump native process if appropriate */
             if (lseek(fd, 0, SEEK_END) < 0) {
                 MYLOGE("lseek: %s\n", strerror(errno));
diff --git a/cmds/installd/Android.mk b/cmds/installd/Android.mk
index f567a10..be1a434 100644
--- a/cmds/installd/Android.mk
+++ b/cmds/installd/Android.mk
@@ -23,10 +23,9 @@
 LOCAL_CFLAGS += -DART_BASE_ADDRESS_MIN_DELTA=$(LOCAL_LIBART_IMG_HOST_MIN_BASE_ADDRESS_DELTA)
 LOCAL_CFLAGS += -DART_BASE_ADDRESS_MAX_DELTA=$(LOCAL_LIBART_IMG_HOST_MAX_BASE_ADDRESS_DELTA)
 
-LOCAL_SRC_FILES := otapreopt.cpp InstalldNativeService.cpp globals.cpp utils.cpp dexopt.cpp binder/android/os/IInstalld.aidl
+LOCAL_SRC_FILES := otapreopt.cpp globals.cpp utils.cpp dexopt.cpp
 LOCAL_SHARED_LIBRARIES := \
     libbase \
-    libbinder \
     libcutils \
     liblog \
     liblogwrap \
diff --git a/cmds/installd/CacheItem.cpp b/cmds/installd/CacheItem.cpp
index 0349b0f..17eb7ff 100644
--- a/cmds/installd/CacheItem.cpp
+++ b/cmds/installd/CacheItem.cpp
@@ -38,12 +38,12 @@
 
     mParent = static_cast<CacheItem*>(p->fts_parent->fts_pointer);
     if (mParent) {
-        atomic = mParent->atomic;
+        group = mParent->group;
         tombstone = mParent->tombstone;
         mName = p->fts_name;
         mName.insert(0, "/");
     } else {
-        atomic = false;
+        group = false;
         tombstone = false;
         mName = p->fts_path;
     }
diff --git a/cmds/installd/CacheItem.h b/cmds/installd/CacheItem.h
index afbb15d..84b77aa 100644
--- a/cmds/installd/CacheItem.h
+++ b/cmds/installd/CacheItem.h
@@ -31,8 +31,8 @@
 
 /**
  * Single cache item that can be purged to free up space. This may be an
- * isolated file, or an entire directory tree that should be atomically
- * deleted.
+ * isolated file, or an entire directory tree that should be deleted as a
+ * group.
  */
 class CacheItem {
 public:
@@ -46,7 +46,7 @@
 
     short level;
     bool directory;
-    bool atomic;
+    bool group;
     bool tombstone;
     int64_t size;
     time_t modified;
diff --git a/cmds/installd/CacheTracker.cpp b/cmds/installd/CacheTracker.cpp
index fada699..4bfc834 100644
--- a/cmds/installd/CacheTracker.cpp
+++ b/cmds/installd/CacheTracker.cpp
@@ -106,11 +106,11 @@
         switch (p->fts_info) {
         case FTS_D: {
             auto item = static_cast<CacheItem*>(p->fts_pointer);
-            item->atomic |= (getxattr(p->fts_path, kXattrCacheAtomic, nullptr, 0) >= 0);
+            item->group |= (getxattr(p->fts_path, kXattrCacheGroup, nullptr, 0) >= 0);
             item->tombstone |= (getxattr(p->fts_path, kXattrCacheTombstone, nullptr, 0) >= 0);
 
-            // When atomic, immediately collect all files under tree
-            if (item->atomic) {
+            // When group, immediately collect all files under tree
+            if (item->group) {
                 while ((p = fts_read(fts)) != nullptr) {
                     if (p->fts_info == FTS_DP && p->fts_level == item->level) break;
                     switch (p->fts_info) {
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 9006330..ca4be0a 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -768,15 +768,17 @@
     auto noop = (flags & FLAG_FREE_CACHE_NOOP);
 
     int64_t free = data_disk_free(data_path);
-    int64_t needed = freeStorageSize - free;
     if (free < 0) {
         return error("Failed to determine free space for " + data_path);
-    } else if (free >= freeStorageSize) {
-        return ok();
     }
 
-    LOG(DEBUG) << "Found " << data_path << " with " << free << " free; caller requested "
-            << freeStorageSize;
+    int64_t needed = freeStorageSize - free;
+    LOG(DEBUG) << "Device " << data_path << " has " << free << " free; requested "
+            << freeStorageSize << "; needed " << needed;
+
+    if (free >= freeStorageSize) {
+        return ok();
+    }
 
     if (flags & FLAG_FREE_CACHE_V2) {
         // This new cache strategy fairly removes files from UIDs by deleting
@@ -811,7 +813,9 @@
                             tracker->cacheQuota = mCacheQuotas[uid];
                         }
                         if (tracker->cacheQuota == 0) {
+#if MEASURE_DEBUG
                             LOG(WARNING) << "UID " << uid << " has no cache quota; assuming 64MB";
+#endif
                             tracker->cacheQuota = 67108864;
                         }
                         trackers[uid] = tracker;
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 5bb2ce7..f7e8d13 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -1564,7 +1564,7 @@
             ALOGV("DexInv: --- END '%s' (success) ---\n", dex_path);
         } else {
             ALOGE("DexInv: --- END '%s' --- status=0x%04x, process failed\n", dex_path, res);
-            return -1;
+            return res;
         }
     }
 
diff --git a/cmds/installd/globals.h b/cmds/installd/globals.h
index 8242eec..c90beec 100644
--- a/cmds/installd/globals.h
+++ b/cmds/installd/globals.h
@@ -20,8 +20,6 @@
 
 #include <inttypes.h>
 
-#include "InstalldNativeService.h"
-
 namespace android {
 namespace installd {
 
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index c74c65b..82b8cc2 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -36,7 +36,6 @@
 #include <log/log.h>
 #include <private/android_filesystem_config.h>
 
-#include "InstalldNativeService.h"
 #include "dexopt.h"
 #include "file_parsing.h"
 #include "globals.h"
diff --git a/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp
index 50a47d2..360f71a 100644
--- a/cmds/installd/tests/installd_cache_test.cpp
+++ b/cmds/installd/tests/installd_cache_test.cpp
@@ -101,6 +101,7 @@
     if (!statvfs("/data/local/tmp", &buf)) {
         return buf.f_bavail * buf.f_bsize;
     } else {
+        PLOG(ERROR) << "Failed to statvfs";
         return -1;
     }
 }
@@ -132,6 +133,8 @@
 };
 
 TEST_F(CacheTest, FreeCache_All) {
+    LOG(INFO) << "FreeCache_All";
+
     mkdir("com.example");
     touch("com.example/normal", 1 * kMbInBytes, 60);
     mkdir("com.example/cache");
@@ -152,6 +155,8 @@
 }
 
 TEST_F(CacheTest, FreeCache_Age) {
+    LOG(INFO) << "FreeCache_Age";
+
     mkdir("com.example");
     mkdir("com.example/cache");
     mkdir("com.example/cache/foo");
@@ -172,6 +177,8 @@
 }
 
 TEST_F(CacheTest, FreeCache_Tombstone) {
+    LOG(INFO) << "FreeCache_Tombstone";
+
     mkdir("com.example");
     mkdir("com.example/cache");
     mkdir("com.example/cache/foo");
@@ -201,14 +208,16 @@
     EXPECT_EQ(0, size("com.example/cache/bar/bar2"));
 }
 
-TEST_F(CacheTest, FreeCache_Atomic) {
+TEST_F(CacheTest, FreeCache_Group) {
+    LOG(INFO) << "FreeCache_Group";
+
     mkdir("com.example");
     mkdir("com.example/cache");
     mkdir("com.example/cache/foo");
     touch("com.example/cache/foo/foo1", 1 * kMbInBytes, 60);
     touch("com.example/cache/foo/foo2", 1 * kMbInBytes, 120);
 
-    setxattr("com.example/cache/foo", "user.cache_atomic");
+    setxattr("com.example/cache/foo", "user.cache_group");
 
     service->freeCache(testUuid, free() + kKbInBytes,
             FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
@@ -217,25 +226,25 @@
     EXPECT_EQ(-1, exists("com.example/cache/foo/foo2"));
 }
 
-TEST_F(CacheTest, FreeCache_AtomicTombstone) {
-    LOG(INFO) << "FreeCache_AtomicTombstone";
+TEST_F(CacheTest, FreeCache_GroupTombstone) {
+    LOG(INFO) << "FreeCache_GroupTombstone";
 
     mkdir("com.example");
     mkdir("com.example/cache");
 
     // this dir must look really old for some reason?
-    mkdir("com.example/cache/atomic");
-    touch("com.example/cache/atomic/file1", kMbInBytes, 120);
-    touch("com.example/cache/atomic/file2", kMbInBytes, 120);
-    mkdir("com.example/cache/atomic/dir");
-    touch("com.example/cache/atomic/dir/file1", kMbInBytes, 120);
-    touch("com.example/cache/atomic/dir/file2", kMbInBytes, 120);
-    mkdir("com.example/cache/atomic/tomb");
-    touch("com.example/cache/atomic/tomb/file1", kMbInBytes, 120);
-    touch("com.example/cache/atomic/tomb/file2", kMbInBytes, 120);
-    mkdir("com.example/cache/atomic/tomb/dir");
-    touch("com.example/cache/atomic/tomb/dir/file1", kMbInBytes, 120);
-    touch("com.example/cache/atomic/tomb/dir/file2", kMbInBytes, 120);
+    mkdir("com.example/cache/group");
+    touch("com.example/cache/group/file1", kMbInBytes, 120);
+    touch("com.example/cache/group/file2", kMbInBytes, 120);
+    mkdir("com.example/cache/group/dir");
+    touch("com.example/cache/group/dir/file1", kMbInBytes, 120);
+    touch("com.example/cache/group/dir/file2", kMbInBytes, 120);
+    mkdir("com.example/cache/group/tomb");
+    touch("com.example/cache/group/tomb/file1", kMbInBytes, 120);
+    touch("com.example/cache/group/tomb/file2", kMbInBytes, 120);
+    mkdir("com.example/cache/group/tomb/dir");
+    touch("com.example/cache/group/tomb/dir/file1", kMbInBytes, 120);
+    touch("com.example/cache/group/tomb/dir/file2", kMbInBytes, 120);
 
     mkdir("com.example/cache/tomb");
     touch("com.example/cache/tomb/file1", kMbInBytes, 240);
@@ -243,80 +252,80 @@
     mkdir("com.example/cache/tomb/dir");
     touch("com.example/cache/tomb/dir/file1", kMbInBytes, 240);
     touch("com.example/cache/tomb/dir/file2", kMbInBytes, 240);
-    mkdir("com.example/cache/tomb/atomic");
-    touch("com.example/cache/tomb/atomic/file1", kMbInBytes, 60);
-    touch("com.example/cache/tomb/atomic/file2", kMbInBytes, 60);
-    mkdir("com.example/cache/tomb/atomic/dir");
-    touch("com.example/cache/tomb/atomic/dir/file1", kMbInBytes, 60);
-    touch("com.example/cache/tomb/atomic/dir/file2", kMbInBytes, 60);
+    mkdir("com.example/cache/tomb/group");
+    touch("com.example/cache/tomb/group/file1", kMbInBytes, 60);
+    touch("com.example/cache/tomb/group/file2", kMbInBytes, 60);
+    mkdir("com.example/cache/tomb/group/dir");
+    touch("com.example/cache/tomb/group/dir/file1", kMbInBytes, 60);
+    touch("com.example/cache/tomb/group/dir/file2", kMbInBytes, 60);
 
-    setxattr("com.example/cache/atomic", "user.cache_atomic");
-    setxattr("com.example/cache/atomic/tomb", "user.cache_tombstone");
+    setxattr("com.example/cache/group", "user.cache_group");
+    setxattr("com.example/cache/group/tomb", "user.cache_tombstone");
     setxattr("com.example/cache/tomb", "user.cache_tombstone");
-    setxattr("com.example/cache/tomb/atomic", "user.cache_atomic");
+    setxattr("com.example/cache/tomb/group", "user.cache_group");
 
     service->freeCache(testUuid, free() + kKbInBytes,
             FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
 
-    EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/file1"));
-    EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/file2"));
-    EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/dir/file1"));
-    EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/dir/file2"));
-    EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/tomb/file1"));
-    EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/tomb/file2"));
-    EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/tomb/dir/file1"));
-    EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/tomb/dir/file2"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/file1"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/file2"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/dir/file1"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/dir/file2"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/tomb/file1"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/tomb/file2"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/tomb/dir/file1"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/group/tomb/dir/file2"));
 
     EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file1"));
     EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file2"));
     EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file1"));
     EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file2"));
-    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file1"));
-    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file2"));
-    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file1"));
-    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file2"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/file1"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/file2"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file1"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file2"));
 
     service->freeCache(testUuid, free() + kKbInBytes,
             FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
 
-    EXPECT_EQ(-1, size("com.example/cache/atomic/file1"));
-    EXPECT_EQ(-1, size("com.example/cache/atomic/file2"));
-    EXPECT_EQ(-1, size("com.example/cache/atomic/dir/file1"));
-    EXPECT_EQ(-1, size("com.example/cache/atomic/dir/file2"));
-    EXPECT_EQ(0, size("com.example/cache/atomic/tomb/file1"));
-    EXPECT_EQ(0, size("com.example/cache/atomic/tomb/file2"));
-    EXPECT_EQ(0, size("com.example/cache/atomic/tomb/dir/file1"));
-    EXPECT_EQ(0, size("com.example/cache/atomic/tomb/dir/file2"));
+    EXPECT_EQ(-1, size("com.example/cache/group/file1"));
+    EXPECT_EQ(-1, size("com.example/cache/group/file2"));
+    EXPECT_EQ(-1, size("com.example/cache/group/dir/file1"));
+    EXPECT_EQ(-1, size("com.example/cache/group/dir/file2"));
+    EXPECT_EQ(0, size("com.example/cache/group/tomb/file1"));
+    EXPECT_EQ(0, size("com.example/cache/group/tomb/file2"));
+    EXPECT_EQ(0, size("com.example/cache/group/tomb/dir/file1"));
+    EXPECT_EQ(0, size("com.example/cache/group/tomb/dir/file2"));
 
     EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file1"));
     EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file2"));
     EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file1"));
     EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file2"));
-    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file1"));
-    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file2"));
-    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file1"));
-    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file2"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/file1"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/file2"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file1"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file2"));
 
     service->freeCache(testUuid, kTbInBytes,
             FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
 
-    EXPECT_EQ(-1, size("com.example/cache/atomic/file1"));
-    EXPECT_EQ(-1, size("com.example/cache/atomic/file2"));
-    EXPECT_EQ(-1, size("com.example/cache/atomic/dir/file1"));
-    EXPECT_EQ(-1, size("com.example/cache/atomic/dir/file2"));
-    EXPECT_EQ(0, size("com.example/cache/atomic/tomb/file1"));
-    EXPECT_EQ(0, size("com.example/cache/atomic/tomb/file2"));
-    EXPECT_EQ(0, size("com.example/cache/atomic/tomb/dir/file1"));
-    EXPECT_EQ(0, size("com.example/cache/atomic/tomb/dir/file2"));
+    EXPECT_EQ(-1, size("com.example/cache/group/file1"));
+    EXPECT_EQ(-1, size("com.example/cache/group/file2"));
+    EXPECT_EQ(-1, size("com.example/cache/group/dir/file1"));
+    EXPECT_EQ(-1, size("com.example/cache/group/dir/file2"));
+    EXPECT_EQ(0, size("com.example/cache/group/tomb/file1"));
+    EXPECT_EQ(0, size("com.example/cache/group/tomb/file2"));
+    EXPECT_EQ(0, size("com.example/cache/group/tomb/dir/file1"));
+    EXPECT_EQ(0, size("com.example/cache/group/tomb/dir/file2"));
 
     EXPECT_EQ(0, size("com.example/cache/tomb/file1"));
     EXPECT_EQ(0, size("com.example/cache/tomb/file2"));
     EXPECT_EQ(0, size("com.example/cache/tomb/dir/file1"));
     EXPECT_EQ(0, size("com.example/cache/tomb/dir/file2"));
-    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file1"));
-    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file2"));
-    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file1"));
-    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file2"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/file1"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/file2"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file1"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/group/dir/file2"));
 }
 
 }  // namespace installd
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 97298e5..03ee23f 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -23,12 +23,7 @@
 #include <sys/stat.h>
 #include <sys/wait.h>
 #include <sys/xattr.h>
-
-#if defined(__APPLE__)
-#include <sys/mount.h>
-#else
-#include <sys/statfs.h>
-#endif
+#include <sys/statvfs.h>
 
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
@@ -637,11 +632,11 @@
 
 int64_t data_disk_free(const std::string& data_path)
 {
-    struct statfs sfs;
-    if (statfs(data_path.c_str(), &sfs) == 0) {
+    struct statvfs sfs;
+    if (statvfs(data_path.c_str(), &sfs) == 0) {
         return sfs.f_bavail * sfs.f_bsize;
     } else {
-        PLOG(ERROR) << "Couldn't statfs " << data_path;
+        PLOG(ERROR) << "Couldn't statvfs " << data_path;
         return -1;
     }
 }
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index abe6830..a4eb1f6 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -66,7 +66,7 @@
 
 constexpr const char* kXattrInodeCache = "user.inode_cache";
 constexpr const char* kXattrInodeCodeCache = "user.inode_code_cache";
-constexpr const char* kXattrCacheAtomic = "user.cache_atomic";
+constexpr const char* kXattrCacheGroup = "user.cache_group";
 constexpr const char* kXattrCacheTombstone = "user.cache_tombstone";
 
 int create_pkg_path(char path[PKG_PATH_MAX],
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index 8750147..a5cac15 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -257,8 +257,9 @@
                 continue;
             }
             // Strip out system libs.
-            // TODO(b/34772739): might want to add other framework HAL packages
-            if (fqName.inPackage("android.hidl")) {
+            if (fqName.inPackage("android.hidl") ||
+                fqName.inPackage("android.frameworks") ||
+                fqName.inPackage("android.system")) {
                 continue;
             }
             std::string interfaceName =
@@ -456,6 +457,9 @@
     using namespace ::android::hidl::base::V1_0;
     auto ret = timeoutIPC(manager, &IServiceManager::debugDump, [&] (const auto &infos) {
         for (const auto &info : infos) {
+            if (info.clientPids.size() <= 0) {
+                continue;
+            }
             putEntry(PTSERVICEMANAGER_REG_CLIENT, {
                 .interfaceName =
                         std::string{info.interfaceName.c_str()} + "/" +
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
index dc8e675..5431233 100644
--- a/cmds/servicemanager/Android.bp
+++ b/cmds/servicemanager/Android.bp
@@ -34,3 +34,15 @@
     shared_libs: ["libcutils", "libselinux"],
     init_rc: ["servicemanager.rc"],
 }
+
+cc_binary {
+    name: "vndservicemanager",
+    defaults: ["servicemanager_flags"],
+    proprietary: true,
+    srcs: [
+        "service_manager.c",
+        "binder.c",
+    ],
+    shared_libs: ["libcutils", "libselinux"],
+    init_rc: ["vndservicemanager.rc"],
+}
diff --git a/cmds/servicemanager/bctest.c b/cmds/servicemanager/bctest.c
index 6466654..354df67 100644
--- a/cmds/servicemanager/bctest.c
+++ b/cmds/servicemanager/bctest.c
@@ -62,7 +62,7 @@
     uint32_t svcmgr = BINDER_SERVICE_MANAGER;
     uint32_t handle;
 
-    bs = binder_open(128*1024);
+    bs = binder_open("/dev/binder", 128*1024);
     if (!bs) {
         fprintf(stderr, "failed to open binder driver\n");
         return -1;
diff --git a/cmds/servicemanager/binder.c b/cmds/servicemanager/binder.c
index 753aeb5..93a18fc 100644
--- a/cmds/servicemanager/binder.c
+++ b/cmds/servicemanager/binder.c
@@ -94,7 +94,7 @@
     size_t mapsize;
 };
 
-struct binder_state *binder_open(size_t mapsize)
+struct binder_state *binder_open(const char* driver, size_t mapsize)
 {
     struct binder_state *bs;
     struct binder_version vers;
@@ -105,10 +105,10 @@
         return NULL;
     }
 
-    bs->fd = open("/dev/binder", O_RDWR | O_CLOEXEC);
+    bs->fd = open(driver, O_RDWR | O_CLOEXEC);
     if (bs->fd < 0) {
-        fprintf(stderr,"binder: cannot open device (%s)\n",
-                strerror(errno));
+        fprintf(stderr,"binder: cannot open %s (%s)\n",
+                driver, strerror(errno));
         goto fail_open;
     }
 
diff --git a/cmds/servicemanager/binder.h b/cmds/servicemanager/binder.h
index 881ab07..c95b33f 100644
--- a/cmds/servicemanager/binder.h
+++ b/cmds/servicemanager/binder.h
@@ -46,7 +46,7 @@
                               struct binder_io *msg,
                               struct binder_io *reply);
 
-struct binder_state *binder_open(size_t mapsize);
+struct binder_state *binder_open(const char* driver, size_t mapsize);
 void binder_close(struct binder_state *bs);
 
 /* initiate a blocking binder call
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index 43c4c8b..5d44e87 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -360,14 +360,21 @@
     return 0;
 }
 
-int main()
+int main(int argc, char** argv)
 {
     struct binder_state *bs;
     union selinux_callback cb;
+    char *driver;
 
-    bs = binder_open(128*1024);
+    if (argc > 1) {
+        driver = argv[1];
+    } else {
+        driver = "/dev/binder";
+    }
+
+    bs = binder_open(driver, 128*1024);
     if (!bs) {
-        ALOGE("failed to open binder driver\n");
+        ALOGE("failed to open binder driver %s\n", driver);
         return -1;
     }
 
diff --git a/cmds/servicemanager/vndservicemanager.rc b/cmds/servicemanager/vndservicemanager.rc
new file mode 100644
index 0000000..d5ddaaf
--- /dev/null
+++ b/cmds/servicemanager/vndservicemanager.rc
@@ -0,0 +1,6 @@
+service vndservicemanager /vendor/bin/vndservicemanager /dev/vndbinder
+    class core
+    user system
+    group system readproc
+    writepid /dev/cpuset/system-background/tasks
+
diff --git a/data/etc/android.hardware.vr.headtracking-0.mxl b/data/etc/android.hardware.vr.headtracking-0.xml
similarity index 100%
rename from data/etc/android.hardware.vr.headtracking-0.mxl
rename to data/etc/android.hardware.vr.headtracking-0.xml
diff --git a/data/etc/android.hardware.vr.headtracking-1.mxl b/data/etc/android.hardware.vr.headtracking-1.xml
similarity index 100%
rename from data/etc/android.hardware.vr.headtracking-1.mxl
rename to data/etc/android.hardware.vr.headtracking-1.xml
diff --git a/data/etc/android.software.companion_device_setup.xml b/data/etc/android.software.companion_device_setup.xml
new file mode 100644
index 0000000..e60ef88
--- /dev/null
+++ b/data/etc/android.software.companion_device_setup.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+
+<permissions>
+    <feature name="android.software.companion_device_setup" />
+</permissions>
diff --git a/data/etc/car_core_hardware.xml b/data/etc/car_core_hardware.xml
index ab89ef5..835504f 100644
--- a/data/etc/car_core_hardware.xml
+++ b/data/etc/car_core_hardware.xml
@@ -23,6 +23,9 @@
      devices.
 -->
 <permissions>
+    <!-- This is Android and fully CTS compatible.  Basically this is for CTS tests to use. -->
+    <feature name="android.software.cts" />
+
     <feature name="android.hardware.audio.output" />
     <feature name="android.hardware.location" />
     <feature name="android.hardware.location.network" />
diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
index ed3db5c..b5287ac 100644
--- a/data/etc/handheld_core_hardware.xml
+++ b/data/etc/handheld_core_hardware.xml
@@ -23,6 +23,9 @@
      devices.
 -->
 <permissions>
+    <!-- This is Android and fully CTS compatible.  Basically this is for CTS tests to use. -->
+    <feature name="android.software.cts" />
+
     <feature name="android.hardware.audio.output" />
     <feature name="android.hardware.camera" />
     <feature name="android.hardware.location" />
@@ -44,6 +47,7 @@
     <feature name="android.software.input_methods" />
     <feature name="android.software.picture_in_picture" />
     <feature name="android.software.print" />
+    <feature name="android.software.companion_device_setup" />
 
     <!-- Feature to specify if the device supports adding device admins. -->
     <feature name="android.software.device_admin" />
diff --git a/data/etc/tablet_core_hardware.xml b/data/etc/tablet_core_hardware.xml
index 7f545e6..51ea1ca 100644
--- a/data/etc/tablet_core_hardware.xml
+++ b/data/etc/tablet_core_hardware.xml
@@ -23,6 +23,9 @@
      devices.
 -->
 <permissions>
+    <!-- This is Android and fully CTS compatible.  Basically this is for CTS tests to use. -->
+    <feature name="android.software.cts" />
+
     <feature name="android.hardware.audio.output" />
     <feature name="android.hardware.location" />
     <feature name="android.hardware.location.network" />
@@ -44,6 +47,7 @@
     <feature name="android.software.input_methods" />
     <feature name="android.software.picture_in_picture" />
     <feature name="android.software.print" />
+    <feature name="android.software.companion_device_setup" />
 
     <!-- Feature to specify if the device supports adding device admins. -->
     <feature name="android.software.device_admin" />
diff --git a/data/etc/wearable_core_hardware.xml b/data/etc/wearable_core_hardware.xml
index 84230da..a7955e9 100644
--- a/data/etc/wearable_core_hardware.xml
+++ b/data/etc/wearable_core_hardware.xml
@@ -21,6 +21,9 @@
      Wearable devices include watches, glasses, backpacks, and sweaters.
 -->
 <permissions>
+    <!-- This is Android and fully CTS compatible.  Basically this is for CTS tests to use. -->
+    <feature name="android.software.cts" />
+
     <feature name="android.hardware.location" />
     <!-- devices supporting compass/magnitometer sensor must include
 	 android.hardware.sensor.compass.xml -->
diff --git a/include/batteryservice/IBatteryPropertiesRegistrar.h b/include/batteryservice/IBatteryPropertiesRegistrar.h
index b5c3a4d..a7dbea6 100644
--- a/include/batteryservice/IBatteryPropertiesRegistrar.h
+++ b/include/batteryservice/IBatteryPropertiesRegistrar.h
@@ -27,6 +27,7 @@
     REGISTER_LISTENER = IBinder::FIRST_CALL_TRANSACTION,
     UNREGISTER_LISTENER,
     GET_PROPERTY,
+    SCHEDULE_UPDATE,
 };
 
 class IBatteryPropertiesRegistrar : public IInterface {
@@ -36,6 +37,7 @@
     virtual void registerListener(const sp<IBatteryPropertiesListener>& listener) = 0;
     virtual void unregisterListener(const sp<IBatteryPropertiesListener>& listener) = 0;
     virtual status_t getProperty(int id, struct BatteryProperty *val) = 0;
+    virtual void scheduleUpdate() = 0;
 };
 
 class BnBatteryPropertiesRegistrar : public BnInterface<IBatteryPropertiesRegistrar> {
diff --git a/include/binder/IPCThreadState.h b/include/binder/IPCThreadState.h
index 1853cff..7b826d6 100644
--- a/include/binder/IPCThreadState.h
+++ b/include/binder/IPCThreadState.h
@@ -115,7 +115,6 @@
                                            void* cookie);
     
     const   sp<ProcessState>    mProcess;
-    const   pid_t               mMyThreadId;
             Vector<BBinder*>    mPendingStrongDerefs;
             Vector<RefBase::weakref_type*> mPendingWeakDerefs;
 
diff --git a/include/binder/ProcessState.h b/include/binder/ProcessState.h
index 64cf72e..05e9d09 100644
--- a/include/binder/ProcessState.h
+++ b/include/binder/ProcessState.h
@@ -35,6 +35,11 @@
 {
 public:
     static  sp<ProcessState>    self();
+    /* initWithDriver() can be used to configure libbinder to use
+     * a different binder driver dev node. It must be called *before*
+     * any call to ProcessState::self(). /dev/binder remains the default.
+     */
+    static  sp<ProcessState>    initWithDriver(const char *driver);
 
             void                setContextObject(const sp<IBinder>& object);
             sp<IBinder>         getContextObject(const sp<IBinder>& caller);
@@ -67,7 +72,7 @@
 private:
     friend class IPCThreadState;
     
-                                ProcessState();
+                                ProcessState(const char* driver);
                                 ~ProcessState();
 
                                 ProcessState(const ProcessState& o);
diff --git a/include/gui/BufferItemConsumer.h b/include/gui/BufferItemConsumer.h
index ec77ec7..db7e944 100644
--- a/include/gui/BufferItemConsumer.h
+++ b/include/gui/BufferItemConsumer.h
@@ -37,6 +37,10 @@
   public:
     typedef ConsumerBase::FrameAvailableListener FrameAvailableListener;
 
+    struct BufferFreedListener : public virtual RefBase {
+        virtual void onBufferFreed(const wp<GraphicBuffer>& graphicBuffer) = 0;
+    };
+
     enum { DEFAULT_MAX_BUFFERS = -1 };
     enum { INVALID_BUFFER_SLOT = BufferQueue::INVALID_BUFFER_SLOT };
     enum { NO_BUFFER_AVAILABLE = BufferQueue::NO_BUFFER_AVAILABLE };
@@ -57,6 +61,10 @@
     // log messages.
     void setName(const String8& name);
 
+    // setBufferFreedListener sets the listener object that will be notified
+    // when an old buffer is being freed.
+    void setBufferFreedListener(const wp<BufferFreedListener>& listener);
+
     // Gets the next graphics buffer from the producer, filling out the
     // passed-in BufferItem structure. Returns NO_BUFFER_AVAILABLE if the queue
     // of buffers is empty, and INVALID_OPERATION if the maximum number of
@@ -81,6 +89,13 @@
     status_t releaseBuffer(const BufferItem &item,
             const sp<Fence>& releaseFence = Fence::NO_FENCE);
 
+   private:
+    void freeBufferLocked(int slotIndex) override;
+
+    // mBufferFreedListener is the listener object that will be called when
+    // an old buffer is being freed. If it is not NULL it will be called from
+    // freeBufferLocked.
+    wp<BufferFreedListener> mBufferFreedListener;
 };
 
 } // namespace android
diff --git a/include/gui/FrameTimestamps.h b/include/gui/FrameTimestamps.h
index cbb4491..92251ed 100644
--- a/include/gui/FrameTimestamps.h
+++ b/include/gui/FrameTimestamps.h
@@ -43,7 +43,6 @@
     LAST_REFRESH_START,
     GPU_COMPOSITION_DONE,
     DISPLAY_PRESENT,
-    DISPLAY_RETIRE,
     DEQUEUE_READY,
     RELEASE,
     EVENT_COUNT, // Not an actual event.
@@ -70,7 +69,6 @@
     bool hasAcquireInfo() const;
     bool hasGpuCompositionDoneInfo() const;
     bool hasDisplayPresentInfo() const;
-    bool hasDisplayRetireInfo() const;
     bool hasReleaseInfo() const;
     bool hasDequeueReadyInfo() const;
 
@@ -85,7 +83,6 @@
     // encountered help us determine if timestamps aren't available because
     // a) we'll just never get them or b) they're not ready yet.
     bool addPostCompositeCalled{false};
-    bool addRetireCalled{false};
     bool addReleaseCalled{false};
 
     nsecs_t postedTime{TIMESTAMP_PENDING};
@@ -98,7 +95,6 @@
     std::shared_ptr<FenceTime> acquireFence{FenceTime::NO_FENCE};
     std::shared_ptr<FenceTime> gpuCompositionDoneFence{FenceTime::NO_FENCE};
     std::shared_ptr<FenceTime> displayPresentFence{FenceTime::NO_FENCE};
-    std::shared_ptr<FenceTime> displayRetireFence{FenceTime::NO_FENCE};
     std::shared_ptr<FenceTime> releaseFence{FenceTime::NO_FENCE};
 };
 
@@ -167,7 +163,6 @@
     FenceTimeline mAcquireTimeline;
     FenceTimeline mGpuCompositionDoneTimeline;
     FenceTimeline mPresentTimeline;
-    FenceTimeline mRetireTimeline;
     FenceTimeline mReleaseTimeline;
 };
 
@@ -224,8 +219,6 @@
             const std::shared_ptr<FenceTime>& gpuCompositionDone,
             const std::shared_ptr<FenceTime>& displayPresent,
             const CompositorTiming& compositorTiming);
-    void addRetire(uint64_t frameNumber,
-            const std::shared_ptr<FenceTime>& displayRetire);
     void addRelease(uint64_t frameNumber, nsecs_t dequeueReadyTime,
             std::shared_ptr<FenceTime>&& release);
 
@@ -239,7 +232,6 @@
 
     size_t mQueueOffset{0};
     size_t mCompositionOffset{0};
-    size_t mRetireOffset{0};
     size_t mReleaseOffset{0};
 
     int mCurrentConnectId{0};
@@ -281,7 +273,6 @@
     uint64_t mFrameNumber{0};
 
     bool mAddPostCompositeCalled{0};
-    bool mAddRetireCalled{0};
     bool mAddReleaseCalled{0};
 
     nsecs_t mPostedTime{FrameEvents::TIMESTAMP_PENDING};
@@ -293,17 +284,16 @@
 
     FenceTime::Snapshot mGpuCompositionDoneFence;
     FenceTime::Snapshot mDisplayPresentFence;
-    FenceTime::Snapshot mDisplayRetireFence;
     FenceTime::Snapshot mReleaseFence;
 
     // This is a static method with an auto return value so we can call
     // it without needing const and non-const versions.
     template <typename ThisT>
     static inline auto allFences(ThisT fed) ->
-            std::array<decltype(&fed->mReleaseFence), 4> {
+            std::array<decltype(&fed->mReleaseFence), 3> {
         return {{
             &fed->mGpuCompositionDoneFence, &fed->mDisplayPresentFence,
-            &fed->mDisplayRetireFence, &fed->mReleaseFence
+            &fed->mReleaseFence
         }};
     }
 };
diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
index 9870ba0..2fbe07a 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -126,11 +126,6 @@
     virtual bool authenticateSurfaceTexture(
             const sp<IGraphicBufferProducer>& surface) const = 0;
 
-    /* Returns the frame timestamps supported by SurfaceFlinger.
-     */
-    virtual status_t getSupportedFrameTimestamps(
-            std::vector<FrameEvent>* outSupported) const = 0;
-
     /* set display power mode. depending on the mode, it can either trigger
      * screen on, off or low power mode and wait for it to complete.
      * requires ACCESS_SURFACE_FLINGER permission.
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index cfc68c6..62f6cad 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -152,8 +152,8 @@
             nsecs_t* outRequestedPresentTime, nsecs_t* outAcquireTime,
             nsecs_t* outLatchTime, nsecs_t* outFirstRefreshStartTime,
             nsecs_t* outLastRefreshStartTime, nsecs_t* outGlCompositionDoneTime,
-            nsecs_t* outDisplayPresentTime, nsecs_t* outDisplayRetireTime,
-            nsecs_t* outDequeueReadyTime, nsecs_t* outReleaseTime);
+            nsecs_t* outDisplayPresentTime, nsecs_t* outDequeueReadyTime,
+            nsecs_t* outReleaseTime);
 
     status_t getWideColorSupport(bool* supported);
     status_t getHdrSupport(bool* supported);
@@ -411,11 +411,6 @@
     uint64_t mNextFrameNumber = 1;
     uint64_t mLastFrameNumber = 0;
 
-    // Mutable because ANativeWindow::query needs this class const.
-    mutable bool mQueriedSupportedTimestamps;
-    mutable bool mFrameTimestampsSupportsPresent;
-    mutable bool mFrameTimestampsSupportsRetire;
-
     // A cached copy of the FrameEventHistory maintained by the consumer.
     bool mEnableFrameTimestamps = false;
     std::unique_ptr<ProducerFrameEventHistory> mFrameEventHistory;
diff --git a/include/vr/vr_manager/vr_manager.h b/include/vr/vr_manager/vr_manager.h
index 0c5da19..9df2c6b 100644
--- a/include/vr/vr_manager/vr_manager.h
+++ b/include/vr/vr_manager/vr_manager.h
@@ -41,6 +41,28 @@
 };
 
 
+// Must be kept in sync with interface defined in
+// IPersistentVrStateCallbacks.aidl.
+
+class IPersistentVrStateCallbacks : public IInterface {
+public:
+    DECLARE_META_INTERFACE(PersistentVrStateCallbacks)
+
+    virtual void onPersistentVrStateChanged(bool enabled) = 0;
+};
+
+enum PersistentVrStateCallbacksTransaction {
+    ON_PERSISTENT_VR_STATE_CHANGED = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+class BnPersistentVrStateCallbacks
+        : public BnInterface<IPersistentVrStateCallbacks> {
+public:
+    status_t onTransact(uint32_t code, const Parcel& data,
+                        Parcel* reply, uint32_t flags = 0) override;
+};
+
+
 // Must be kept in sync with interface defined in IVrManager.aidl.
 
 class IVrManager : public IInterface {
@@ -49,12 +71,18 @@
 
     virtual void registerListener(const sp<IVrStateCallbacks>& cb) = 0;
     virtual void unregisterListener(const sp<IVrStateCallbacks>& cb) = 0;
+    virtual void registerPersistentVrStateListener(
+        const sp<IPersistentVrStateCallbacks>& cb) = 0;
+    virtual void unregisterPersistentVrStateListener(
+        const sp<IPersistentVrStateCallbacks>& cb) = 0;
     virtual bool getVrModeState() = 0;
 };
 
 enum VrManagerTransaction {
     REGISTER_LISTENER = IBinder::FIRST_CALL_TRANSACTION,
     UNREGISTER_LISTENER,
+    REGISTER_PERSISTENT_VR_STATE_LISTENER,
+    UNREGISTER_PERSISTENT_VR_STATE_LISTENER,
     GET_VR_MODE_STATE,
 };
 
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 02b4232..d0cd8f2 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -46,6 +46,7 @@
 #define IF_LOG_COMMANDS() if (false)
 #define LOG_REMOTEREFS(...) 
 #define IF_LOG_REMOTEREFS() if (false)
+
 #define LOG_THREADPOOL(...) 
 #define LOG_ONEWAY(...) 
 
@@ -149,7 +150,7 @@
         return cmd;
     }
     out << kReturnStrings[cmdIndex];
-    
+
     switch (code) {
         case BR_TRANSACTION:
         case BR_REPLY: {
@@ -157,12 +158,12 @@
             cmd = (const int32_t *)printBinderTransactionData(out, cmd);
             out << dedent;
         } break;
-        
+
         case BR_ACQUIRE_RESULT: {
             const int32_t res = *cmd++;
             out << ": " << res << (res ? " (SUCCESS)" : " (FAILURE)");
         } break;
-        
+
         case BR_INCREFS:
         case BR_ACQUIRE:
         case BR_RELEASE:
@@ -171,7 +172,7 @@
             const int32_t c = *cmd++;
             out << ": target=" << (void*)(long)b << " (cookie " << (void*)(long)c << ")";
         } break;
-    
+
         case BR_ATTEMPT_ACQUIRE: {
             const int32_t p = *cmd++;
             const int32_t b = *cmd++;
@@ -191,7 +192,7 @@
             // BR_TRANSACTION_COMPLETE, BR_FINISHED
             break;
     }
-    
+
     out << endl;
     return cmd;
 }
@@ -216,17 +217,17 @@
             cmd = (const int32_t *)printBinderTransactionData(out, cmd);
             out << dedent;
         } break;
-        
+
         case BC_ACQUIRE_RESULT: {
             const int32_t res = *cmd++;
             out << ": " << res << (res ? " (SUCCESS)" : " (FAILURE)");
         } break;
-        
+
         case BC_FREE_BUFFER: {
             const int32_t buf = *cmd++;
             out << ": buffer=" << (void*)(long)buf;
         } break;
-        
+
         case BC_INCREFS:
         case BC_ACQUIRE:
         case BC_RELEASE:
@@ -234,20 +235,20 @@
             const int32_t d = *cmd++;
             out << ": desc=" << d;
         } break;
-    
+
         case BC_INCREFS_DONE:
         case BC_ACQUIRE_DONE: {
             const int32_t b = *cmd++;
             const int32_t c = *cmd++;
             out << ": target=" << (void*)(long)b << " (cookie " << (void*)(long)c << ")";
         } break;
-        
+
         case BC_ATTEMPT_ACQUIRE: {
             const int32_t p = *cmd++;
             const int32_t d = *cmd++;
             out << ": desc=" << d << ", pri=" << p;
         } break;
-        
+
         case BC_REQUEST_DEATH_NOTIFICATION:
         case BC_CLEAR_DEATH_NOTIFICATION: {
             const int32_t h = *cmd++;
@@ -265,7 +266,7 @@
             // BC_EXIT_LOOPER
             break;
     }
-    
+
     out << endl;
     return cmd;
 }
@@ -285,12 +286,12 @@
         if (st) return st;
         return new IPCThreadState;
     }
-    
+
     if (gShutdown) {
         ALOGW("Calling IPCThreadState::self() during shutdown is dangerous, expect a crash.\n");
         return NULL;
     }
-    
+
     pthread_mutex_lock(&gTLSMutex);
     if (!gHaveTLS) {
         int key_create_value = pthread_key_create(&gTLS, threadDestructor);
@@ -319,7 +320,7 @@
 void IPCThreadState::shutdown()
 {
     gShutdown = true;
-    
+
     if (gHaveTLS) {
         // XXX Need to wait for all thread pool threads to exit!
         IPCThreadState* st = (IPCThreadState*)pthread_getspecific(gTLS);
@@ -455,15 +456,6 @@
         }
         pthread_cond_broadcast(&mProcess->mThreadCountDecrement);
         pthread_mutex_unlock(&mProcess->mThreadCountLock);
-
-        // After executing the command, ensure that the thread is returned to the
-        // foreground cgroup before rejoining the pool.  The driver takes care of
-        // restoring the priority, but doesn't do anything with cgroups so we
-        // need to take care of that here in userspace.  Note that we do make
-        // sure to go in the foreground after executing a transaction, but
-        // there are other callbacks into user code that could have changed
-        // our group so we want to make absolutely sure it is put back.
-        set_sched_policy(mMyThreadId, SP_FOREGROUND);
     }
 
     return result;
@@ -498,12 +490,7 @@
     LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
 
     mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
-    
-    // This thread may have been spawned by a thread that was in the background
-    // scheduling group, so first we will make sure it is in the foreground
-    // one to avoid performing an initial transaction in the background.
-    set_sched_policy(mMyThreadId, SP_FOREGROUND);
-        
+
     status_t result;
     do {
         processPendingDerefs();
@@ -515,7 +502,7 @@
                   mProcess->mDriverFD, result);
             abort();
         }
-        
+
         // Let this thread exit the thread pool if it is no longer
         // needed and it is not the main process thread.
         if(result == TIMED_OUT && !isMain) {
@@ -525,7 +512,7 @@
 
     LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%d\n",
         (void*)pthread_self(), getpid(), result);
-    
+
     mOut.writeInt32(BC_EXIT_LOOPER);
     talkWithDriver(false);
 }
@@ -578,18 +565,18 @@
             << handle << " / code " << TypeCode(code) << ": "
             << indent << data << dedent << endl;
     }
-    
+
     if (err == NO_ERROR) {
         LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
             (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
         err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
     }
-    
+
     if (err != NO_ERROR) {
         if (reply) reply->setError(err);
         return (mLastError = err);
     }
-    
+
     if ((flags & TF_ONE_WAY) == 0) {
         #if 0
         if (code == 4) { // relayout
@@ -611,7 +598,7 @@
             ALOGI("<<<<<< RETURNING transaction %d", code);
         }
         #endif
-        
+
         IF_LOG_TRANSACTIONS() {
             TextOutput::Bundle _b(alog);
             alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "
@@ -622,7 +609,7 @@
     } else {
         err = waitForResponse(NULL, NULL);
     }
-    
+
     return err;
 }
 
@@ -662,14 +649,14 @@
     mOut.writeInt32(0); // xxx was thread priority
     mOut.writeInt32(handle);
     status_t result = UNKNOWN_ERROR;
-    
+
     waitForResponse(NULL, &result);
-    
+
 #if LOG_REFCOUNTS
     ALOGV("IPCThreadState::attemptIncStrongHandle(%ld) = %s\n",
         handle, result == NO_ERROR ? "SUCCESS" : "FAILURE");
 #endif
-    
+
     return result;
 #else
     (void)handle;
@@ -704,7 +691,6 @@
 
 IPCThreadState::IPCThreadState()
     : mProcess(ProcessState::self()),
-      mMyThreadId(gettid()),
       mStrictModePolicy(0),
       mLastTransactionBinderFlags(0)
 {
@@ -724,7 +710,7 @@
     status_t statusBuffer;
     err = writeTransactionData(BC_REPLY, flags, -1, 0, reply, &statusBuffer);
     if (err < NO_ERROR) return err;
-    
+
     return waitForResponse(NULL, NULL);
 }
 
@@ -738,9 +724,9 @@
         err = mIn.errorCheck();
         if (err < NO_ERROR) break;
         if (mIn.dataAvail() == 0) continue;
-        
+
         cmd = (uint32_t)mIn.readInt32();
-        
+
         IF_LOG_COMMANDS() {
             alog << "Processing waitForResponse Command: "
                 << getReturnString(cmd) << endl;
@@ -750,7 +736,7 @@
         case BR_TRANSACTION_COMPLETE:
             if (!reply && !acquireResult) goto finish;
             break;
-        
+
         case BR_DEAD_REPLY:
             err = DEAD_OBJECT;
             goto finish;
@@ -758,7 +744,7 @@
         case BR_FAILED_REPLY:
             err = FAILED_TRANSACTION;
             goto finish;
-        
+
         case BR_ACQUIRE_RESULT:
             {
                 ALOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");
@@ -767,7 +753,7 @@
                 *acquireResult = result ? NO_ERROR : INVALID_OPERATION;
             }
             goto finish;
-        
+
         case BR_REPLY:
             {
                 binder_transaction_data tr;
@@ -815,7 +801,7 @@
         if (reply) reply->setError(err);
         mLastError = err;
     }
-    
+
     return err;
 }
 
@@ -824,17 +810,17 @@
     if (mProcess->mDriverFD <= 0) {
         return -EBADF;
     }
-    
+
     binder_write_read bwr;
-    
+
     // Is the read buffer empty?
     const bool needRead = mIn.dataPosition() >= mIn.dataSize();
-    
+
     // We don't want to write anything if we are still reading
     // from data left in the input buffer and the caller
     // has requested to read the next data.
     const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
-    
+
     bwr.write_size = outAvail;
     bwr.write_buffer = (uintptr_t)mOut.data();
 
@@ -860,7 +846,7 @@
         alog << "Size of receive buffer: " << bwr.read_size
             << ", needRead: " << needRead << ", doReceive: " << doReceive << endl;
     }
-    
+
     // Return immediately if there is nothing to do.
     if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
 
@@ -916,7 +902,7 @@
         }
         return NO_ERROR;
     }
-    
+
     return err;
 }
 
@@ -932,7 +918,7 @@
     tr.cookie = 0;
     tr.sender_pid = 0;
     tr.sender_euid = 0;
-    
+
     const status_t err = data.errorCheck();
     if (err == NO_ERROR) {
         tr.data_size = data.ipcDataSize();
@@ -949,10 +935,10 @@
     } else {
         return (mLastError = err);
     }
-    
+
     mOut.writeInt32(cmd);
     mOut.write(&tr, sizeof(tr));
-    
+
     return NO_ERROR;
 }
 
@@ -968,15 +954,15 @@
     BBinder* obj;
     RefBase::weakref_type* refs;
     status_t result = NO_ERROR;
-    
+
     switch ((uint32_t)cmd) {
     case BR_ERROR:
         result = mIn.readInt32();
         break;
-        
+
     case BR_OK:
         break;
-        
+
     case BR_ACQUIRE:
         refs = (RefBase::weakref_type*)mIn.readPointer();
         obj = (BBinder*)mIn.readPointer();
@@ -992,7 +978,7 @@
         mOut.writePointer((uintptr_t)refs);
         mOut.writePointer((uintptr_t)obj);
         break;
-        
+
     case BR_RELEASE:
         refs = (RefBase::weakref_type*)mIn.readPointer();
         obj = (BBinder*)mIn.readPointer();
@@ -1005,7 +991,7 @@
         }
         mPendingStrongDerefs.push(obj);
         break;
-        
+
     case BR_INCREFS:
         refs = (RefBase::weakref_type*)mIn.readPointer();
         obj = (BBinder*)mIn.readPointer();
@@ -1014,7 +1000,7 @@
         mOut.writePointer((uintptr_t)refs);
         mOut.writePointer((uintptr_t)obj);
         break;
-        
+
     case BR_DECREFS:
         refs = (RefBase::weakref_type*)mIn.readPointer();
         obj = (BBinder*)mIn.readPointer();
@@ -1026,22 +1012,22 @@
         //           refs, obj, refs->refBase());
         mPendingWeakDerefs.push(refs);
         break;
-        
+
     case BR_ATTEMPT_ACQUIRE:
         refs = (RefBase::weakref_type*)mIn.readPointer();
         obj = (BBinder*)mIn.readPointer();
-         
+
         {
             const bool success = refs->attemptIncStrong(mProcess.get());
             ALOG_ASSERT(success && refs->refBase() == obj,
                        "BR_ATTEMPT_ACQUIRE: object %p does not match cookie %p (expected %p)",
                        refs, obj, refs->refBase());
-            
+
             mOut.writeInt32(BC_ACQUIRE_RESULT);
             mOut.writeInt32((int32_t)success);
         }
         break;
-    
+
     case BR_TRANSACTION:
         {
             binder_transaction_data tr;
@@ -1049,14 +1035,14 @@
             ALOG_ASSERT(result == NO_ERROR,
                 "Not enough command data for brTRANSACTION");
             if (result != NO_ERROR) break;
-            
+
             Parcel buffer;
             buffer.ipcSetDataReference(
                 reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                 tr.data_size,
                 reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
                 tr.offsets_size/sizeof(binder_size_t), freeBuffer, this);
-            
+
             const pid_t origPid = mCallingPid;
             const uid_t origUid = mCallingUid;
             const int32_t origStrictModePolicy = mStrictModePolicy;
@@ -1066,26 +1052,6 @@
             mCallingUid = tr.sender_euid;
             mLastTransactionBinderFlags = tr.flags;
 
-            int curPrio = getpriority(PRIO_PROCESS, mMyThreadId);
-            if (gDisableBackgroundScheduling) {
-                if (curPrio > ANDROID_PRIORITY_NORMAL) {
-                    // We have inherited a reduced priority from the caller, but do not
-                    // want to run in that state in this process.  The driver set our
-                    // priority already (though not our scheduling class), so bounce
-                    // it back to the default before invoking the transaction.
-                    setpriority(PRIO_PROCESS, mMyThreadId, ANDROID_PRIORITY_NORMAL);
-                }
-            } else {
-                if (curPrio >= ANDROID_PRIORITY_BACKGROUND) {
-                    // We want to use the inherited priority from the caller.
-                    // Ensure this thread is in the background scheduling class,
-                    // since the driver won't modify scheduling classes for us.
-                    // The scheduling group is reset to default by the caller
-                    // once this method returns after the transaction is complete.
-                    set_sched_policy(mMyThreadId, SP_BACKGROUND);
-                }
-            }
-
             //ALOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid);
 
             Parcel reply;
@@ -1119,7 +1085,7 @@
 
             //ALOGI("<<<< TRANSACT from pid %d restore pid %d uid %d\n",
             //     mCallingPid, origPid, origUid);
-            
+
             if ((tr.flags & TF_ONE_WAY) == 0) {
                 LOG_ONEWAY("Sending reply to %d!", mCallingPid);
                 if (error < NO_ERROR) reply.setError(error);
@@ -1127,7 +1093,7 @@
             } else {
                 LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
             }
-            
+
             mCallingPid = origPid;
             mCallingUid = origUid;
             mStrictModePolicy = origStrictModePolicy;
@@ -1138,10 +1104,10 @@
                 alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "
                     << tr.target.ptr << ": " << indent << reply << dedent << endl;
             }
-            
+
         }
         break;
-    
+
     case BR_DEAD_BINDER:
         {
             BpBinder *proxy = (BpBinder*)mIn.readPointer();
@@ -1149,24 +1115,24 @@
             mOut.writeInt32(BC_DEAD_BINDER_DONE);
             mOut.writePointer((uintptr_t)proxy);
         } break;
-        
+
     case BR_CLEAR_DEATH_NOTIFICATION_DONE:
         {
             BpBinder *proxy = (BpBinder*)mIn.readPointer();
             proxy->getWeakRefs()->decWeak(proxy);
         } break;
-        
+
     case BR_FINISHED:
         result = TIMED_OUT;
         break;
-        
+
     case BR_NOOP:
         break;
-        
+
     case BR_SPAWN_LOOPER:
         mProcess->spawnPooledThread(false);
         break;
-        
+
     default:
         ALOGE("*** BAD COMMAND %d received from Binder driver\n", cmd);
         result = UNKNOWN_ERROR;
@@ -1176,7 +1142,7 @@
     if (result != NO_ERROR) {
         mLastError = result;
     }
-    
+
     return result;
 }
 
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 98107c5..5c4cfe2 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -71,7 +71,17 @@
     if (gProcess != NULL) {
         return gProcess;
     }
-    gProcess = new ProcessState;
+    gProcess = new ProcessState("/dev/binder");
+    return gProcess;
+}
+
+sp<ProcessState> ProcessState::initWithDriver(const char* driver)
+{
+    Mutex::Autolock _l(gProcessMutex);
+    if (gProcess != NULL) {
+        LOG_ALWAYS_FATAL("ProcessState was already initialized.");
+    }
+    gProcess = new ProcessState(driver);
     return gProcess;
 }
 
@@ -307,9 +317,9 @@
     androidSetThreadName( makeBinderThreadName().string() );
 }
 
-static int open_driver()
+static int open_driver(const char *driver)
 {
-    int fd = open("/dev/binder", O_RDWR | O_CLOEXEC);
+    int fd = open(driver, O_RDWR | O_CLOEXEC);
     if (fd >= 0) {
         int vers = 0;
         status_t result = ioctl(fd, BINDER_VERSION, &vers);
@@ -330,13 +340,13 @@
             ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
         }
     } else {
-        ALOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
+        ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno));
     }
     return fd;
 }
 
-ProcessState::ProcessState()
-    : mDriverFD(open_driver())
+ProcessState::ProcessState(const char *driver)
+    : mDriverFD(open_driver(driver))
     , mVMStart(MAP_FAILED)
     , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
     , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 5f5fb91..5fc6abe 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -112,9 +112,11 @@
         "libnativewindow",
         "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",
     ],
 
     export_shared_lib_headers: [
@@ -123,6 +125,8 @@
         "android.hidl.token@1.0-utils",
         "android.hardware.graphics.bufferqueue@1.0",
     ],
+
+    header_libs: ["android.hardware.configstore-utils"],
 }
 
 subdirs = ["tests"]
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index 3491043..d9d50db 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -22,7 +22,7 @@
 #include <gui/BufferItem.h>
 #include <gui/BufferItemConsumer.h>
 
-//#define BI_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__)
+#define BI_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__)
 //#define BI_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__)
 //#define BI_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__)
 //#define BI_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__)
@@ -57,6 +57,12 @@
     mConsumer->setConsumerName(name);
 }
 
+void BufferItemConsumer::setBufferFreedListener(
+        const wp<BufferFreedListener>& listener) {
+    Mutex::Autolock _l(mMutex);
+    mBufferFreedListener = listener;
+}
+
 status_t BufferItemConsumer::acquireBuffer(BufferItem *item,
         nsecs_t presentWhen, bool waitForFence) {
     status_t err;
@@ -104,4 +110,14 @@
     return err;
 }
 
+void BufferItemConsumer::freeBufferLocked(int slotIndex) {
+    sp<BufferFreedListener> listener = mBufferFreedListener.promote();
+    if (listener != NULL && mSlots[slotIndex].mGraphicBuffer != NULL) {
+        // Fire callback if we have a listener registered and the buffer being freed is valid.
+        BI_LOGV("actually calling onBufferFreed");
+        listener->onBufferFreed(mSlots[slotIndex].mGraphicBuffer);
+    }
+    ConsumerBase::freeBufferLocked(slotIndex);
+}
+
 } // namespace android
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 9e3fecb..d653db8 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -261,6 +261,13 @@
 
     for (auto& b : mQueue) {
         b.mIsStale = true;
+
+        // We set this to false to force the BufferQueue to resend the buffer
+        // handle upon acquire, since if we're here due to a producer
+        // disconnect, the consumer will have been told to purge its cache of
+        // slot-to-buffer-handle mappings and will not be able to otherwise
+        // obtain a valid buffer handle.
+        b.mAcquireCalled = false;
     }
 
     VALIDATE_CONSISTENCY();
diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp
index 019a11e..fccca97 100644
--- a/libs/gui/FrameTimestamps.cpp
+++ b/libs/gui/FrameTimestamps.cpp
@@ -52,9 +52,8 @@
 
 bool FrameEvents::hasLastRefreshStartInfo() const {
     // The last refresh start time may continue to update until a new frame
-    // is latched. We know we have the final value once the release or retire
-    // info is set. See ConsumerFrameEventHistory::addRetire/Release.
-    return addRetireCalled || addReleaseCalled;
+    // is latched. We know we have the final value once the release info is set.
+    return addReleaseCalled;
 }
 
 bool FrameEvents::hasDequeueReadyInfo() const {
@@ -76,11 +75,6 @@
     return addPostCompositeCalled;
 }
 
-bool FrameEvents::hasDisplayRetireInfo() const {
-    // We may not get a displayRetire in addRetire for HWC2.
-    return addRetireCalled;
-}
-
 bool FrameEvents::hasReleaseInfo() const {
     return addReleaseCalled;
 }
@@ -89,7 +83,6 @@
     acquireFence->getSignalTime();
     gpuCompositionDoneFence->getSignalTime();
     displayPresentFence->getSignalTime();
-    displayRetireFence->getSignalTime();
     releaseFence->getSignalTime();
 }
 
@@ -145,8 +138,6 @@
             !addPostCompositeCalled, *gpuCompositionDoneFence);
     dumpFenceTime(outString, "Display Present   \t",
             !addPostCompositeCalled, *displayPresentFence);
-    dumpFenceTime(outString, "Display Retire    \t",
-            !addRetireCalled, *displayRetireFence);
 
     outString.appendFormat("--- DequeueReady  \t");
     if (FrameEvents::isValidTimestamp(dequeueReadyTime)) {
@@ -286,7 +277,6 @@
         FrameEvents& frame = mFrames[d.mIndex];
 
         frame.addPostCompositeCalled = d.mAddPostCompositeCalled != 0;
-        frame.addRetireCalled = d.mAddRetireCalled != 0;
         frame.addReleaseCalled = d.mAddReleaseCalled != 0;
 
         frame.postedTime = d.mPostedTime;
@@ -302,7 +292,6 @@
             frame.acquireFence = FenceTime::NO_FENCE;
             frame.gpuCompositionDoneFence = FenceTime::NO_FENCE;
             frame.displayPresentFence = FenceTime::NO_FENCE;
-            frame.displayRetireFence = FenceTime::NO_FENCE;
             frame.releaseFence = FenceTime::NO_FENCE;
             // The consumer only sends valid frames.
             frame.valid = true;
@@ -312,8 +301,6 @@
                 &frame.gpuCompositionDoneFence, d.mGpuCompositionDoneFence);
         applyFenceDelta(&mPresentTimeline,
                 &frame.displayPresentFence, d.mDisplayPresentFence);
-        applyFenceDelta(&mRetireTimeline,
-                &frame.displayRetireFence, d.mDisplayRetireFence);
         applyFenceDelta(&mReleaseTimeline,
                 &frame.releaseFence, d.mReleaseFence);
     }
@@ -323,7 +310,6 @@
     mAcquireTimeline.updateSignalTimes();
     mGpuCompositionDoneTimeline.updateSignalTimes();
     mPresentTimeline.updateSignalTimes();
-    mRetireTimeline.updateSignalTimes();
     mReleaseTimeline.updateSignalTimes();
 }
 
@@ -444,18 +430,6 @@
     }
 }
 
-void ConsumerFrameEventHistory::addRetire(
-        uint64_t frameNumber, const std::shared_ptr<FenceTime>& displayRetire) {
-    FrameEvents* frame = getFrame(frameNumber, &mRetireOffset);
-    if (frame == nullptr) {
-        ALOGE_IF(mProducerWantsEvents, "addRetire: Did not find frame.");
-        return;
-    }
-    frame->addRetireCalled = true;
-    frame->displayRetireFence = displayRetire;
-    mFramesDirty[mRetireOffset].setDirty<FrameEvent::DISPLAY_RETIRE>();
-}
-
 void ConsumerFrameEventHistory::addRelease(uint64_t frameNumber,
         nsecs_t dequeueReadyTime, std::shared_ptr<FenceTime>&& release) {
     FrameEvents* frame = getFrame(frameNumber, &mReleaseOffset);
@@ -515,7 +489,6 @@
     : mIndex(index),
       mFrameNumber(frameTimestamps.frameNumber),
       mAddPostCompositeCalled(frameTimestamps.addPostCompositeCalled),
-      mAddRetireCalled(frameTimestamps.addRetireCalled),
       mAddReleaseCalled(frameTimestamps.addReleaseCalled),
       mPostedTime(frameTimestamps.postedTime),
       mRequestedPresentTime(frameTimestamps.requestedPresentTime),
@@ -531,9 +504,6 @@
         mDisplayPresentFence =
                 frameTimestamps.displayPresentFence->getSnapshot();
     }
-    if (dirtyFields.isDirty<FrameEvent::DISPLAY_RETIRE>()) {
-        mDisplayRetireFence = frameTimestamps.displayRetireFence->getSnapshot();
-    }
     if (dirtyFields.isDirty<FrameEvent::RELEASE>()) {
         mReleaseFence = frameTimestamps.releaseFence->getSnapshot();
     }
@@ -541,9 +511,8 @@
 
 constexpr size_t FrameEventsDelta::minFlattenedSize() {
     return sizeof(FrameEventsDelta::mFrameNumber) +
-            sizeof(uint8_t) + // mIndex
+            sizeof(uint16_t) + // mIndex
             sizeof(uint8_t) + // mAddPostCompositeCalled
-            sizeof(uint8_t) + // mAddRetireCalled
             sizeof(uint8_t) + // mAddReleaseCalled
             sizeof(FrameEventsDelta::mPostedTime) +
             sizeof(FrameEventsDelta::mRequestedPresentTime) +
@@ -578,19 +547,17 @@
     }
 
     if (mIndex >= FrameEventHistory::MAX_FRAME_HISTORY ||
-            mIndex > std::numeric_limits<uint8_t>::max()) {
+            mIndex > std::numeric_limits<uint16_t>::max()) {
         return BAD_VALUE;
     }
 
     FlattenableUtils::write(buffer, size, mFrameNumber);
 
-    // These are static_cast to uint8_t for alignment.
-    FlattenableUtils::write(buffer, size, static_cast<uint8_t>(mIndex));
+    // These are static_cast to uint16_t/uint8_t for alignment.
+    FlattenableUtils::write(buffer, size, static_cast<uint16_t>(mIndex));
     FlattenableUtils::write(
             buffer, size, static_cast<uint8_t>(mAddPostCompositeCalled));
     FlattenableUtils::write(
-            buffer, size, static_cast<uint8_t>(mAddRetireCalled));
-    FlattenableUtils::write(
             buffer, size, static_cast<uint8_t>(mAddReleaseCalled));
 
     FlattenableUtils::write(buffer, size, mPostedTime);
@@ -618,19 +585,18 @@
 
     FlattenableUtils::read(buffer, size, mFrameNumber);
 
-    // These were written as uint8_t for alignment.
-    uint8_t temp = 0;
-    FlattenableUtils::read(buffer, size, temp);
-    mIndex = temp;
+    // These were written as uint16_t/uint8_t for alignment.
+    uint16_t temp16 = 0;
+    FlattenableUtils::read(buffer, size, temp16);
+    mIndex = temp16;
     if (mIndex >= FrameEventHistory::MAX_FRAME_HISTORY) {
         return BAD_VALUE;
     }
-    FlattenableUtils::read(buffer, size, temp);
-    mAddPostCompositeCalled = static_cast<bool>(temp);
-    FlattenableUtils::read(buffer, size, temp);
-    mAddRetireCalled = static_cast<bool>(temp);
-    FlattenableUtils::read(buffer, size, temp);
-    mAddReleaseCalled = static_cast<bool>(temp);
+    uint8_t temp8 = 0;
+    FlattenableUtils::read(buffer, size, temp8);
+    mAddPostCompositeCalled = static_cast<bool>(temp8);
+    FlattenableUtils::read(buffer, size, temp8);
+    mAddReleaseCalled = static_cast<bool>(temp8);
 
     FlattenableUtils::read(buffer, size, mPostedTime);
     FlattenableUtils::read(buffer, size, mRequestedPresentTime);
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 4d2692f..5a32d05 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -166,50 +166,6 @@
         return result != 0;
     }
 
-    virtual status_t getSupportedFrameTimestamps(
-            std::vector<FrameEvent>* outSupported) const {
-        if (!outSupported) {
-            return UNEXPECTED_NULL;
-        }
-        outSupported->clear();
-
-        Parcel data, reply;
-
-        status_t err = data.writeInterfaceToken(
-                ISurfaceComposer::getInterfaceDescriptor());
-        if (err != NO_ERROR) {
-            return err;
-        }
-
-        err = remote()->transact(
-                BnSurfaceComposer::GET_SUPPORTED_FRAME_TIMESTAMPS,
-                data, &reply);
-        if (err != NO_ERROR) {
-            return err;
-        }
-
-        int32_t result = 0;
-        err = reply.readInt32(&result);
-        if (err != NO_ERROR) {
-            return err;
-        }
-        if (result != NO_ERROR) {
-            return result;
-        }
-
-        std::vector<int32_t> supported;
-        err = reply.readInt32Vector(&supported);
-        if (err != NO_ERROR) {
-            return err;
-        }
-
-        outSupported->reserve(supported.size());
-        for (int32_t s : supported) {
-            outSupported->push_back(static_cast<FrameEvent>(s));
-        }
-        return NO_ERROR;
-    }
-
     virtual sp<IDisplayEventConnection> createDisplayEventConnection()
     {
         Parcel data, reply;
@@ -580,25 +536,6 @@
             reply->writeInt32(result);
             return NO_ERROR;
         }
-        case GET_SUPPORTED_FRAME_TIMESTAMPS: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            std::vector<FrameEvent> supportedTimestamps;
-            status_t result = getSupportedFrameTimestamps(&supportedTimestamps);
-            status_t err = reply->writeInt32(result);
-            if (err != NO_ERROR) {
-                return err;
-            }
-            if (result != NO_ERROR) {
-                return result;
-            }
-
-            std::vector<int32_t> supported;
-            supported.reserve(supportedTimestamps.size());
-            for (FrameEvent s : supportedTimestamps) {
-                supported.push_back(static_cast<int32_t>(s));
-            }
-            return reply->writeInt32Vector(supported);
-        }
         case CREATE_DISPLAY_EVENT_CONNECTION: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IDisplayEventConnection> connection(createDisplayEventConnection());
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index a2e12f7..06fc31d 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -37,6 +37,9 @@
 #include <gui/ISurfaceComposer.h>
 #include <private/gui/ComposerService.h>
 
+#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <configstore/Utils.h>
+
 namespace android {
 
 Surface::Surface(
@@ -49,9 +52,6 @@
       mAutoRefresh(false),
       mSharedBufferSlot(BufferItem::INVALID_BUFFER_SLOT),
       mSharedBufferHasBeenQueued(false),
-      mQueriedSupportedTimestamps(false),
-      mFrameTimestampsSupportsPresent(false),
-      mFrameTimestampsSupportsRetire(false),
       mEnableFrameTimestamps(false),
       mFrameEventHistory(std::make_unique<ProducerFrameEventHistory>())
 {
@@ -199,7 +199,6 @@
         const nsecs_t* outLastRefreshStartTime,
         const nsecs_t* outGpuCompositionDoneTime,
         const nsecs_t* outDisplayPresentTime,
-        const nsecs_t* outDisplayRetireTime,
         const nsecs_t* outDequeueReadyTime,
         const nsecs_t* outReleaseTime) {
     bool checkForLatch = (outLatchTime != nullptr) && !e->hasLatchInfo();
@@ -210,13 +209,11 @@
     bool checkForDisplayPresent = (outDisplayPresentTime != nullptr) &&
             !e->hasDisplayPresentInfo();
 
-    // LastRefreshStart, DisplayRetire, DequeueReady, and Release are never
+    // LastRefreshStart, DequeueReady, and Release are never
     // available for the last frame.
     bool checkForLastRefreshStart = (outLastRefreshStartTime != nullptr) &&
             !e->hasLastRefreshStartInfo() &&
             (e->frameNumber != lastFrameNumber);
-    bool checkForDisplayRetire = (outDisplayRetireTime != nullptr) &&
-            !e->hasDisplayRetireInfo() && (e->frameNumber != lastFrameNumber);
     bool checkForDequeueReady = (outDequeueReadyTime != nullptr) &&
             !e->hasDequeueReadyInfo() && (e->frameNumber != lastFrameNumber);
     bool checkForRelease = (outReleaseTime != nullptr) &&
@@ -225,8 +222,7 @@
     // RequestedPresent and Acquire info are always available producer-side.
     return checkForLatch || checkForFirstRefreshStart ||
             checkForLastRefreshStart || checkForGpuCompositionDone ||
-            checkForDisplayPresent || checkForDisplayRetire ||
-            checkForDequeueReady || checkForRelease;
+            checkForDisplayPresent || checkForDequeueReady || checkForRelease;
 }
 
 static void getFrameTimestamp(nsecs_t *dst, const nsecs_t& src) {
@@ -246,8 +242,8 @@
         nsecs_t* outRequestedPresentTime, nsecs_t* outAcquireTime,
         nsecs_t* outLatchTime, nsecs_t* outFirstRefreshStartTime,
         nsecs_t* outLastRefreshStartTime, nsecs_t* outGpuCompositionDoneTime,
-        nsecs_t* outDisplayPresentTime, nsecs_t* outDisplayRetireTime,
-        nsecs_t* outDequeueReadyTime, nsecs_t* outReleaseTime) {
+        nsecs_t* outDisplayPresentTime, nsecs_t* outDequeueReadyTime,
+        nsecs_t* outReleaseTime) {
     ATRACE_CALL();
 
     Mutex::Autolock lock(mMutex);
@@ -256,15 +252,6 @@
         return INVALID_OPERATION;
     }
 
-    // Verify the requested timestamps are supported.
-    querySupportedTimestampsLocked();
-    if (outDisplayPresentTime != nullptr && !mFrameTimestampsSupportsPresent) {
-        return BAD_VALUE;
-    }
-    if (outDisplayRetireTime != nullptr && !mFrameTimestampsSupportsRetire) {
-        return BAD_VALUE;
-    }
-
     FrameEvents* events = mFrameEventHistory->getFrame(frameNumber);
     if (events == nullptr) {
         // If the entry isn't available in the producer, it's definitely not
@@ -276,7 +263,7 @@
     if (checkConsumerForUpdates(events, mLastFrameNumber,
             outLatchTime, outFirstRefreshStartTime, outLastRefreshStartTime,
             outGpuCompositionDoneTime, outDisplayPresentTime,
-            outDisplayRetireTime, outDequeueReadyTime, outReleaseTime)) {
+            outDequeueReadyTime, outReleaseTime)) {
         FrameEventHistoryDelta delta;
         mGraphicBufferProducer->getFrameTimestamps(&delta);
         mFrameEventHistory->applyDelta(delta);
@@ -300,12 +287,14 @@
             outGpuCompositionDoneTime, events->gpuCompositionDoneFence);
     getFrameTimestampFence(
             outDisplayPresentTime, events->displayPresentFence);
-    getFrameTimestampFence(outDisplayRetireTime, events->displayRetireFence);
     getFrameTimestampFence(outReleaseTime, events->releaseFence);
 
     return NO_ERROR;
 }
 
+using namespace android::hardware::configstore;
+using namespace android::hardware::configstore::V1_0;
+
 status_t Surface::getWideColorSupport(bool* supported) {
     ATRACE_CALL();
 
@@ -318,13 +307,19 @@
     if (err)
         return err;
 
+    bool wideColorBoardConfig =
+        getBool<ISurfaceFlingerConfigs,
+                &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
+
     *supported = false;
     for (android_color_mode_t colorMode : colorModes) {
         switch (colorMode) {
             case HAL_COLOR_MODE_DISPLAY_P3:
             case HAL_COLOR_MODE_ADOBE_RGB:
             case HAL_COLOR_MODE_DCI_P3:
-                *supported = true;
+                if (wideColorBoardConfig) {
+                    *supported = true;
+                }
                 break;
             default:
                 break;
@@ -740,31 +735,6 @@
     return err;
 }
 
-void Surface::querySupportedTimestampsLocked() const {
-    // mMutex must be locked when calling this method.
-
-    if (mQueriedSupportedTimestamps) {
-        return;
-    }
-    mQueriedSupportedTimestamps = true;
-
-    std::vector<FrameEvent> supportedFrameTimestamps;
-    status_t err = composerService()->getSupportedFrameTimestamps(
-            &supportedFrameTimestamps);
-
-    if (err != NO_ERROR) {
-        return;
-    }
-
-    for (auto sft : supportedFrameTimestamps) {
-        if (sft == FrameEvent::DISPLAY_PRESENT) {
-            mFrameTimestampsSupportsPresent = true;
-        } else if (sft == FrameEvent::DISPLAY_RETIRE) {
-            mFrameTimestampsSupportsRetire = true;
-        }
-    }
-}
-
 int Surface::query(int what, int* value) const {
     ATRACE_CALL();
     ALOGV("Surface::query");
@@ -826,16 +796,6 @@
                         static_cast<int>(durationUs);
                 return NO_ERROR;
             }
-            case NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT: {
-                querySupportedTimestampsLocked();
-                *value = mFrameTimestampsSupportsPresent ? 1 : 0;
-                return NO_ERROR;
-            }
-            case NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_RETIRE: {
-                querySupportedTimestampsLocked();
-                *value = mFrameTimestampsSupportsRetire ? 1 : 0;
-                return NO_ERROR;
-            }
             case NATIVE_WINDOW_IS_VALID: {
                 *value = mGraphicBufferProducer != nullptr ? 1 : 0;
                 return NO_ERROR;
@@ -1090,14 +1050,13 @@
     nsecs_t* outLastRefreshStartTime = va_arg(args, int64_t*);
     nsecs_t* outGpuCompositionDoneTime = va_arg(args, int64_t*);
     nsecs_t* outDisplayPresentTime = va_arg(args, int64_t*);
-    nsecs_t* outDisplayRetireTime = va_arg(args, int64_t*);
     nsecs_t* outDequeueReadyTime = va_arg(args, int64_t*);
     nsecs_t* outReleaseTime = va_arg(args, int64_t*);
     return getFrameTimestamps(frameId,
             outRequestedPresentTime, outAcquireTime, outLatchTime,
             outFirstRefreshStartTime, outLastRefreshStartTime,
             outGpuCompositionDoneTime, outDisplayPresentTime,
-            outDisplayRetireTime, outDequeueReadyTime, outReleaseTime);
+            outDequeueReadyTime, outReleaseTime);
 }
 
 int Surface::dispatchGetWideColorSupport(va_list args) {
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 4492a08..3a99147 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -8,6 +8,7 @@
     clang: true,
 
     srcs: [
+        "BufferItemConsumer_test.cpp",
         "BufferQueue_test.cpp",
         "CpuConsumer_test.cpp",
         "FillBuffer.cpp",
diff --git a/libs/gui/tests/BufferItemConsumer_test.cpp b/libs/gui/tests/BufferItemConsumer_test.cpp
new file mode 100644
index 0000000..d64e530
--- /dev/null
+++ b/libs/gui/tests/BufferItemConsumer_test.cpp
@@ -0,0 +1,206 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "BufferItemConsumer_test"
+//#define LOG_NDEBUG 0
+
+#include <gtest/gtest.h>
+#include <gui/BufferItemConsumer.h>
+#include <gui/IProducerListener.h>
+#include <gui/Surface.h>
+
+namespace android {
+
+static constexpr int kWidth = 100;
+static constexpr int kHeight = 100;
+static constexpr int kMaxLockedBuffers = 3;
+static constexpr int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+static constexpr int kFrameSleepUs = 30 * 1000;
+
+class BufferItemConsumerTest : public ::testing::Test {
+   protected:
+    struct BufferFreedListener
+        : public BufferItemConsumer::BufferFreedListener {
+        explicit BufferFreedListener(BufferItemConsumerTest* test)
+            : mTest(test) {}
+        void onBufferFreed(const wp<GraphicBuffer>& /* gBuffer */) override {
+            mTest->HandleBufferFreed();
+        }
+        BufferItemConsumerTest* mTest;
+    };
+
+    void SetUp() override {
+        BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+        mBIC =
+            new BufferItemConsumer(mConsumer, kFormat, kMaxLockedBuffers, true);
+        String8 name("BufferItemConsumer_Under_Test");
+        mBIC->setName(name);
+        mBFL = new BufferFreedListener(this);
+        mBIC->setBufferFreedListener(mBFL);
+
+        sp<IProducerListener> producerListener = new DummyProducerListener();
+        IGraphicBufferProducer::QueueBufferOutput bufferOutput;
+        ASSERT_EQ(NO_ERROR,
+                  mProducer->connect(producerListener, NATIVE_WINDOW_API_CPU,
+                                     true, &bufferOutput));
+        ASSERT_EQ(NO_ERROR,
+                  mProducer->setMaxDequeuedBufferCount(kMaxLockedBuffers));
+    }
+
+    int GetFreedBufferCount() {
+        std::lock_guard<std::mutex> lock(mMutex);
+        return mFreedBufferCount;
+    }
+
+    void HandleBufferFreed() {
+        std::lock_guard<std::mutex> lock(mMutex);
+        mFreedBufferCount++;
+        ALOGV("HandleBufferFreed, mFreedBufferCount=%d", mFreedBufferCount);
+    }
+
+    void DequeueBuffer(int* outSlot) {
+        ASSERT_NE(outSlot, nullptr);
+
+        int slot;
+        sp<Fence> outFence;
+        status_t ret = mProducer->dequeueBuffer(&slot, &outFence, kWidth,
+                                                kHeight, 0, 0, nullptr);
+        ASSERT_GE(ret, 0);
+
+        ALOGV("dequeueBuffer: slot=%d", slot);
+        if (ret & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
+            ret = mProducer->requestBuffer(slot, &mBuffers[slot]);
+            ASSERT_EQ(NO_ERROR, ret);
+        }
+        *outSlot = slot;
+    }
+
+    void QueueBuffer(int slot) {
+        ALOGV("enqueueBuffer: slot=%d", slot);
+        IGraphicBufferProducer::QueueBufferInput bufferInput(
+            0ULL, true, HAL_DATASPACE_UNKNOWN, Rect::INVALID_RECT,
+            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
+        IGraphicBufferProducer::QueueBufferOutput bufferOutput;
+        status_t ret = mProducer->queueBuffer(slot, bufferInput, &bufferOutput);
+        ASSERT_EQ(NO_ERROR, ret);
+    }
+
+    void AcquireBuffer(int* outSlot) {
+        ASSERT_NE(outSlot, nullptr);
+        BufferItem buffer;
+        status_t ret = mBIC->acquireBuffer(&buffer, 0, false);
+        ASSERT_EQ(NO_ERROR, ret);
+
+        ALOGV("acquireBuffer: slot=%d", buffer.mSlot);
+        *outSlot = buffer.mSlot;
+    }
+
+    void ReleaseBuffer(int slot) {
+        ALOGV("releaseBuffer: slot=%d", slot);
+        BufferItem buffer;
+        buffer.mSlot = slot;
+        buffer.mGraphicBuffer = mBuffers[slot];
+        status_t ret = mBIC->releaseBuffer(buffer, Fence::NO_FENCE);
+        ASSERT_EQ(NO_ERROR, ret);
+    }
+
+
+    std::mutex mMutex;
+    int mFreedBufferCount{0};
+
+    sp<BufferItemConsumer> mBIC;
+    sp<BufferFreedListener> mBFL;
+    sp<IGraphicBufferProducer> mProducer;
+    sp<IGraphicBufferConsumer> mConsumer;
+    sp<GraphicBuffer> mBuffers[BufferQueueDefs::NUM_BUFFER_SLOTS];
+};
+
+// Test that detaching buffer from consumer side triggers onBufferFreed.
+TEST_F(BufferItemConsumerTest, TriggerBufferFreed_DetachBufferFromConsumer) {
+    int slot;
+    // Producer: generate a dummy buffer.
+    DequeueBuffer(&slot);
+    QueueBuffer(slot);
+
+    ASSERT_EQ(0, GetFreedBufferCount());
+    // Consumer: acquire the buffer and then detach it.
+    AcquireBuffer(&slot);
+    status_t ret = mBIC->detachBuffer(slot);
+    ASSERT_EQ(NO_ERROR, ret);
+
+    // Sleep to give some time for callbacks to happen.
+    usleep(kFrameSleepUs);
+    ASSERT_EQ(1, GetFreedBufferCount());
+}
+
+// Test that detaching buffer from producer side triggers onBufferFreed.
+TEST_F(BufferItemConsumerTest, TriggerBufferFreed_DetachBufferFromProducer) {
+    int slot;
+    // Let buffer go through the cycle at least once.
+    DequeueBuffer(&slot);
+    QueueBuffer(slot);
+    AcquireBuffer(&slot);
+    ReleaseBuffer(slot);
+
+    ASSERT_EQ(0, GetFreedBufferCount());
+
+    // Producer: generate the buffer again.
+    DequeueBuffer(&slot);
+
+    // Producer: detach the buffer.
+    status_t ret = mProducer->detachBuffer(slot);
+    ASSERT_EQ(NO_ERROR, ret);
+
+    // Sleep to give some time for callbacks to happen.
+    usleep(kFrameSleepUs);
+    ASSERT_EQ(1, GetFreedBufferCount());
+}
+
+// Test that abandoning BufferItemConsumer triggers onBufferFreed.
+TEST_F(BufferItemConsumerTest, TriggerBufferFreed_AbandonBufferItemConsumer) {
+    int slot;
+    // Let buffer go through the cycle at least once.
+    DequeueBuffer(&slot);
+    QueueBuffer(slot);
+    AcquireBuffer(&slot);
+    ReleaseBuffer(slot);
+
+    // Abandon the BufferItemConsumer.
+    mBIC->abandon();
+
+    // Sleep to give some time for callbacks to happen.
+    usleep(kFrameSleepUs);
+    ASSERT_EQ(1, GetFreedBufferCount());
+}
+
+// Test that delete BufferItemConsumer triggers onBufferFreed.
+TEST_F(BufferItemConsumerTest, TriggerBufferFreed_DeleteBufferItemConsumer) {
+    int slot;
+    // Let buffer go through the cycle at least once.
+    DequeueBuffer(&slot);
+    QueueBuffer(slot);
+    AcquireBuffer(&slot);
+    ReleaseBuffer(slot);
+
+    // Delete the BufferItemConsumer.
+    mBIC.clear();
+
+    // Sleep to give some time for callbacks to happen.
+    usleep(kFrameSleepUs);
+    ASSERT_EQ(1, GetFreedBufferCount());
+}
+
+}  // namespace android
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 91ce531..907e0493 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -1117,4 +1117,64 @@
     ASSERT_EQ(true, output.bufferReplaced);
 }
 
+TEST_F(BufferQueueTest, TestStaleBufferHandleSentAfterDisconnect) {
+    createBufferQueue();
+    sp<DummyConsumer> dc(new DummyConsumer);
+    ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true));
+    IGraphicBufferProducer::QueueBufferOutput output;
+    sp<IProducerListener> dummyListener(new DummyProducerListener);
+    ASSERT_EQ(OK, mProducer->connect(dummyListener, NATIVE_WINDOW_API_CPU,
+            true, &output));
+
+    int slot = BufferQueue::INVALID_BUFFER_SLOT;
+    sp<Fence> fence = Fence::NO_FENCE;
+    sp<GraphicBuffer> buffer = nullptr;
+    IGraphicBufferProducer::QueueBufferInput input(0ull, true,
+            HAL_DATASPACE_UNKNOWN, Rect::INVALID_RECT,
+            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
+
+    // Dequeue, request, and queue one buffer
+    status_t result = mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0,
+            nullptr);
+    ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result);
+    ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
+    ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
+
+    // Acquire and release the buffer. Upon acquiring, the buffer handle should
+    // be non-null since this is the first time we've acquired this slot.
+    BufferItem item;
+    ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
+    ASSERT_EQ(slot, item.mSlot);
+    ASSERT_NE(nullptr, item.mGraphicBuffer.get());
+    ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
+            EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
+
+    // Dequeue and queue the buffer again
+    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+    ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
+
+    // Acquire and release the buffer again. Upon acquiring, the buffer handle
+    // should be null since this is not the first time we've acquired this slot.
+    ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
+    ASSERT_EQ(slot, item.mSlot);
+    ASSERT_EQ(nullptr, item.mGraphicBuffer.get());
+    ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
+            EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
+
+    // Dequeue and queue the buffer again
+    ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr));
+    ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output));
+
+    // Disconnect the producer end. This should clear all of the slots and mark
+    // the buffer in the queue as stale.
+    ASSERT_EQ(OK, mProducer->disconnect(NATIVE_WINDOW_API_CPU));
+
+    // Acquire the buffer again. Upon acquiring, the buffer handle should not be
+    // null since the queued buffer should have been marked as stale, which
+    // should trigger the BufferQueue to resend the buffer handle.
+    ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
+    ASSERT_EQ(slot, item.mSlot);
+    ASSERT_NE(nullptr, item.mGraphicBuffer.get());
+}
+
 } // namespace android
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 58227e6..3932b92 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -358,11 +358,6 @@
 public:
     ~FakeSurfaceComposer() override {}
 
-    void setSupportedTimestamps(bool supportsPresent, bool supportsRetire) {
-        mSupportsPresent = supportsPresent;
-        mSupportsRetire = supportsRetire;
-    }
-
     sp<ISurfaceComposerClient> createConnection() override { return nullptr; }
     sp<ISurfaceComposerClient> createScopedConnection(
             const sp<IGraphicBufferProducer>& /* parent */) override {
@@ -386,30 +381,6 @@
             const sp<IGraphicBufferProducer>& /*surface*/) const override {
         return false;
     }
-
-    status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported)
-            const override {
-        *outSupported = {
-                FrameEvent::REQUESTED_PRESENT,
-                FrameEvent::ACQUIRE,
-                FrameEvent::LATCH,
-                FrameEvent::FIRST_REFRESH_START,
-                FrameEvent::LAST_REFRESH_START,
-                FrameEvent::GPU_COMPOSITION_DONE,
-                FrameEvent::DEQUEUE_READY,
-                FrameEvent::RELEASE
-        };
-        if (mSupportsPresent) {
-            outSupported->push_back(
-                        FrameEvent::DISPLAY_PRESENT);
-        }
-        if (mSupportsRetire) {
-            outSupported->push_back(
-                        FrameEvent::DISPLAY_RETIRE);
-        }
-        return NO_ERROR;
-    }
-
     void setPowerMode(const sp<IBinder>& /*display*/, int /*mode*/) override {}
     status_t getDisplayConfigs(const sp<IBinder>& /*display*/,
             Vector<DisplayInfo>* /*configs*/) override { return NO_ERROR; }
@@ -574,8 +545,7 @@
               kConsumerAcquireTime(frameStartTime + 301),
               kLatchTime(frameStartTime + 500),
               kDequeueReadyTime(frameStartTime + 600),
-              kRetireTime(frameStartTime + 700),
-              kReleaseTime(frameStartTime + 800),
+              kReleaseTime(frameStartTime + 700),
               mRefreshes {
                     { mFenceMap, frameStartTime + 410 },
                     { mFenceMap, frameStartTime + 420 },
@@ -595,7 +565,6 @@
         }
 
         void signalReleaseFences() {
-            mFenceMap.signalAllForTest(mRetire.mFence, kRetireTime);
             mFenceMap.signalAllForTest(mRelease.mFence, kReleaseTime);
         }
 
@@ -603,7 +572,6 @@
 
         FenceAndFenceTime mAcquireConsumer { mFenceMap };
         FenceAndFenceTime mAcquireProducer { mFenceMap };
-        FenceAndFenceTime mRetire { mFenceMap };
         FenceAndFenceTime mRelease { mFenceMap };
 
         const nsecs_t kPostedTime;
@@ -612,7 +580,6 @@
         const nsecs_t kConsumerAcquireTime;
         const nsecs_t kLatchTime;
         const nsecs_t kDequeueReadyTime;
-        const nsecs_t kRetireTime;
         const nsecs_t kReleaseTime;
 
         RefreshEvents mRefreshes[3];
@@ -651,7 +618,7 @@
                 &outRequestedPresentTime, &outAcquireTime, &outLatchTime,
                 &outFirstRefreshStartTime, &outLastRefreshStartTime,
                 &outGpuCompositionDoneTime, &outDisplayPresentTime,
-                &outDisplayRetireTime, &outDequeueReadyTime, &outReleaseTime);
+                &outDequeueReadyTime, &outReleaseTime);
     }
 
     void resetTimestamps() {
@@ -662,7 +629,6 @@
         outLastRefreshStartTime = -1;
         outGpuCompositionDoneTime = -1;
         outDisplayPresentTime = -1;
-        outDisplayRetireTime = -1;
         outDequeueReadyTime = -1;
         outReleaseTime = -1;
     }
@@ -715,8 +681,8 @@
         uint64_t nOldFrame = iOldFrame + 1;
         uint64_t nNewFrame = iNewFrame + 1;
 
-        // Latch, Composite, Retire, and Release the frames in a plausible
-        // order. Note: The timestamps won't necessarily match the order, but
+        // Latch, Composite, and Release the frames in a plausible order.
+        // Note: The timestamps won't necessarily match the order, but
         // that's okay for the purposes of this test.
         std::shared_ptr<FenceTime> gpuDoneFenceTime = FenceTime::NO_FENCE;
 
@@ -750,11 +716,6 @@
                 newFrame->mRefreshes[0].mPresent.mFenceTime,
                 newFrame->mRefreshes[0].kCompositorTiming);
 
-        // Retire the previous buffer just after compositing the new buffer.
-        if (oldFrame != nullptr) {
-            mCfeh->addRetire(nOldFrame, oldFrame->mRetire.mFenceTime);
-        }
-
         mCfeh->addPreComposition(nNewFrame, newFrame->mRefreshes[1].kStartTime);
         gpuDoneFenceTime = gpuComposited ?
                 newFrame->mRefreshes[1].mGpuCompositionDone.mFenceTime :
@@ -764,11 +725,6 @@
                 newFrame->mRefreshes[1].kCompositorTiming);
     }
 
-    void QueryPresentRetireSupported(
-            bool displayPresentSupported, bool displayRetireSupported);
-    void PresentOrRetireUnsupportedNoSyncTest(
-            bool displayPresentSupported, bool displayRetireSupported);
-
     sp<IGraphicBufferProducer> mProducer;
     sp<IGraphicBufferConsumer> mConsumer;
     sp<FakeConsumer> mFakeConsumer;
@@ -787,7 +743,6 @@
     int64_t outLastRefreshStartTime = -1;
     int64_t outGpuCompositionDoneTime = -1;
     int64_t outDisplayPresentTime = -1;
-    int64_t outDisplayRetireTime = -1;
     int64_t outDequeueReadyTime = -1;
     int64_t outReleaseTime = -1;
 
@@ -899,31 +854,6 @@
     EXPECT_EQ(4, mFakeConsumer->mGetFrameTimestampsCount);
 }
 
-void GetFrameTimestampsTest::QueryPresentRetireSupported(
-        bool displayPresentSupported, bool displayRetireSupported) {
-    mSurface->mFakeSurfaceComposer->setSupportedTimestamps(
-            displayPresentSupported, displayRetireSupported);
-
-    // Verify supported bits are forwarded.
-    int supportsPresent = -1;
-    mWindow.get()->query(mWindow.get(),
-            NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT, &supportsPresent);
-    EXPECT_EQ(displayPresentSupported, supportsPresent);
-
-    int supportsRetire = -1;
-    mWindow.get()->query(mWindow.get(),
-            NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_RETIRE, &supportsRetire);
-    EXPECT_EQ(displayRetireSupported, supportsRetire);
-}
-
-TEST_F(GetFrameTimestampsTest, QueryPresentSupported) {
-   QueryPresentRetireSupported(true, false);
-}
-
-TEST_F(GetFrameTimestampsTest, QueryRetireSupported) {
-   QueryPresentRetireSupported(false, true);
-}
-
 TEST_F(GetFrameTimestampsTest, SnapToNextTickBasic) {
     nsecs_t phase = 4000;
     nsecs_t interval = 1000;
@@ -1184,7 +1114,6 @@
     EXPECT_EQ(mFrames[0].mRefreshes[0].kGpuCompositionDoneTime,
             outGpuCompositionDoneTime);
     EXPECT_EQ(mFrames[0].mRefreshes[0].kPresentTime, outDisplayPresentTime);
-    EXPECT_EQ(mFrames[0].kRetireTime, outDisplayRetireTime);
     EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
     EXPECT_EQ(mFrames[0].kReleaseTime, outReleaseTime);
 
@@ -1200,7 +1129,6 @@
     EXPECT_EQ(mFrames[1].mRefreshes[0].kGpuCompositionDoneTime,
             outGpuCompositionDoneTime);
     EXPECT_EQ(mFrames[1].mRefreshes[0].kPresentTime, outDisplayPresentTime);
-    EXPECT_EQ(0, outDisplayRetireTime);
     EXPECT_EQ(0, outDequeueReadyTime);
     EXPECT_EQ(0, outReleaseTime);
 }
@@ -1209,7 +1137,6 @@
 // back to the producer and the producer saves its own fence.
 TEST_F(GetFrameTimestampsTest, QueueTimestampsNoSync) {
     enableFrameTimestamps();
-    mSurface->mFakeSurfaceComposer->setSupportedTimestamps(true, true);
 
     // Dequeue and queue frame 1.
     const uint64_t fId1 = getNextFrameId();
@@ -1222,7 +1149,7 @@
     int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
     int result = native_window_get_frame_timestamps(mWindow.get(), fId1,
             &outRequestedPresentTime, &outAcquireTime, nullptr, nullptr,
-            nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
+            nullptr, nullptr, nullptr, nullptr, nullptr);
     EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
     EXPECT_EQ(NO_ERROR, result);
     EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
@@ -1234,7 +1161,7 @@
     oldCount = mFakeConsumer->mGetFrameTimestampsCount;
     result = native_window_get_frame_timestamps(mWindow.get(), fId1,
             &outRequestedPresentTime, &outAcquireTime, nullptr, nullptr,
-            nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
+            nullptr, nullptr, nullptr, nullptr, nullptr);
     EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
     EXPECT_EQ(NO_ERROR, result);
     EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
@@ -1251,7 +1178,7 @@
     oldCount = mFakeConsumer->mGetFrameTimestampsCount;
     result = native_window_get_frame_timestamps(mWindow.get(), fId2,
             &outRequestedPresentTime, &outAcquireTime, nullptr, nullptr,
-            nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
+            nullptr, nullptr, nullptr, nullptr, nullptr);
     EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
     EXPECT_EQ(NO_ERROR, result);
     EXPECT_EQ(mFrames[1].kRequestedPresentTime, outRequestedPresentTime);
@@ -1263,7 +1190,7 @@
     oldCount = mFakeConsumer->mGetFrameTimestampsCount;
     result = native_window_get_frame_timestamps(mWindow.get(), fId2,
             &outRequestedPresentTime, &outAcquireTime, nullptr, nullptr,
-            nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
+            nullptr, nullptr, nullptr, nullptr, nullptr);
     EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
     EXPECT_EQ(NO_ERROR, result);
     EXPECT_EQ(mFrames[1].kRequestedPresentTime, outRequestedPresentTime);
@@ -1272,7 +1199,6 @@
 
 TEST_F(GetFrameTimestampsTest, ZeroRequestedTimestampsNoSync) {
     enableFrameTimestamps();
-    mSurface->mFakeSurfaceComposer->setSupportedTimestamps(true, true);
 
     // Dequeue and queue frame 1.
     dequeueAndQueue(0);
@@ -1292,7 +1218,7 @@
     // Verify a request for no timestamps doesn't result in a sync call.
     int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
     int result = native_window_get_frame_timestamps(mWindow.get(), fId2,
-            nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+            nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
             nullptr, nullptr, nullptr);
     EXPECT_EQ(NO_ERROR, result);
     EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
@@ -1302,7 +1228,6 @@
 // side without an additional sync call to the consumer.
 TEST_F(GetFrameTimestampsTest, FencesInProducerNoSync) {
     enableFrameTimestamps();
-    mSurface->mFakeSurfaceComposer->setSupportedTimestamps(true, true);
 
     // Dequeue and queue frame 1.
     const uint64_t fId1 = getNextFrameId();
@@ -1332,7 +1257,6 @@
     EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
     EXPECT_EQ(0, outGpuCompositionDoneTime);
     EXPECT_EQ(0, outDisplayPresentTime);
-    EXPECT_EQ(0, outDisplayRetireTime);
     EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
     EXPECT_EQ(0, outReleaseTime);
 
@@ -1351,7 +1275,6 @@
     EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
     EXPECT_EQ(0, outGpuCompositionDoneTime);
     EXPECT_EQ(0, outDisplayPresentTime);
-    EXPECT_EQ(0, outDisplayRetireTime);
     EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
     EXPECT_EQ(0, outReleaseTime);
 
@@ -1373,7 +1296,6 @@
     EXPECT_EQ(mFrames[0].mRefreshes[0].kGpuCompositionDoneTime,
             outGpuCompositionDoneTime);
     EXPECT_EQ(mFrames[0].mRefreshes[0].kPresentTime, outDisplayPresentTime);
-    EXPECT_EQ(mFrames[0].kRetireTime, outDisplayRetireTime);
     EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
     EXPECT_EQ(mFrames[0].kReleaseTime, outReleaseTime);
 }
@@ -1383,7 +1305,6 @@
 // never exist.
 TEST_F(GetFrameTimestampsTest, NoGpuNoSync) {
     enableFrameTimestamps();
-    mSurface->mFakeSurfaceComposer->setSupportedTimestamps(true, true);
 
     // Dequeue and queue frame 1.
     const uint64_t fId1 = getNextFrameId();
@@ -1413,7 +1334,6 @@
     EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
     EXPECT_EQ(0, outGpuCompositionDoneTime);
     EXPECT_EQ(0, outDisplayPresentTime);
-    EXPECT_EQ(0, outDisplayRetireTime);
     EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
     EXPECT_EQ(0, outReleaseTime);
 
@@ -1435,7 +1355,6 @@
     EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
     EXPECT_EQ(0, outGpuCompositionDoneTime);
     EXPECT_EQ(mFrames[0].mRefreshes[0].kPresentTime, outDisplayPresentTime);
-    EXPECT_EQ(mFrames[0].kRetireTime, outDisplayRetireTime);
     EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
     EXPECT_EQ(mFrames[0].kReleaseTime, outReleaseTime);
 }
@@ -1444,7 +1363,6 @@
 // the most recent frame, then a sync call is not done.
 TEST_F(GetFrameTimestampsTest, NoRetireOrReleaseNoSync) {
     enableFrameTimestamps();
-    mSurface->mFakeSurfaceComposer->setSupportedTimestamps(true, true);
 
     // Dequeue and queue frame 1.
     const uint64_t fId1 = getNextFrameId();
@@ -1475,7 +1393,6 @@
     EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
     EXPECT_EQ(0, outGpuCompositionDoneTime);
     EXPECT_EQ(0, outDisplayPresentTime);
-    EXPECT_EQ(0, outDisplayRetireTime);
     EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
     EXPECT_EQ(0, outReleaseTime);
 
@@ -1484,7 +1401,7 @@
     mFrames[1].signalRefreshFences();
 
     // Verify querying for all timestmaps of f2 does not do a sync call. Even
-    // though the lastRefresh, retire, dequeueReady, and release times aren't
+    // though the lastRefresh, dequeueReady, and release times aren't
     // available, a sync call should not occur because it's not possible for f2
     // to encounter the final value for those events until another frame is
     // queued.
@@ -1500,45 +1417,8 @@
     EXPECT_EQ(mFrames[1].mRefreshes[1].kStartTime, outLastRefreshStartTime);
     EXPECT_EQ(0, outGpuCompositionDoneTime);
     EXPECT_EQ(mFrames[1].mRefreshes[0].kPresentTime, outDisplayPresentTime);
-    EXPECT_EQ(0, outDisplayRetireTime);
     EXPECT_EQ(0, outDequeueReadyTime);
     EXPECT_EQ(0, outReleaseTime);
 }
 
-// This test verifies there are no sync calls for present or retire times
-// when they aren't supported and that an error is returned.
-void GetFrameTimestampsTest::PresentOrRetireUnsupportedNoSyncTest(
-        bool displayPresentSupported, bool displayRetireSupported) {
-
-    enableFrameTimestamps();
-    mSurface->mFakeSurfaceComposer->setSupportedTimestamps(
-        displayPresentSupported, displayRetireSupported);
-
-    // Dequeue and queue frame 1.
-    const uint64_t fId1 = getNextFrameId();
-    dequeueAndQueue(0);
-
-    // Verify a query for the Present and Retire times do not trigger
-    // a sync call if they are not supported.
-    resetTimestamps();
-    int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
-    int result = native_window_get_frame_timestamps(mWindow.get(), fId1,
-            nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
-            displayPresentSupported ? nullptr : &outDisplayPresentTime,
-            displayRetireSupported ? nullptr : &outDisplayRetireTime,
-            nullptr, nullptr);
-    EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
-    EXPECT_EQ(BAD_VALUE, result);
-    EXPECT_EQ(-1, outDisplayRetireTime);
-    EXPECT_EQ(-1, outDisplayPresentTime);
-}
-
-TEST_F(GetFrameTimestampsTest, PresentUnsupportedNoSync) {
-   PresentOrRetireUnsupportedNoSyncTest(false, true);
-}
-
-TEST_F(GetFrameTimestampsTest, RetireUnsupportedNoSync) {
-   PresentOrRetireUnsupportedNoSyncTest(true, false);
-}
-
 }
diff --git a/libs/hwc2on1adapter/Android.bp b/libs/hwc2on1adapter/Android.bp
index 2be3e67..438d3f5 100644
--- a/libs/hwc2on1adapter/Android.bp
+++ b/libs/hwc2on1adapter/Android.bp
@@ -48,6 +48,9 @@
         "-Wno-sign-conversion",
         "-Wno-switch-enum",
         "-Wno-float-equal",
+        "-Wno-shorten-64-to-32",
+        "-Wno-sign-compare",
+        "-Wno-missing-prototypes",
     ],
 
     srcs: [
diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp
index 9309275..d6d3304 100644
--- a/libs/sensor/SensorManager.cpp
+++ b/libs/sensor/SensorManager.cpp
@@ -38,14 +38,15 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
-android::Mutex android::SensorManager::sLock;
-std::map<String16, SensorManager*> android::SensorManager::sPackageInstances;
+Mutex SensorManager::sLock;
+std::map<String16, SensorManager*> SensorManager::sPackageInstances;
 
 SensorManager& SensorManager::getInstanceForPackage(const String16& packageName) {
+    waitForSensorService(nullptr);
+
     Mutex::Autolock _l(sLock);
     SensorManager* sensorManager;
-    std::map<String16, SensorManager*>::iterator iterator =
-        sPackageInstances.find(packageName);
+    auto iterator = sPackageInstances.find(packageName);
 
     if (iterator != sPackageInstances.end()) {
         sensorManager = iterator->second;
@@ -100,6 +101,28 @@
     free(mSensorList);
 }
 
+status_t SensorManager::waitForSensorService(sp<ISensorServer> *server) {
+    // try for 300 seconds (60*5(getService() tries for 5 seconds)) before giving up ...
+    sp<ISensorServer> s;
+    const String16 name("sensorservice");
+    for (int i = 0; i < 60; i++) {
+        status_t err = getService(name, &s);
+        switch (err) {
+            case NAME_NOT_FOUND:
+                sleep(1);
+                continue;
+            case NO_ERROR:
+                if (server != nullptr) {
+                    *server = s;
+                }
+                return NO_ERROR;
+            default:
+                return err;
+        }
+    }
+    return TIMED_OUT;
+}
+
 void SensorManager::sensorManagerDied() {
     Mutex::Autolock _l(mLock);
     mSensorServer.clear();
@@ -120,19 +143,8 @@
         }
     }
     if (initSensorManager) {
-        // try for 300 seconds (60*5(getService() tries for 5 seconds)) before giving up ...
-        const String16 name("sensorservice");
-        for (int i = 0; i < 60; i++) {
-            status_t err = getService(name, &mSensorServer);
-            if (err == NAME_NOT_FOUND) {
-                sleep(1);
-                continue;
-            }
-            if (err != NO_ERROR) {
-                return err;
-            }
-            break;
-        }
+        waitForSensorService(&mSensorServer);
+        LOG_ALWAYS_FATAL_IF(mSensorServer == nullptr, "getService(SensorService) NULL");
 
         class DeathObserver : public IBinder::DeathRecipient {
             SensorManager& mSensorManager;
@@ -144,8 +156,6 @@
             explicit DeathObserver(SensorManager& mgr) : mSensorManager(mgr) { }
         };
 
-        LOG_ALWAYS_FATAL_IF(mSensorServer.get() == NULL, "getService(SensorService) NULL");
-
         mDeathObserver = new DeathObserver(*const_cast<SensorManager *>(this));
         IInterface::asBinder(mSensorServer)->linkToDeath(mDeathObserver);
 
diff --git a/libs/sensor/include/sensor/SensorManager.h b/libs/sensor/include/sensor/SensorManager.h
index a3d9741..92c9823 100644
--- a/libs/sensor/include/sensor/SensorManager.h
+++ b/libs/sensor/include/sensor/SensorManager.h
@@ -68,6 +68,7 @@
 private:
     // DeathRecipient interface
     void sensorManagerDied();
+    static status_t waitForSensorService(sp<ISensorServer> *server);
 
     SensorManager(const String16& opPackageName);
     status_t assertStateLocked();
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index 452bad0..e068469 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -15,6 +15,7 @@
 sourceFiles = [
     "buffer_hub_client.cpp",
     "buffer_hub_rpc.cpp",
+    "dvr_buffer.cpp",
     "ion_buffer.cpp",
 ]
 
diff --git a/libs/vr/libbufferhub/buffer_hub_client.cpp b/libs/vr/libbufferhub/buffer_hub_client.cpp
index e2413bd..2749fd1 100644
--- a/libs/vr/libbufferhub/buffer_hub_client.cpp
+++ b/libs/vr/libbufferhub/buffer_hub_client.cpp
@@ -51,8 +51,6 @@
 
 int BufferHubBuffer::ImportBuffer() {
   ATRACE_NAME("BufferHubBuffer::ImportBuffer");
-  if (!IonBuffer::GetGrallocModule())
-    return -EIO;
 
   Status<std::vector<NativeBufferHandle<LocalHandle>>> status =
       InvokeRemoteMethod<BufferHubRPC::GetBuffers>();
@@ -132,6 +130,13 @@
   return ret;
 }
 
+void BufferHubBuffer::GetBlobFds(int* fds, size_t* fds_count,
+                                 size_t max_fds_count) const {
+  size_t numFds = static_cast<size_t>(native_handle()->numFds);
+  *fds_count = std::min(max_fds_count, numFds);
+  std::copy(native_handle()->data, native_handle()->data + *fds_count, fds);
+}
+
 BufferConsumer::BufferConsumer(LocalChannelHandle channel)
     : BASE(std::move(channel)) {
   const int ret = ImportBuffer();
diff --git a/libs/vr/libbufferhub/dvr_buffer.cpp b/libs/vr/libbufferhub/dvr_buffer.cpp
new file mode 100644
index 0000000..3eb611f
--- /dev/null
+++ b/libs/vr/libbufferhub/dvr_buffer.cpp
@@ -0,0 +1,124 @@
+#include <private/dvr/buffer_hub_client.h>
+#include <private/dvr/dvr_buffer.h>
+#include <ui/GraphicBuffer.h>
+
+using namespace android;
+
+struct DvrWriteBuffer {
+  std::unique_ptr<dvr::BufferProducer> write_buffer_;
+  sp<GraphicBuffer> graphic_buffer_;
+};
+
+struct DvrReadBuffer {
+  std::unique_ptr<dvr::BufferConsumer> read_buffer_;
+  sp<GraphicBuffer> graphic_buffer_;
+};
+
+namespace android {
+namespace dvr {
+
+DvrWriteBuffer* CreateDvrWriteBufferFromBufferProducer(
+    std::unique_ptr<dvr::BufferProducer> buffer_producer) {
+  DvrWriteBuffer* write_buffer = new DvrWriteBuffer;
+  write_buffer->write_buffer_ = std::move(buffer_producer);
+  return write_buffer;
+}
+
+DvrReadBuffer* CreateDvrReadBufferFromBufferConsumer(
+    std::unique_ptr<dvr::BufferConsumer> buffer_consumer) {
+  DvrReadBuffer* read_buffer = new DvrReadBuffer;
+  read_buffer->read_buffer_ = std::move(buffer_consumer);
+  return read_buffer;
+}
+
+}  // namespace dvr
+}  // namespace android
+
+namespace {
+
+void InitializeGraphicBuffer(const dvr::BufferHubBuffer* buffer,
+                             sp<GraphicBuffer>* graphic_buffer) {
+  *graphic_buffer = sp<GraphicBuffer>(new GraphicBuffer(
+      buffer->width(), buffer->height(), buffer->format(), 1, /* layer count */
+      buffer->usage(), buffer->stride(), buffer->native_handle(),
+      false /* keep ownership */));
+}
+
+}  // anonymous namespace
+
+extern "C" {
+
+void dvrWriteBufferDestroy(DvrWriteBuffer* client) { delete client; }
+
+void dvrWriteBufferGetBlobFds(DvrWriteBuffer* client, int* fds,
+                              size_t* fds_count, size_t max_fds_count) {
+  client->write_buffer_->GetBlobFds(fds, fds_count, max_fds_count);
+}
+
+int dvrWriteBufferGetAHardwareBuffer(DvrWriteBuffer* client,
+                                     AHardwareBuffer** hardware_buffer) {
+  if (!client->graphic_buffer_.get()) {
+    InitializeGraphicBuffer(client->write_buffer_.get(),
+                            &client->graphic_buffer_);
+  }
+  *hardware_buffer =
+      reinterpret_cast<AHardwareBuffer*>(client->graphic_buffer_.get());
+  return 0;
+}
+
+int dvrWriteBufferPost(DvrWriteBuffer* client, int ready_fence_fd,
+                       const void* meta, size_t meta_size_bytes) {
+  pdx::LocalHandle fence(ready_fence_fd);
+  int result = client->write_buffer_->Post(fence, meta, meta_size_bytes);
+  fence.Release();
+  return result;
+}
+
+int dvrWriteBufferGain(DvrWriteBuffer* client, int* release_fence_fd) {
+  pdx::LocalHandle release_fence;
+  int result = client->write_buffer_->Gain(&release_fence);
+  *release_fence_fd = release_fence.Release();
+  return result;
+}
+
+int dvrWriteBufferGainAsync(DvrWriteBuffer* client) {
+  return client->write_buffer_->GainAsync();
+}
+
+void dvrReadBufferGetBlobFds(DvrReadBuffer* client, int* fds, size_t* fds_count,
+                             size_t max_fds_count) {
+  client->read_buffer_->GetBlobFds(fds, fds_count, max_fds_count);
+}
+
+int dvrReadBufferGetAHardwareBuffer(DvrReadBuffer* client,
+                                    AHardwareBuffer** hardware_buffer) {
+  if (!client->graphic_buffer_.get()) {
+    InitializeGraphicBuffer(client->read_buffer_.get(),
+                            &client->graphic_buffer_);
+  }
+  *hardware_buffer =
+      reinterpret_cast<AHardwareBuffer*>(client->graphic_buffer_.get());
+  return 0;
+}
+
+int dvrReadBufferAcquire(DvrReadBuffer* client, int* ready_fence_fd, void* meta,
+                         size_t meta_size_bytes) {
+  pdx::LocalHandle ready_fence;
+  int result =
+      client->read_buffer_->Acquire(&ready_fence, meta, meta_size_bytes);
+  *ready_fence_fd = ready_fence.Release();
+  return result;
+}
+
+int dvrReadBufferRelease(DvrReadBuffer* client, int release_fence_fd) {
+  pdx::LocalHandle fence(release_fence_fd);
+  int result = client->read_buffer_->Release(fence);
+  fence.Release();
+  return result;
+}
+
+int dvrReadBufferReleaseAsync(DvrReadBuffer* client) {
+  return client->read_buffer_->ReleaseAsync();
+}
+
+}  // extern "C"
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
index cefde7b..aacc385 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
@@ -70,6 +70,10 @@
     return LocalHandle(dup(native_handle()->data[0]));
   }
 
+  // Get up to |max_fds_count| file descriptors for accessing the blob shared
+  // memory. |fds_count| will contain the actual number of file descriptors.
+  void GetBlobFds(int* fds, size_t* fds_count, size_t max_fds_count) const;
+
   using Client::event_fd;
 
   Status<int> GetEventMask(int events) {
diff --git a/libs/vr/libbufferhub/include/private/dvr/dvr_buffer.h b/libs/vr/libbufferhub/include/private/dvr/dvr_buffer.h
new file mode 100644
index 0000000..c14b1a3
--- /dev/null
+++ b/libs/vr/libbufferhub/include/private/dvr/dvr_buffer.h
@@ -0,0 +1,55 @@
+#ifndef ANDROID_DVR_BUFFER_H_
+#define ANDROID_DVR_BUFFER_H_
+
+#include <memory>
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct DvrWriteBuffer DvrWriteBuffer;
+typedef struct DvrReadBuffer DvrReadBuffer;
+typedef struct AHardwareBuffer AHardwareBuffer;
+
+// Write buffer
+void dvrWriteBufferDestroy(DvrWriteBuffer* client);
+void dvrWriteBufferGetBlobFds(DvrWriteBuffer* client, int* fds,
+                              size_t* fds_count, size_t max_fds_count);
+int dvrWriteBufferGetAHardwareBuffer(DvrWriteBuffer* client,
+                                     AHardwareBuffer** hardware_buffer);
+int dvrWriteBufferPost(DvrWriteBuffer* client, int ready_fence_fd,
+                       const void* meta, size_t meta_size_bytes);
+int dvrWriteBufferGain(DvrWriteBuffer* client, int* release_fence_fd);
+int dvrWriteBufferGainAsync(DvrWriteBuffer* client);
+
+// Read buffer
+void dvrReadBufferGetBlobFds(DvrReadBuffer* client, int* fds, size_t* fds_count,
+                             size_t max_fds_count);
+int dvrReadBufferGetAHardwareBuffer(DvrReadBuffer* client,
+                                    AHardwareBuffer** hardware_buffer);
+int dvrReadBufferAcquire(DvrReadBuffer* client, int* ready_fence_fd, void* meta,
+                         size_t meta_size_bytes);
+int dvrReadBufferRelease(DvrReadBuffer* client, int release_fence_fd);
+int dvrReadBufferReleaseAsync(DvrReadBuffer* client);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+namespace android {
+namespace dvr {
+
+class BufferProducer;
+class BufferConsumer;
+
+DvrWriteBuffer* CreateDvrWriteBufferFromBufferProducer(
+    std::unique_ptr<BufferProducer> buffer_producer);
+DvrReadBuffer* CreateDvrReadBufferFromBufferConsumer(
+    std::unique_ptr<BufferConsumer> buffer_consumer);
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_BUFFER_H_
diff --git a/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h b/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h
index 8125c54..e449cbd 100644
--- a/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h
+++ b/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h
@@ -2,6 +2,8 @@
 #define ANDROID_DVR_ION_BUFFER_H_
 
 #include <hardware/gralloc.h>
+#include <log/log.h>
+#include <ui/GraphicBuffer.h>
 
 namespace android {
 namespace dvr {
@@ -58,45 +60,24 @@
   int LockYUV(int usage, int x, int y, int width, int height,
               struct android_ycbcr* yuv);
   int Unlock();
-
-  buffer_handle_t handle() const { return handle_; }
-  int width() const { return width_; }
-  int height() const { return height_; }
-  int layer_count() const { return layer_count_; }
-  int stride() const { return stride_; }
-  int layer_stride() const { return layer_stride_; }
-  int format() const { return format_; }
-  int usage() const { return usage_; }
-
-  static gralloc_module_t const* GetGrallocModule() {
-    GrallocInit();
-    return gralloc_module_;
-  }
-
-  static alloc_device_t* GetGrallocDevice() {
-    GrallocInit();
-    return gralloc_device_;
-  }
+  buffer_handle_t handle() const { if (buffer_.get()) return buffer_->handle;
+                                   else return nullptr; }
+  int width() const { if (buffer_.get()) return buffer_->getWidth();
+                      else return 0; }
+  int height() const { if (buffer_.get()) return buffer_->getHeight();
+                       else return 0; }
+  int layer_count() const { if (buffer_.get()) return buffer_->getLayerCount();
+                            else return 0; }
+  int stride() const { if (buffer_.get()) return buffer_->getStride();
+                       else return 0; }
+  int layer_stride() const { return 0; }
+  int format() const { if (buffer_.get()) return buffer_->getPixelFormat();
+                       else return 0; }
+  int usage() const { if (buffer_.get()) return buffer_->getUsage();
+                      else return 0; }
 
  private:
-  buffer_handle_t handle_;
-  int width_;
-  int height_;
-  int layer_count_;
-  int stride_;
-  int layer_stride_;
-  int format_;
-  int usage_;
-  bool locked_;
-  bool needs_unregister_;
-
-  void Replace(buffer_handle_t handle, int width, int height, int layer_count,
-               int stride, int layer_stride, int format, int usage,
-               bool needs_unregister);
-
-  static void GrallocInit();
-  static gralloc_module_t const* gralloc_module_;
-  static alloc_device_t* gralloc_device_;
+  sp<GraphicBuffer> buffer_;
 
   IonBuffer(const IonBuffer&) = delete;
   void operator=(const IonBuffer&) = delete;
diff --git a/libs/vr/libbufferhub/ion_buffer.cpp b/libs/vr/libbufferhub/ion_buffer.cpp
index 4db2164..3fb3f3c 100644
--- a/libs/vr/libbufferhub/ion_buffer.cpp
+++ b/libs/vr/libbufferhub/ion_buffer.cpp
@@ -1,4 +1,5 @@
 #include <private/dvr/ion_buffer.h>
+#include <ui/GraphicBufferMapper.h>
 
 #include <log/log.h>
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -9,9 +10,6 @@
 namespace android {
 namespace dvr {
 
-gralloc_module_t const* IonBuffer::gralloc_module_ = nullptr;
-alloc_device_t* IonBuffer::gralloc_device_ = nullptr;
-
 IonBuffer::IonBuffer() : IonBuffer(nullptr, 0, 0, 0, 0, 0, 0, 0) {}
 
 IonBuffer::IonBuffer(int width, int height, int format, int usage)
@@ -23,33 +21,26 @@
                      int format, int usage)
     : IonBuffer(handle, width, height, 1, stride, 0, format, usage) {}
 
+
 IonBuffer::IonBuffer(buffer_handle_t handle, int width, int height,
                      int layer_count, int stride, int layer_stride, int format,
                      int usage)
-    : handle_(handle),
-      width_(width),
-      height_(height),
-      layer_count_(layer_count),
-      stride_(stride),
-      layer_stride_(layer_stride),
-      format_(format),
-      usage_(usage),
-      locked_(false),
-      needs_unregister_(false) {
+    : buffer_(nullptr) {
   ALOGD_IF(TRACE,
-           "IonBuffer::IonBuffer: handle=%p width=%d height=%d layer_count=%d "
-           "stride=%d layer stride=%d format=%d usage=%d",
-           handle_, width_, height_, layer_count_, stride_, layer_stride_,
-           format_, usage_);
-  GrallocInit();
+         "IonBuffer::IonBuffer: handle=%p width=%d height=%d layer_count=%d "
+         "stride=%d layer stride=%d format=%d usage=%d",
+         handle, width, height, layer_count, stride, layer_stride,
+         format, usage);
+  if (handle != 0) {
+    Import(handle, width, height, stride, format, usage);
+  }
 }
 
 IonBuffer::~IonBuffer() {
   ALOGD_IF(TRACE,
            "IonBuffer::~IonBuffer: handle=%p width=%d height=%d stride=%d "
            "format=%d usage=%d",
-           handle_, width_, height_, stride_, format_, usage_);
-
+           handle() , width(), height(), stride(), format(), usage());
   FreeHandle();
 }
 
@@ -58,111 +49,42 @@
 }
 
 IonBuffer& IonBuffer::operator=(IonBuffer&& other) {
-  ALOGD_IF(TRACE, "IonBuffer::operator=: handle_=%p other.handle_=%p", handle_,
-           other.handle_);
+  ALOGD_IF(TRACE, "IonBuffer::operator=: handle_=%p other.handle_=%p", handle(),
+           other.handle());
 
   if (this != &other) {
-    Replace(other.handle_, other.width_, other.height_, other.layer_count_,
-            other.stride_, other.layer_stride_, other.format_, other.usage_,
-            other.needs_unregister_);
-    locked_ = other.locked_;
-    other.handle_ = nullptr;
+    buffer_ = other.buffer_;
     other.FreeHandle();
   }
-
   return *this;
 }
 
 void IonBuffer::FreeHandle() {
-  if (handle_) {
-    // Lock/Unlock don't need to be balanced, but one Unlock is needed to
-    // clean/unmap the buffer. Warn if this didn't happen before freeing the
-    // native handle.
-    ALOGW_IF(locked_,
-             "IonBuffer::FreeHandle: freeing a locked handle!!! handle=%p",
-             handle_);
-
-    if (needs_unregister_) {
-      int ret = gralloc_module_->unregisterBuffer(gralloc_module_, handle_);
-      ALOGE_IF(ret < 0,
-               "IonBuffer::FreeHandle: Failed to unregister handle: %s",
-               strerror(-ret));
-
-      native_handle_close(const_cast<native_handle_t*>(handle_));
-      native_handle_delete(const_cast<native_handle_t*>(handle_));
-    } else {
-      int ret = gralloc_device_->free(gralloc_device_, handle_);
-      if (ret < 0) {
-        ALOGE("IonBuffer::FreeHandle: failed to free buffer: %s",
-              strerror(-ret));
-
-        // Not sure if this is the right thing to do. Attempting to prevent a
-        // memory leak of the native handle.
-        native_handle_close(const_cast<native_handle_t*>(handle_));
-        native_handle_delete(const_cast<native_handle_t*>(handle_));
-      }
-    }
+  if (buffer_.get()) {
+    // GraphicBuffer unregisters and cleans up the handle if needed
+    buffer_ = nullptr;
   }
-
-  // Always re-initialize these members, even if handle_ was nullptr, in case
-  // someone was dumb enough to pass a nullptr handle to the constructor or
-  // Reset.
-  handle_ = nullptr;
-  width_ = 0;
-  height_ = 0;
-  layer_count_ = 0;
-  stride_ = 0;
-  layer_stride_ = 0;
-  format_ = 0;
-  usage_ = 0;
-  locked_ = false;
-  needs_unregister_ = false;
 }
 
 int IonBuffer::Alloc(int width, int height, int format, int usage) {
-  ATRACE_NAME("IonBuffer::Alloc");
   ALOGD_IF(TRACE, "IonBuffer::Alloc: width=%d height=%d format=%d usage=%d",
            width, height, format, usage);
 
-  int stride;
-  buffer_handle_t handle;
-
-  int ret = gralloc_device_->alloc(gralloc_device_, width, height, format,
-                                   usage, &handle, &stride);
-  if (ret < 0) {
-    ALOGE("IonBuffer::Alloc: failed to allocate gralloc buffer: %s",
-          strerror(-ret));
-    return ret;
+  GraphicBufferMapper& mapper = GraphicBufferMapper::get();
+  buffer_ = new GraphicBuffer(width, height, format, usage);
+  if (mapper.registerBuffer(buffer_.get()) != OK) {
+    ALOGE("IonBuffer::Aloc: Failed to register buffer");
   }
-
-  Replace(handle, width, height, 1, stride, 0, format, usage, false);
   return 0;
 }
 
-void IonBuffer::Replace(buffer_handle_t handle, int width, int height,
-                        int layer_count, int stride, int layer_stride,
-                        int format, int usage, bool needs_unregister) {
-  FreeHandle();
-
-  handle_ = handle;
-  width_ = width;
-  height_ = height;
-  layer_count_ = layer_count;
-  stride_ = stride;
-  layer_stride_ = layer_stride;
-  format_ = format;
-  usage_ = usage;
-  needs_unregister_ = needs_unregister;
-}
-
 void IonBuffer::Reset(buffer_handle_t handle, int width, int height, int stride,
                       int format, int usage) {
   ALOGD_IF(TRACE,
            "IonBuffer::Reset: handle=%p width=%d height=%d stride=%d format=%d "
            "usage=%d",
            handle, width, height, stride, format, usage);
-
-  Replace(handle, width, height, 1, stride, 0, format, usage, false);
+  Import(handle, width, height, stride, format, usage);
 }
 
 int IonBuffer::Import(buffer_handle_t handle, int width, int height, int stride,
@@ -173,14 +95,14 @@
       "IonBuffer::Import: handle=%p width=%d height=%d stride=%d format=%d "
       "usage=%d",
       handle, width, height, stride, format, usage);
-
-  int ret = gralloc_module_->registerBuffer(gralloc_module_, handle);
-  if (ret < 0) {
-    ALOGE("IonBuffer::Import: failed to import handle: %s", strerror(-ret));
-    return ret;
+  FreeHandle();
+  GraphicBufferMapper& mapper = GraphicBufferMapper::get();
+  buffer_ = new GraphicBuffer(width, height, format, 1, usage,
+                              stride, (native_handle_t*)handle, true);
+  if (mapper.registerBuffer(buffer_.get()) != OK) {
+    ALOGE("IonBuffer::Import: Failed to register cloned buffer");
+    return -EINVAL;
   }
-
-  Replace(handle, width, height, 1, stride, 0, format, usage, true);
   return 0;
 }
 
@@ -262,15 +184,14 @@
   ALOGD_IF(TRACE,
            "IonBuffer::Lock: handle=%p usage=%d x=%d y=%d width=%d height=%d "
            "address=%p",
-           handle_, usage, x, y, width, height, address);
+           handle(), usage, x, y, width, height, address);
 
-  // Lock may be called multiple times; but only one Unlock is required.
-  const int err = gralloc_module_->lock(gralloc_module_, handle_, usage, x, y,
-                                        width, height, address);
-  if (!err)
-    locked_ = true;
-
-  return err;
+  status_t err = buffer_->lock(usage, Rect(x, y, x + width, y + height),
+                               address);
+  if (err != NO_ERROR)
+    return -EINVAL;
+  else
+    return 0;
 }
 
 int IonBuffer::LockYUV(int usage, int x, int y, int width, int height,
@@ -278,45 +199,25 @@
   ATRACE_NAME("IonBuffer::LockYUV");
   ALOGD_IF(TRACE,
            "IonBuffer::Lock: handle=%p usage=%d x=%d y=%d width=%d height=%d",
-           handle_, usage, x, y, width, height);
-  const int err = gralloc_module_->lock_ycbcr(gralloc_module_, handle_, usage,
-                                              x, y, width, height, yuv);
-  if (!err)
-    locked_ = true;
+           handle(), usage, x, y, width, height);
 
-  return err;
+  status_t err = buffer_->lockYCbCr(usage, Rect(x, y, x + width, y + height),
+                                    yuv);
+  if (err != NO_ERROR)
+    return -EINVAL;
+  else
+    return 0;
 }
 
 int IonBuffer::Unlock() {
   ATRACE_NAME("IonBuffer::Unlock");
-  ALOGD_IF(TRACE, "IonBuffer::Unlock: handle=%p", handle_);
+  ALOGD_IF(TRACE, "IonBuffer::Unlock: handle=%p", handle());
 
-  // Lock may be called multiple times; but only one Unlock is required.
-  const int err = gralloc_module_->unlock(gralloc_module_, handle_);
-  if (!err)
-    locked_ = false;
-
-  return err;
+  status_t err = buffer_->unlock();
+  if (err != NO_ERROR)
+    return -EINVAL;
+  else
+    return 0;
 }
-
-void IonBuffer::GrallocInit() {
-  static std::once_flag gralloc_flag;
-  std::call_once(gralloc_flag, []() {
-    hw_module_t const* module = nullptr;
-    alloc_device_t* device = nullptr;
-
-    int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
-    ALOGE_IF(err, "IonBuffer::GrallocInit: failed to find the %s module: %s",
-             GRALLOC_HARDWARE_MODULE_ID, strerror(-err));
-
-    err = gralloc_open(module, &device);
-    ALOGE_IF(err, "IonBuffer::GrallocInit: failed to open gralloc device: %s",
-             strerror(-err));
-
-    gralloc_module_ = reinterpret_cast<gralloc_module_t const*>(module);
-    gralloc_device_ = device;
-  });
-}
-
-}  // namespace dvr
-}  // namespace android
+} // namespace dvr
+} // namespace android
diff --git a/libs/vr/libbufferhub/tests/Android.mk b/libs/vr/libbufferhub/tests/Android.mk
deleted file mode 100644
index 5053e7d..0000000
--- a/libs/vr/libbufferhub/tests/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/libs/vr/libbufferhub/tests/ion_buffer/Android.mk b/libs/vr/libbufferhub/tests/ion_buffer/Android.mk
deleted file mode 100644
index 3bfdb7b..0000000
--- a/libs/vr/libbufferhub/tests/ion_buffer/Android.mk
+++ /dev/null
@@ -1,74 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-COMPONENT_TOP := ${LOCAL_PATH}/../..
-
-LOCAL_SRC_FILES := \
-        ion_buffer-test.cpp \
-        ../../ion_buffer.cpp \
-        ../../mocks/gralloc/gralloc.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-        libc \
-        libcutils \
-        libutils \
-        liblog
-
-LOCAL_STATIC_LIBRARIES := \
-        libgmock
-
-LOCAL_C_INCLUDES := \
-        ${COMPONENT_TOP}/mocks/gralloc \
-        ${COMPONENT_TOP}/include \
-        $(TOP)/system/core/base/include
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := ${LOCAL_C_INCLUDES}
-
-LOCAL_NATIVE_COVERAGE := true
-
-LOCAL_CFLAGS := -DTRACE=0 -g
-
-LOCAL_MODULE := ion_buffer-test
-LOCAL_MODULE_TAGS := tests
-
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-        ion_buffer-test.cpp \
-        ../../ion_buffer.cpp \
-        ../../mocks/gralloc/gralloc.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-        liblog
-
-LOCAL_STATIC_LIBRARIES := \
-        libgmock_host
-
-LOCAL_C_INCLUDES := \
-        ${COMPONENT_TOP}/mocks/gralloc \
-        ${COMPONENT_TOP}/include \
-        $(TOP)/system/core/base/include
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := ${LOCAL_C_INCLUDES}
-
-LOCAL_NATIVE_COVERAGE := true
-
-LOCAL_CFLAGS := -DTRACE=0
-
-LOCAL_MODULE := ion_buffer-host_test
-LOCAL_MODULE_TAGS := tests
-include $(BUILD_HOST_NATIVE_TEST)
-
-.PHONY: dvr_host_native_unit_tests
-dvr_host_native_unit_tests: ion_buffer-host_test
-ifeq (true,$(NATIVE_COVERAGE))
-  ion_buffer-host_test: llvm-cov
-  ion_buffer-test: llvm-cov
-  # This shouldn't be necessary, but the default build with
-  # NATIVE_COVERAGE=true manages to ion_buffer-test without
-  # building llvm-cov (droid is the default target).
-  droid: llvm-cov
-endif
diff --git a/libs/vr/libbufferhub/tests/ion_buffer/ion_buffer-test.cpp b/libs/vr/libbufferhub/tests/ion_buffer/ion_buffer-test.cpp
deleted file mode 100644
index 68f82d7..0000000
--- a/libs/vr/libbufferhub/tests/ion_buffer/ion_buffer-test.cpp
+++ /dev/null
@@ -1,375 +0,0 @@
-#include <gmock/gmock.h>
-#include <gralloc_mock.h>
-#include <gtest/gtest.h>
-#include <private/dvr/ion_buffer.h>
-
-using ::testing::_;
-using ::testing::Invoke;
-using ::testing::Return;
-using ::testing::SetArgPointee;
-using android::dvr::IonBuffer;
-
-GrallocMock* GrallocMock::staticObject = nullptr;
-
-namespace {
-
-const int w1 = 100;
-const int h1 = 200;
-const int d1 = 2;
-const int f1 = 1;
-const int u1 = 3;
-const int stride1 = 8;
-const int layer_stride1 = 8;
-native_handle_t handle1;
-const int w2 = 150;
-const int h2 = 300;
-const int d2 = 4;
-const int f2 = 2;
-const int u2 = 5;
-const int stride2 = 4;
-const int layer_stride2 = 4;
-native_handle_t handle2;
-const int kMaxFd = 10;
-const int kMaxInt = 10;
-char handleData[sizeof(native_handle_t) + (kMaxFd + kMaxInt) * sizeof(int)];
-native_handle_t* const dataHandle =
-    reinterpret_cast<native_handle_t*>(handleData);
-char refData[sizeof(native_handle_t) + (kMaxFd + kMaxInt) * sizeof(int)];
-native_handle_t* const refHandle = reinterpret_cast<native_handle_t*>(refData);
-
-class IonBufferUnitTest : public ::testing::Test {
- protected:
-  // You can remove any or all of the following functions if its body
-  // is empty.
-
-  IonBufferUnitTest() {
-    GrallocMock::staticObject = new GrallocMock;
-    // You can do set-up work for each test here.
-    // most ServicefsClients will use this initializer. Use as the
-    // default.
-  }
-
-  virtual ~IonBufferUnitTest() {
-    delete GrallocMock::staticObject;
-    GrallocMock::staticObject = nullptr;
-    // You can do clean-up work that doesn't throw exceptions here.
-  }
-
-  // If the constructor and destructor are not enough for setting up
-  // and cleaning up each test, you can define the following methods:
-
-  void SetUp() override {
-    // Code here will be called immediately after the constructor (right
-    // before each test).
-  }
-
-  void TearDown() override {
-    // Code here will be called immediately after each test (right
-    // before the destructor).
-  }
-};
-
-void TestIonBufferState(const IonBuffer& buffer, int w, int h, int d, int f,
-                        int u, native_handle_t* handle, int stride,
-                        int layer_stride) {
-  EXPECT_EQ(buffer.width(), w);
-  EXPECT_EQ(buffer.height(), h);
-  EXPECT_EQ(buffer.layer_count(), d);
-  EXPECT_EQ(buffer.format(), f);
-  EXPECT_EQ(buffer.usage(), u);
-  EXPECT_EQ(buffer.handle(), handle);
-  EXPECT_EQ(buffer.stride(), stride);
-  EXPECT_EQ(buffer.layer_stride(), layer_stride);
-}
-
-TEST_F(IonBufferUnitTest, TestFreeOnDestruction) {
-  // Set up |alloc|(|w1...|) to succeed once and fail on others calls.
-  EXPECT_CALL(*GrallocMock::staticObject, alloc(w1, h1, f1, u1, _, _))
-      .Times(1)
-      .WillOnce(DoAll(SetArgPointee<4>(&handle1), SetArgPointee<5>(stride1),
-                      Return(0)));
-  // Set up |free| to be called once.
-  EXPECT_CALL(*GrallocMock::staticObject, free(&handle1))
-      .Times(1)
-      .WillRepeatedly(Return(0));
-
-  IonBuffer buffer;
-  // First call to |alloc| with |w1...| set up to succeed.
-  int ret = buffer.Alloc(w1, h1, f1, u1);
-  EXPECT_EQ(ret, 0);
-  TestIonBufferState(buffer, w1, h1, 1, f1, u1, &handle1, stride1, 0);
-
-  // Scoped destructor will be called, calling |free| on |handle1|.
-}
-
-TEST_F(IonBufferUnitTest, TestAlloc) {
-  IonBuffer buffer;
-  // Set up |alloc|(|w1...|) to succeed once and fail on others calls.
-  EXPECT_CALL(*GrallocMock::staticObject, alloc(w1, h1, f1, u1, _, _))
-      .Times(2)
-      .WillOnce(DoAll(SetArgPointee<4>(&handle1), SetArgPointee<5>(stride1),
-                      Return(0)))
-      .WillRepeatedly(Return(-1));
-
-  // Set up |alloc|(|w2...|)  to succeed once and fail on others calls.
-  EXPECT_CALL(*GrallocMock::staticObject, alloc(w2, h2, f2, u2, _, _))
-      .Times(2)
-      .WillOnce(DoAll(SetArgPointee<4>(&handle2), SetArgPointee<5>(stride2),
-                      Return(0)))
-      .WillRepeatedly(Return(-1));
-  EXPECT_CALL(*GrallocMock::staticObject, free(&handle1))
-      .Times(1)
-      .WillRepeatedly(Return(0));
-  EXPECT_CALL(*GrallocMock::staticObject, free(&handle2))
-      .Times(1)
-      .WillRepeatedly(Return(0));
-
-  // First call to |alloc| with |w1...| set up to succeed.
-  int ret = buffer.Alloc(w1, h1, f1, u1);
-  EXPECT_EQ(ret, 0);
-  TestIonBufferState(buffer, w1, h1, 1, f1, u1, &handle1, stride1, 0);
-
-  // First call to |alloc| with |w2...| set up to succeed, |free| should be
-  // called once on |handle1|.
-  ret = buffer.Alloc(w2, h2, f2, u2);
-  EXPECT_EQ(ret, 0);
-  TestIonBufferState(buffer, w2, h2, 1, f2, u2, &handle2, stride2, 0);
-
-  // Second call to |alloc| with |w1| is set up to fail.
-  ret = buffer.Alloc(w1, h1, f1, u1);
-  EXPECT_LT(ret, 0);
-  TestIonBufferState(buffer, w2, h2, 1, f2, u2, &handle2, stride2, 0);
-
-  // |free| on |handle2| should be called here.
-  buffer.FreeHandle();
-  TestIonBufferState(buffer, 0, 0, 0, 0, 0, nullptr, 0, 0);
-
-  // |alloc| is set up to fail.
-  ret = buffer.Alloc(w2, h2, f2, u2);
-  EXPECT_LT(ret, 0);
-  TestIonBufferState(buffer, 0, 0, 0, 0, 0, nullptr, 0, 0);
-}
-
-TEST_F(IonBufferUnitTest, TestReset) {
-  IonBuffer buffer;
-  EXPECT_CALL(*GrallocMock::staticObject, free(&handle1))
-      .Times(1)
-      .WillRepeatedly(Return(0));
-  EXPECT_CALL(*GrallocMock::staticObject, free(&handle2))
-      .Times(1)
-      .WillRepeatedly(Return(0));
-  buffer.Reset(&handle1, w1, h1, stride1, f1, u1);
-  TestIonBufferState(buffer, w1, h1, 1, f1, u1, &handle1, stride1, 0);
-  buffer.Reset(&handle2, w2, h2, stride2, f2, u2);
-  TestIonBufferState(buffer, w2, h2, 1, f2, u2, &handle2, stride2, 0);
-  buffer.FreeHandle();
-}
-
-TEST_F(IonBufferUnitTest, TestImport1) {
-  IonBuffer buffer;
-  EXPECT_CALL(*GrallocMock::staticObject, registerBuffer(&handle1))
-      .Times(3)
-      .WillOnce(Return(0))
-      .WillRepeatedly(Return(-1));
-  EXPECT_CALL(*GrallocMock::staticObject, registerBuffer(&handle2))
-      .Times(3)
-      .WillOnce(Return(0))
-      .WillOnce(Return(-1))
-      .WillOnce(Return(0));
-  EXPECT_CALL(*GrallocMock::staticObject, unregisterBuffer(&handle1))
-      .Times(1)
-      .WillOnce(Return(0));
-  EXPECT_CALL(*GrallocMock::staticObject, native_handle_close(&handle1))
-      .Times(1);
-  EXPECT_CALL(*GrallocMock::staticObject, native_handle_delete(&handle1))
-      .Times(1);
-  EXPECT_CALL(*GrallocMock::staticObject, alloc(w1, h1, f1, u1, _, _))
-      .Times(1)
-      .WillRepeatedly(DoAll(SetArgPointee<4>(&handle1),
-                            SetArgPointee<5>(stride1), Return(0)));
-  EXPECT_CALL(*GrallocMock::staticObject, unregisterBuffer(&handle2))
-      .Times(2)
-      .WillRepeatedly(Return(0));
-  EXPECT_CALL(*GrallocMock::staticObject, native_handle_close(&handle2))
-      .Times(2);
-  EXPECT_CALL(*GrallocMock::staticObject, native_handle_delete(&handle2))
-      .Times(2);
-  EXPECT_CALL(*GrallocMock::staticObject, free(&handle1))
-      .Times(1)
-      .WillRepeatedly(Return(0));
-
-  int ret = buffer.Import(&handle1, w1, h1, stride1, f1, u1);
-  EXPECT_EQ(ret, 0);
-  TestIonBufferState(buffer, w1, h1, 1, f1, u1, &handle1, stride1, 0);
-  ret = buffer.Import(&handle2, w2, h2, stride2, f2, u2);
-  EXPECT_EQ(ret, 0);
-  TestIonBufferState(buffer, w2, h2, 1, f2, u2, &handle2, stride2, 0);
-  ret = buffer.Alloc(w1, h1, f1, u1);
-  EXPECT_EQ(ret, 0);
-  ret = buffer.Import(&handle2, w2, h2, stride2, f2, u2);
-  EXPECT_LT(ret, 0);
-  TestIonBufferState(buffer, w1, h1, 1, f1, u1, &handle1, stride1, 0);
-  ret = buffer.Import(&handle2, w2, h2, stride2, f2, u2);
-  EXPECT_EQ(ret, 0);
-  TestIonBufferState(buffer, w2, h2, 1, f2, u2, &handle2, stride2, 0);
-  ret = buffer.Import(&handle1, w1, h1, stride1, f1, u1);
-  EXPECT_LT(ret, 0);
-  TestIonBufferState(buffer, w2, h2, 1, f2, u2, &handle2, stride2, 0);
-  buffer.FreeHandle();
-  ret = buffer.Import(&handle1, w1, h1, stride1, f1, u1);
-  EXPECT_LT(ret, 0);
-  TestIonBufferState(buffer, 0, 0, 0, 0, 0, nullptr, 0, 0);
-}
-
-native_handle_t* native_handle_create_impl(int nFds, int nInts) {
-  if ((nFds + nInts) > (kMaxFd + kMaxInt))
-    return nullptr;
-  dataHandle->version = sizeof(native_handle_t);
-  dataHandle->numFds = nFds;
-  dataHandle->numInts = nInts;
-  for (int i = 0; i < nFds + nInts; i++)
-    dataHandle->data[i] = 0;
-  return dataHandle;
-}
-
-TEST_F(IonBufferUnitTest, TestImport2) {
-  IonBuffer buffer;
-  int ints[] = {211, 313, 444};
-  int fds[] = {-1, -1};
-  int ni = sizeof(ints) / sizeof(ints[0]);
-  int nfd = sizeof(fds) / sizeof(fds[0]);
-  EXPECT_CALL(*GrallocMock::staticObject, native_handle_create(nfd, ni))
-      .Times(3)
-      .WillOnce(Return(nullptr))
-      .WillRepeatedly(Invoke(native_handle_create_impl));
-  EXPECT_CALL(*GrallocMock::staticObject, registerBuffer(dataHandle))
-      .Times(2)
-      .WillOnce(Return(-1))
-      .WillRepeatedly(Return(0));
-  EXPECT_CALL(*GrallocMock::staticObject, native_handle_close(dataHandle))
-      .Times(2);
-  EXPECT_CALL(*GrallocMock::staticObject, native_handle_delete(dataHandle))
-      .Times(2);
-  EXPECT_CALL(*GrallocMock::staticObject, unregisterBuffer(dataHandle))
-      .Times(1)
-      .WillRepeatedly(Return(0));
-
-  int ret = buffer.Import(fds, -1, ints, ni, w1, h1, stride1, f1, u1);
-  EXPECT_LT(ret, 0);
-  ret = buffer.Import(fds, nfd, ints, -1, w1, h1, stride1, f1, u1);
-  EXPECT_LT(ret, 0);
-  ret = buffer.Import(fds, nfd, ints, ni, w1, h1, stride1, f1, u1);
-  EXPECT_LT(ret, 0);
-  ret = buffer.Import(fds, nfd, ints, ni, w1, h1, stride1, f1, u1);
-  EXPECT_LT(ret, 0);
-  ret = buffer.Import(fds, nfd, ints, ni, w1, h1, stride1, f1, u1);
-  EXPECT_EQ(ret, 0);
-  TestIonBufferState(buffer, w1, h1, 1, f1, u1, dataHandle, stride1, 0);
-  EXPECT_EQ(dataHandle->numFds, nfd);
-  EXPECT_EQ(dataHandle->numInts, ni);
-  for (int i = 0; i < nfd; i++)
-    EXPECT_EQ(dataHandle->data[i], fds[i]);
-  for (int i = 0; i < ni; i++)
-    EXPECT_EQ(dataHandle->data[nfd + i], ints[i]);
-  buffer.FreeHandle();
-}
-
-TEST_F(IonBufferUnitTest, TestDuplicate) {
-  IonBuffer buffer;
-  IonBuffer ref;
-  int ints[] = {211, 313, 444};
-  int fds[] = {-1, -1};
-  int ni = sizeof(ints) / sizeof(ints[0]);
-  int nfd = sizeof(fds) / sizeof(fds[0]);
-
-  for (int i = 0; i < nfd; i++) {
-    refHandle->data[i] = fds[i];
-  }
-  for (int i = 0; i < ni; i++) {
-    refHandle->data[i + nfd] = ints[i];
-  }
-
-  EXPECT_CALL(*GrallocMock::staticObject, alloc(w1, h1, f1, u1, _, _))
-      .Times(1)
-      .WillRepeatedly(DoAll(SetArgPointee<4>(refHandle),
-                            SetArgPointee<5>(stride1), Return(0)));
-  EXPECT_CALL(*GrallocMock::staticObject, native_handle_create(nfd, ni))
-      .Times(3)
-      .WillOnce(Return(nullptr))
-      .WillRepeatedly(Invoke(native_handle_create_impl));
-  EXPECT_CALL(*GrallocMock::staticObject, registerBuffer(dataHandle))
-      .Times(2)
-      .WillOnce(Return(-1))
-      .WillRepeatedly(Return(0));
-  EXPECT_CALL(*GrallocMock::staticObject, native_handle_close(dataHandle))
-      .Times(2);
-  EXPECT_CALL(*GrallocMock::staticObject, native_handle_delete(dataHandle))
-      .Times(2);
-  EXPECT_CALL(*GrallocMock::staticObject, unregisterBuffer(dataHandle))
-      .Times(1)
-      .WillRepeatedly(Return(0));
-  EXPECT_CALL(*GrallocMock::staticObject, free(refHandle))
-      .Times(1)
-      .WillRepeatedly(Return(0));
-
-  int ret = buffer.Duplicate(&ref);
-  EXPECT_LT(ret, 0);
-  ret = ref.Alloc(w1, h1, f1, u1);
-  EXPECT_EQ(ret, 0);
-  refHandle->numFds = -1;
-  refHandle->numInts = 0;
-  ret = buffer.Duplicate(&ref);
-  EXPECT_LT(ret, 0);
-  refHandle->numFds = nfd;
-  refHandle->numInts = ni;
-  ret = buffer.Duplicate(&ref);
-  EXPECT_LT(ret, 0);
-  ret = buffer.Duplicate(&ref);
-  EXPECT_LT(ret, 0);
-  ret = buffer.Duplicate(&ref);
-  EXPECT_EQ(ret, 0);
-  TestIonBufferState(buffer, w1, h1, 1, f1, u1, dataHandle, stride1, 0);
-  EXPECT_EQ(dataHandle->numFds, nfd);
-  EXPECT_EQ(dataHandle->numInts, ni);
-  for (int i = 0; i < nfd; i++)
-    EXPECT_LT(dataHandle->data[i], 0);
-  for (int i = 0; i < ni; i++)
-    EXPECT_EQ(dataHandle->data[nfd + i], ints[i]);
-  buffer.FreeHandle();
-  ref.FreeHandle();
-}
-
-TEST_F(IonBufferUnitTest, TestLockUnlock) {
-  IonBuffer buffer;
-  const int x = 12;
-  const int y = 24;
-  const int value1 = 17;
-  const int value2 = 25;
-  void* addr1;
-  void** addr = &addr1;
-
-  EXPECT_CALL(*GrallocMock::staticObject, alloc(w1, h1, f1, u1, _, _))
-      .Times(1)
-      .WillRepeatedly(DoAll(SetArgPointee<4>(&handle1),
-                            SetArgPointee<5>(stride1), Return(0)));
-  EXPECT_CALL(*GrallocMock::staticObject,
-              lock(&handle1, u2, x, y, w2, h2, addr))
-      .Times(1)
-      .WillRepeatedly(Return(value1));
-  EXPECT_CALL(*GrallocMock::staticObject, unlock(&handle1))
-      .Times(1)
-      .WillRepeatedly(Return(value2));
-  EXPECT_CALL(*GrallocMock::staticObject, free(&handle1))
-      .Times(1)
-      .WillRepeatedly(Return(0));
-
-  int ret = buffer.Alloc(w1, h1, f1, u1);
-  EXPECT_EQ(ret, 0);
-  ret = buffer.Lock(u2, x, y, w2, h2, addr);
-  EXPECT_EQ(ret, value1);
-  ret = buffer.Unlock();
-  EXPECT_EQ(ret, value2);
-  buffer.FreeHandle();
-}
-
-}  // namespace
diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp
index 10198fd..1c8f2c0 100644
--- a/libs/vr/libbufferhubqueue/Android.bp
+++ b/libs/vr/libbufferhubqueue/Android.bp
@@ -42,10 +42,15 @@
 
 cc_library {
     name: "libbufferhubqueue",
-    cflags = [ "-DLOGTAG=\"libbufferhubqueue\"" ],
+    cflags = [
+        "-DLOGTAG=\"libbufferhubqueue\"",
+        "-DTRACE=0",
+    ],
     srcs: sourceFiles,
     export_include_dirs: includeFiles,
+    export_static_lib_headers: staticLibraries,
     static_libs: staticLibraries,
     shared_libs: sharedLibraries,
 }
 
+subdirs = ["tests"]
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index a8077b9..bd6511d 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -1,7 +1,5 @@
 #include "include/private/dvr/buffer_hub_queue_client.h"
 
-//#define LOG_NDEBUG 0
-
 #include <inttypes.h>
 #include <log/log.h>
 #include <sys/epoll.h>
@@ -73,7 +71,8 @@
 
   auto return_value = status.take();
 
-  ALOGD("CreateConsumerQueue: meta_size_bytes=%zu", return_value.second);
+  ALOGD_IF(TRACE, "BufferHubQueue::CreateConsumerQueue: meta_size_bytes=%zu",
+           return_value.second);
   return ConsumerQueue::Create(std::move(return_value.first),
                                return_value.second);
 }
@@ -85,7 +84,7 @@
     int ret = epoll_fd_.Wait(events.data(), events.size(), timeout);
 
     if (ret == 0) {
-      ALOGD("Wait on epoll returns nothing before timeout.");
+      ALOGD_IF(TRACE, "Wait on epoll returns nothing before timeout.");
       return false;
     }
 
@@ -102,7 +101,7 @@
     for (int i = 0; i < num_events; i++) {
       int64_t index = static_cast<int64_t>(events[i].data.u64);
 
-      ALOGD("New BufferHubQueue event %d: index=%" PRId64, i, index);
+      ALOGD_IF(TRACE, "New BufferHubQueue event %d: index=%" PRId64, i, index);
 
       if (is_buffer_event_index(index)) {
         HandleBufferEvent(static_cast<size_t>(index), events[i]);
@@ -255,7 +254,7 @@
                                                          size_t* slot,
                                                          void* meta,
                                                          LocalHandle* fence) {
-  ALOGD("Dequeue: count=%zu, timeout=%d", count(), timeout);
+  ALOGD_IF(TRACE, "Dequeue: count=%zu, timeout=%d", count(), timeout);
 
   if (count() == 0 && !WaitForBuffers(timeout))
     return nullptr;
@@ -341,8 +340,9 @@
   // 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("ProducerQueue::AllocateBuffer, new buffer, channel_handle: %d",
-        buffer_handle.value());
+  ALOGD_IF(TRACE,
+           "ProducerQueue::AllocateBuffer, new buffer, channel_handle: %d",
+           buffer_handle.value());
 
   *out_slot = buffer_slot;
   return AddBuffer(BufferProducer::Import(std::move(buffer_handle)),
@@ -414,8 +414,9 @@
 
   auto buffer_handle_slots = status.take();
   for (auto& buffer_handle_slot : buffer_handle_slots) {
-    ALOGD("ConsumerQueue::ImportBuffers, new buffer, buffer_handle: %d",
-          buffer_handle_slot.first.value());
+    ALOGD_IF(TRACE,
+             "ConsumerQueue::ImportBuffers, new buffer, buffer_handle: %d",
+             buffer_handle_slot.first.value());
 
     std::unique_ptr<BufferConsumer> buffer_consumer =
         BufferConsumer::Import(std::move(buffer_handle_slot.first));
@@ -473,7 +474,7 @@
   } else if (ret < 0) {
     ALOGE("Failed to import buffers on buffer allocated event.");
   }
-  ALOGD("Imported %d consumer buffers.", ret);
+  ALOGD_IF(TRACE, "Imported %d consumer buffers.", ret);
   return ret;
 }
 
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_consumer.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_consumer.cpp
index 02bca09..1ea3994 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_consumer.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_consumer.cpp
@@ -1,7 +1,5 @@
 #include "include/private/dvr/buffer_hub_queue_consumer.h"
 
-//#define LOG_NDEBUG 0
-
 namespace android {
 namespace dvr {
 
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_core.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_core.cpp
index b013c85..a108042 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_core.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_core.cpp
@@ -1,8 +1,5 @@
 #include "include/private/dvr/buffer_hub_queue_core.h"
 
-//#define LOG_NDEBUG 0
-#define LOG_TAG "BufferHubQueueCore"
-
 #include <log/log.h>
 
 namespace android {
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
index 0deb764..ddf7fd2 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
@@ -1,7 +1,5 @@
 #include "include/private/dvr/buffer_hub_queue_producer.h"
 
-//#define LOG_NDEBUG 0
-
 #include <inttypes.h>
 #include <log/log.h>
 
@@ -14,7 +12,7 @@
 
 status_t BufferHubQueueProducer::requestBuffer(int slot,
                                                sp<GraphicBuffer>* buf) {
-  ALOGD("requestBuffer: slot=%d", slot);
+  ALOGD_IF(TRACE, "requestBuffer: slot=%d", slot);
 
   std::unique_lock<std::mutex> lock(core_->mutex_);
 
@@ -35,8 +33,8 @@
 
 status_t BufferHubQueueProducer::setMaxDequeuedBufferCount(
     int max_dequeued_buffers) {
-  ALOGD("setMaxDequeuedBufferCount: max_dequeued_buffers=%d",
-        max_dequeued_buffers);
+  ALOGD_IF(TRACE, "setMaxDequeuedBufferCount: max_dequeued_buffers=%d",
+           max_dequeued_buffers);
 
   std::unique_lock<std::mutex> lock(core_->mutex_);
 
@@ -63,8 +61,8 @@
                                                PixelFormat format,
                                                uint32_t usage,
                                                FrameEventHistoryDelta* /* outTimestamps */) {
-  ALOGD("dequeueBuffer: w=%u, h=%u, format=%d, usage=%u", width, height, format,
-        usage);
+  ALOGD_IF(TRACE, "dequeueBuffer: w=%u, h=%u, format=%d, usage=%u", width,
+           height, format, usage);
 
   status_t ret;
   std::unique_lock<std::mutex> lock(core_->mutex_);
@@ -134,7 +132,7 @@
 
   core_->buffers_[slot].mBufferState.freeQueued();
   core_->buffers_[slot].mBufferState.dequeue();
-  ALOGD("dequeueBuffer: slot=%zu", slot);
+  ALOGD_IF(TRACE, "dequeueBuffer: slot=%zu", slot);
 
   // TODO(jwcai) Handle fence properly. |BufferHub| has full fence support, we
   // just need to exopose that through |BufferHubQueue| once we need fence.
@@ -173,7 +171,7 @@
 status_t BufferHubQueueProducer::queueBuffer(int slot,
                                              const QueueBufferInput& input,
                                              QueueBufferOutput* /* output */) {
-  ALOGD("queueBuffer: slot %d", slot);
+  ALOGD_IF(TRACE, "queueBuffer: slot %d", slot);
 
   int64_t timestamp;
   sp<Fence> fence;
@@ -220,7 +218,7 @@
 
 status_t BufferHubQueueProducer::cancelBuffer(int slot,
                                               const sp<Fence>& fence) {
-  ALOGD(__FUNCTION__);
+  ALOGD_IF(TRACE, __FUNCTION__);
 
   std::unique_lock<std::mutex> lock(core_->mutex_);
 
@@ -241,13 +239,13 @@
   core_->producer_->Enqueue(buffer_producer, slot);
   core_->buffers_[slot].mBufferState.cancel();
   core_->buffers_[slot].mFence = fence;
-  ALOGD("cancelBuffer: slot %d", slot);
+  ALOGD_IF(TRACE, "cancelBuffer: slot %d", slot);
 
   return NO_ERROR;
 }
 
 status_t BufferHubQueueProducer::query(int what, int* out_value) {
-  ALOGD(__FUNCTION__);
+  ALOGD_IF(TRACE, __FUNCTION__);
 
   std::unique_lock<std::mutex> lock(core_->mutex_);
 
@@ -278,7 +276,7 @@
       return BAD_VALUE;
   }
 
-  ALOGD("query: key=%d, v=%d", what, value);
+  ALOGD_IF(TRACE, "query: key=%d, v=%d", what, value);
   *out_value = value;
   return NO_ERROR;
 }
@@ -288,14 +286,14 @@
     bool /* producer_controlled_by_app */, QueueBufferOutput* /* output */) {
   // Consumer interaction are actually handled by buffer hub, and we need
   // to maintain consumer operations here. Hence |connect| is a NO-OP.
-  ALOGD(__FUNCTION__);
+  ALOGD_IF(TRACE, __FUNCTION__);
   return NO_ERROR;
 }
 
 status_t BufferHubQueueProducer::disconnect(int /* api */, DisconnectMode /* mode */) {
   // Consumer interaction are actually handled by buffer hub, and we need
   // to maintain consumer operations here. Hence |disconnect| is a NO-OP.
-  ALOGD(__FUNCTION__);
+  ALOGD_IF(TRACE, __FUNCTION__);
   return NO_ERROR;
 }
 
@@ -327,7 +325,7 @@
 
 status_t BufferHubQueueProducer::setGenerationNumber(
     uint32_t generation_number) {
-  ALOGD(__FUNCTION__);
+  ALOGD_IF(TRACE, __FUNCTION__);
 
   std::unique_lock<std::mutex> lock(core_->mutex_);
   core_->generation_number_ = generation_number;
@@ -354,7 +352,7 @@
 }
 
 status_t BufferHubQueueProducer::setDequeueTimeout(nsecs_t timeout) {
-  ALOGD(__FUNCTION__);
+  ALOGD_IF(TRACE, __FUNCTION__);
 
   std::unique_lock<std::mutex> lock(core_->mutex_);
   core_->dequeue_timeout_ms_ = static_cast<int>(timeout / (1000 * 1000));
@@ -374,7 +372,7 @@
 }
 
 status_t BufferHubQueueProducer::getUniqueId(uint64_t* out_id) const {
-  ALOGD(__FUNCTION__);
+  ALOGD_IF(TRACE, __FUNCTION__);
 
   *out_id = core_->unique_id_;
   return NO_ERROR;
diff --git a/libs/vr/libdisplay/display_client.cpp b/libs/vr/libdisplay/display_client.cpp
index 54098e8..9952e59 100644
--- a/libs/vr/libdisplay/display_client.cpp
+++ b/libs/vr/libdisplay/display_client.cpp
@@ -148,18 +148,22 @@
   }
 }
 
-std::shared_ptr<BufferProducer> DisplaySurfaceClient::AllocateBuffer(
-    uint32_t* buffer_index) {
-  auto status = InvokeRemoteMethod<DisplayRPC::AllocateBuffer>();
-  if (!status) {
-    ALOGE("DisplaySurfaceClient::AllocateBuffer: Failed to allocate buffer: %s",
+std::shared_ptr<ProducerQueue> DisplaySurfaceClient::GetProducerQueue() {
+  if (producer_queue_ == nullptr) {
+    // Create producer queue through DisplayRPC
+    auto status = InvokeRemoteMethod<DisplayRPC::CreateBufferQueue>();
+    if (!status) {
+      ALOGE(
+          "DisplaySurfaceClient::GetProducerQueue: failed to create producer "
+          "queue: %s",
           status.GetErrorMessage().c_str());
-    return nullptr;
-  }
+      return nullptr;
+    }
 
-  if (buffer_index)
-    *buffer_index = status.get().first;
-  return BufferProducer::Import(status.take().second);
+    producer_queue_ =
+        ProducerQueue::Import<DisplaySurfaceMetadata>(status.take());
+  }
+  return producer_queue_;
 }
 
 volatile DisplaySurfaceMetadata* DisplaySurfaceClient::GetMetadataBufferPtr() {
@@ -244,33 +248,29 @@
   return 0;
 }
 
-int DisplayClient::EnterVrMode() {
-  auto status = InvokeRemoteMethod<DisplayRPC::EnterVrMode>();
-  if (!status) {
-    ALOGE(
-        "DisplayClient::EnterVrMode: Failed to set display service to Vr mode");
-    return -status.error();
-  }
-
-  return 0;
-}
-
-int DisplayClient::ExitVrMode() {
-  auto status = InvokeRemoteMethod<DisplayRPC::ExitVrMode>();
-  if (!status) {
-    ALOGE(
-        "DisplayClient::ExitVrMode: Failed to revert display service from Vr "
-        "mode");
-    return -status.error();
-  }
-
-  return 0;
-}
-
 std::unique_ptr<DisplaySurfaceClient> DisplayClient::CreateDisplaySurface(
     int width, int height, int format, int usage, int flags) {
   return DisplaySurfaceClient::Create(width, height, format, usage, flags);
 }
 
+std::unique_ptr<BufferConsumer> DisplayClient::GetPoseBuffer() {
+  auto status = InvokeRemoteMethod<DisplayRPC::GetPoseBuffer>();
+  if (!status) {
+    ALOGE(
+        "DisplayClient::GetPoseBuffer: Failed to get pose buffer %s",
+        status.GetErrorMessage().c_str());
+    return nullptr;
+  }
+
+  return BufferConsumer::Import(std::move(status));
+}
+
+bool DisplayClient::IsVrAppRunning() {
+  auto status = InvokeRemoteMethod<DisplayRPC::IsVrAppRunning>();
+  if (!status)
+    return 0;
+  return static_cast<bool>(status.get());
+}
+
 }  // namespace dvr
 }  // namespace android
diff --git a/libs/vr/libdisplay/display_manager_client.cpp b/libs/vr/libdisplay/display_manager_client.cpp
index fe18619..d60d35b 100644
--- a/libs/vr/libdisplay/display_manager_client.cpp
+++ b/libs/vr/libdisplay/display_manager_client.cpp
@@ -2,6 +2,7 @@
 
 #include <private/dvr/buffer_hub_client.h>
 #include <private/dvr/display_manager_client_impl.h>
+#include <private/dvr/dvr_buffer.h>
 
 using android::dvr::DisplaySurfaceAttributeEnum;
 
@@ -41,6 +42,18 @@
   delete client;
 }
 
+DvrWriteBuffer* dvrDisplayManagerSetupPoseBuffer(
+    DvrDisplayManagerClient* client, size_t extended_region_size,
+    uint64_t usage0, uint64_t usage1) {
+  // TODO(hendrikw): When we move to gralloc1, pass both usage0 and usage1 down.
+  auto buffer_producer = client->client->SetupPoseBuffer(
+      extended_region_size, static_cast<int>(usage0));
+  if (buffer_producer) {
+    return CreateDvrWriteBufferFromBufferProducer(std::move(buffer_producer));
+  }
+  return nullptr;
+}
+
 int dvrDisplayManagerClientGetEventFd(DvrDisplayManagerClient* client) {
   return client->client->event_fd();
 }
diff --git a/libs/vr/libdisplay/display_manager_client_impl.cpp b/libs/vr/libdisplay/display_manager_client_impl.cpp
index 3fbd1e0..7993fce 100644
--- a/libs/vr/libdisplay/display_manager_client_impl.cpp
+++ b/libs/vr/libdisplay/display_manager_client_impl.cpp
@@ -31,5 +31,20 @@
   return 0;
 }
 
+std::unique_ptr<BufferProducer> DisplayManagerClient::SetupPoseBuffer(
+    size_t extended_region_size, int usage) {
+  auto status = InvokeRemoteMethod<DisplayManagerRPC::SetupPoseBuffer>(
+      extended_region_size, usage);
+  if (!status) {
+    ALOGE(
+        "DisplayManagerClient::SetupPoseBuffer: Failed to create the pose "
+        "buffer %s",
+        status.GetErrorMessage().c_str());
+    return {};
+  }
+
+  return BufferProducer::Import(std::move(status));
+}
+
 }  // namespace dvr
 }  // namespace android
diff --git a/libs/vr/libdisplay/graphics.cpp b/libs/vr/libdisplay/graphics.cpp
index 61f6fea..3713389 100644
--- a/libs/vr/libdisplay/graphics.cpp
+++ b/libs/vr/libdisplay/graphics.cpp
@@ -17,6 +17,7 @@
 #include <private/dvr/clock_ns.h>
 #include <private/dvr/debug.h>
 #include <private/dvr/display_types.h>
+#include <private/dvr/dvr_buffer.h>
 #include <private/dvr/frame_history.h>
 #include <private/dvr/gl_fenced_flush.h>
 #include <private/dvr/graphics/vr_gl_extensions.h>
@@ -26,6 +27,7 @@
 #include <private/dvr/sensor_constants.h>
 #include <private/dvr/video_mesh_surface_client.h>
 #include <private/dvr/vsync_client.h>
+#include <private/dvr/platform_defines.h>
 
 #include <android/native_window.h>
 
@@ -42,8 +44,10 @@
 
 namespace {
 
+// TODO(urbanus): revisit once we have per-platform usage config in place.
 constexpr int kDefaultDisplaySurfaceUsage =
-    GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
+    GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE |
+    GRALLOC_USAGE_QCOM_FRAMEBUFFER_COMPRESSION;
 constexpr int kDefaultDisplaySurfaceFormat = HAL_PIXEL_FORMAT_RGBA_8888;
 // TODO(alexst): revisit this count when HW encode is available for casting.
 constexpr int kDefaultBufferCount = 4;
@@ -1571,3 +1575,14 @@
     };
   }
 }
+
+extern "C" int dvrGetPoseBuffer(DvrReadBuffer** pose_buffer) {
+  auto client = android::dvr::DisplayClient::Create();
+  if (!client) {
+    ALOGE("Failed to create display client!");
+    return -ECOMM;
+  }
+
+  *pose_buffer = CreateDvrReadBufferFromBufferConsumer(client->GetPoseBuffer());
+  return 0;
+}
diff --git a/libs/vr/libdisplay/include/dvr/graphics.h b/libs/vr/libdisplay/include/dvr/graphics.h
index 19deec3..fc51d52 100644
--- a/libs/vr/libdisplay/include/dvr/graphics.h
+++ b/libs/vr/libdisplay/include/dvr/graphics.h
@@ -160,6 +160,8 @@
 
 int dvrGetNativeDisplayDimensions(int* native_width, int* native_height);
 
+typedef struct DvrReadBuffer DvrReadBuffer;
+
 // Opaque struct that represents a graphics context, the texture swap chain,
 // and surfaces.
 typedef struct DvrGraphicsContext DvrGraphicsContext;
@@ -440,6 +442,9 @@
                                         const int eye,
                                         const float* transform);
 
+// Get a pointer to the global pose buffer.
+int dvrGetPoseBuffer(DvrReadBuffer** pose_buffer);
+
 __END_DECLS
 
 #endif  // DVR_GRAPHICS_H_
diff --git a/libs/vr/libdisplay/include/private/dvr/display_client.h b/libs/vr/libdisplay/include/private/dvr/display_client.h
index 034b7b4..378f67c 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_client.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_client.h
@@ -5,6 +5,7 @@
 #include <pdx/client.h>
 #include <pdx/file_handle.h>
 #include <private/dvr/buffer_hub_client.h>
+#include <private/dvr/buffer_hub_queue_client.h>
 #include <private/dvr/display_rpc.h>
 
 namespace android {
@@ -62,13 +63,9 @@
   void SetBlurBehind(bool blur_behind);
   void SetAttributes(const DisplaySurfaceAttributes& attributes);
 
-  // |out_buffer_index| will receive a unique index for this buffer within the
-  // surface. The first buffer gets 0, second gets 1, and so on. This index
-  // can be used to deliver metadata for buffers that are queued for display.
-  std::shared_ptr<BufferProducer> AllocateBuffer(uint32_t* out_buffer_index);
-  std::shared_ptr<BufferProducer> AllocateBuffer() {
-    return AllocateBuffer(nullptr);
-  }
+  // Get the producer end of the buffer queue that transports graphics buffer
+  // from the application side to the compositor side.
+  std::shared_ptr<ProducerQueue> GetProducerQueue();
 
   // Get the shared memory metadata buffer for this display surface. If it is
   // not yet allocated, this will allocate it.
@@ -93,6 +90,9 @@
   bool blur_behind_;
   DisplaySurfaceMetadata* mapped_metadata_buffer_;
 
+  // TODO(jwcai) Add support for multiple queues.
+  std::shared_ptr<ProducerQueue> producer_queue_;
+
   DisplaySurfaceClient(const DisplaySurfaceClient&) = delete;
   void operator=(const DisplaySurfaceClient&) = delete;
 };
@@ -105,12 +105,14 @@
   // Pull the latest eds pose data from the display service renderer
   int GetLastFrameEdsTransform(LateLatchOutput* ll_out);
 
-  int EnterVrMode();
-  int ExitVrMode();
-
   std::unique_ptr<DisplaySurfaceClient> CreateDisplaySurface(
       int width, int height, int format, int usage, int flags);
 
+  std::unique_ptr<BufferConsumer> GetPoseBuffer();
+
+  // Temporary query for current VR status. Will be removed later.
+  bool IsVrAppRunning();
+
  private:
   friend BASE;
 
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 f515b8f..0928d43 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_manager_client.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_manager_client.h
@@ -14,11 +14,16 @@
     DvrDisplayManagerClientSurfaceList;
 typedef struct DvrDisplayManagerClientSurfaceBuffers
     DvrDisplayManagerClientSurfaceBuffers;
+typedef struct DvrWriteBuffer DvrWriteBuffer;
 
 DvrDisplayManagerClient* dvrDisplayManagerClientCreate();
 
 void dvrDisplayManagerClientDestroy(DvrDisplayManagerClient* client);
 
+DvrWriteBuffer* dvrDisplayManagerSetupPoseBuffer(
+    DvrDisplayManagerClient* client, size_t extended_region_size,
+    uint64_t usage0, uint64_t usage1);
+
 // Return an event fd for checking if there was an event on the server
 // Note that the only event which will be flagged is POLLIN. You must use
 // dvrDisplayManagerClientTranslateEpollEventMask in order to get the real
diff --git a/libs/vr/libdisplay/include/private/dvr/display_manager_client_impl.h b/libs/vr/libdisplay/include/private/dvr/display_manager_client_impl.h
index 0897126..144cd3b 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_manager_client_impl.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_manager_client_impl.h
@@ -9,7 +9,7 @@
 namespace android {
 namespace dvr {
 
-class BufferConsumer;
+class BufferProducer;
 
 class DisplayManagerClient : public pdx::ClientBase<DisplayManagerClient> {
  public:
@@ -17,6 +17,9 @@
 
   int GetSurfaceList(std::vector<DisplaySurfaceInfo>* surface_list);
 
+  std::unique_ptr<BufferProducer> SetupPoseBuffer(size_t extended_region_size,
+                                                  int usage);
+
   using Client::event_fd;
   using Client::GetChannel;
 
diff --git a/libs/vr/libdisplay/include/private/dvr/display_rpc.h b/libs/vr/libdisplay/include/private/dvr/display_rpc.h
index d37aed7..ac08650 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_rpc.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_rpc.h
@@ -212,14 +212,14 @@
     kOpGetMetrics = 0,
     kOpGetEdsCapture,
     kOpCreateSurface,
-    kOpAllocateBuffer,
+    kOpCreateBufferQueue,
     kOpSetAttributes,
     kOpGetMetadataBuffer,
     kOpCreateVideoMeshSurface,
     kOpVideoMeshSurfaceCreateProducerQueue,
-    kOpEnterVrMode,
-    kOpExitVrMode,
-    kOpSetViewerParams
+    kOpSetViewerParams,
+    kOpGetPoseBuffer,
+    kOpIsVrAppRunning,
   };
 
   // Aliases.
@@ -233,8 +233,8 @@
   PDX_REMOTE_METHOD(CreateSurface, kOpCreateSurface,
                     int(int width, int height, int format, int usage,
                         DisplaySurfaceFlags flags));
-  PDX_REMOTE_METHOD(AllocateBuffer, kOpAllocateBuffer,
-                    std::pair<std::uint32_t, LocalChannelHandle>(Void));
+  PDX_REMOTE_METHOD(CreateBufferQueue, kOpCreateBufferQueue,
+                    LocalChannelHandle(Void));
   PDX_REMOTE_METHOD(SetAttributes, kOpSetAttributes,
                     int(const DisplaySurfaceAttributes& attributes));
   PDX_REMOTE_METHOD(GetMetadataBuffer, kOpGetMetadataBuffer,
@@ -245,10 +245,11 @@
   PDX_REMOTE_METHOD(VideoMeshSurfaceCreateProducerQueue,
                     kOpVideoMeshSurfaceCreateProducerQueue,
                     LocalChannelHandle(Void));
-  PDX_REMOTE_METHOD(EnterVrMode, kOpEnterVrMode, int(Void));
-  PDX_REMOTE_METHOD(ExitVrMode, kOpExitVrMode, int(Void));
   PDX_REMOTE_METHOD(SetViewerParams, kOpSetViewerParams,
                     void(const ViewerParams& viewer_params));
+  PDX_REMOTE_METHOD(GetPoseBuffer, kOpGetPoseBuffer,
+                    LocalChannelHandle(Void));
+  PDX_REMOTE_METHOD(IsVrAppRunning, kOpIsVrAppRunning, int(Void));
 };
 
 struct DisplayManagerRPC {
@@ -259,6 +260,7 @@
   enum {
     kOpGetSurfaceList = 0,
     kOpUpdateSurfaces,
+    kOpSetupPoseBuffer,
   };
 
   // Aliases.
@@ -271,6 +273,8 @@
   PDX_REMOTE_METHOD(
       UpdateSurfaces, kOpUpdateSurfaces,
       int(const std::map<int, DisplaySurfaceAttributes>& updates));
+  PDX_REMOTE_METHOD(SetupPoseBuffer, kOpSetupPoseBuffer,
+                    LocalChannelHandle(size_t extended_region_size, int usage));
 };
 
 struct ScreenshotData {
diff --git a/libs/vr/libdisplay/include/private/dvr/native_buffer_queue.h b/libs/vr/libdisplay/include/private/dvr/native_buffer_queue.h
index 87e9c9f..4b1fa98 100644
--- a/libs/vr/libdisplay/include/private/dvr/native_buffer_queue.h
+++ b/libs/vr/libdisplay/include/private/dvr/native_buffer_queue.h
@@ -14,57 +14,27 @@
 namespace android {
 namespace dvr {
 
-// NativeBufferQueue manages a queue of NativeBufferProducers allocated from a
-// DisplaySurfaceClient. Buffers are automatically re-enqueued when released by
-// the consumer side.
+// A wrapper over dvr::ProducerQueue that caches EGLImage.
 class NativeBufferQueue {
  public:
   // Create a queue with the given number of free buffers.
-  NativeBufferQueue(const std::shared_ptr<DisplaySurfaceClient>& surface,
-                    size_t capacity);
   NativeBufferQueue(EGLDisplay display,
                     const std::shared_ptr<DisplaySurfaceClient>& surface,
                     size_t capacity);
-  ~NativeBufferQueue();
 
-  std::shared_ptr<DisplaySurfaceClient> surface() const { return surface_; }
+  size_t GetQueueCapacity() const { return producer_queue_->capacity(); }
 
   // Dequeue a buffer from the free queue, blocking until one is available.
   NativeBufferProducer* Dequeue();
 
-  // Enqueue a buffer at the end of the free queue.
-  void Enqueue(NativeBufferProducer* buf);
-
-  // Get the number of free buffers in the queue.
-  size_t GetFreeBufferCount() const;
-
-  // Get the total number of buffers managed by this queue.
-  size_t GetQueueCapacity() const;
-
-  // Accessors for display surface buffer attributes.
-  int width() const { return surface_->width(); }
-  int height() const { return surface_->height(); }
-  int format() const { return surface_->format(); }
-  int usage() const { return surface_->usage(); }
+  // An noop here to keep Vulkan path in GraphicsContext happy.
+  // TODO(jwcai, cort) Move Vulkan path into GVR/Google3.
+  void Enqueue(NativeBufferProducer* buffer) {}
 
  private:
-  // Wait for buffers to be released and enqueue them.
-  bool WaitForBuffers();
-
-  std::shared_ptr<DisplaySurfaceClient> surface_;
-
-  // A list of strong pointers to the buffers, used for managing buffer
-  // lifetime.
-  std::vector<android::sp<NativeBufferProducer>> buffers_;
-
-  // Used to implement queue semantics.
-  RingBuffer<NativeBufferProducer*> buffer_queue_;
-
-  // Epoll fd used to wait for BufferHub events.
-  int epoll_fd_;
-
-  NativeBufferQueue(const NativeBufferQueue&) = delete;
-  void operator=(NativeBufferQueue&) = delete;
+  EGLDisplay display_;
+  std::shared_ptr<ProducerQueue> producer_queue_;
+  std::vector<sp<NativeBufferProducer>> buffers_;
 };
 
 }  // namespace dvr
diff --git a/libs/vr/libdisplay/include/private/dvr/video_mesh_surface_client.h b/libs/vr/libdisplay/include/private/dvr/video_mesh_surface_client.h
index e52d0b9..3a7f125 100644
--- a/libs/vr/libdisplay/include/private/dvr/video_mesh_surface_client.h
+++ b/libs/vr/libdisplay/include/private/dvr/video_mesh_surface_client.h
@@ -25,7 +25,7 @@
  private:
   friend BASE;
 
-  std::shared_ptr<android::dvr::ProducerQueue> producer_queue_;
+  std::shared_ptr<ProducerQueue> producer_queue_;
   VideoMeshSurfaceMetadata* mapped_metadata_buffer_;
 
   explicit VideoMeshSurfaceClient(LocalChannelHandle handle);
diff --git a/libs/vr/libdisplay/native_buffer_queue.cpp b/libs/vr/libdisplay/native_buffer_queue.cpp
index 8dd0ee0..d516d63 100644
--- a/libs/vr/libdisplay/native_buffer_queue.cpp
+++ b/libs/vr/libdisplay/native_buffer_queue.cpp
@@ -13,138 +13,51 @@
 namespace dvr {
 
 NativeBufferQueue::NativeBufferQueue(
-    const std::shared_ptr<DisplaySurfaceClient>& surface, size_t capacity)
-    : NativeBufferQueue(nullptr, surface, capacity) {}
-
-NativeBufferQueue::NativeBufferQueue(
     EGLDisplay display, const std::shared_ptr<DisplaySurfaceClient>& surface,
     size_t capacity)
-    : surface_(surface),
-      buffers_(capacity),
-      buffer_queue_(capacity) {
-  LOG_ALWAYS_FATAL_IF(!surface);
-
-  epoll_fd_ = epoll_create(64);
-  if (epoll_fd_ < 0) {
-    ALOGE("NativeBufferQueue::NativeBufferQueue: Failed to create epoll fd: %s",
-          strerror(errno));
-    return;
-  }
-
-  // The kSurfaceBufferMaxCount must be >= the capacity so that shader code
-  // can bind surface buffer array data.
-  LOG_ALWAYS_FATAL_IF(kSurfaceBufferMaxCount < capacity);
+    : display_(display), buffers_(capacity) {
+  std::shared_ptr<ProducerQueue> queue = surface->GetProducerQueue();
 
   for (size_t i = 0; i < capacity; i++) {
-    uint32_t buffer_index = 0;
-    auto buffer = surface_->AllocateBuffer(&buffer_index);
-    if (!buffer) {
-      ALOGE("NativeBufferQueue::NativeBufferQueue: Failed to allocate buffer!");
-      return;
-    }
-
-    // TODO(jbates): store an index associated with each buffer so that we can
-    // determine which index in DisplaySurfaceMetadata it is associated
-    // with.
-    buffers_.push_back(new NativeBufferProducer(buffer, display, buffer_index));
-    NativeBufferProducer* native_buffer = buffers_.back().get();
-
-    epoll_event event = {.events = EPOLLIN | EPOLLET,
-                         .data = {.ptr = native_buffer}};
-    if (epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, buffer->event_fd(), &event) <
-        0) {
+    size_t slot;
+    // TODO(jwcai) Should change to use BufferViewPort's spec to config.
+    int ret =
+        queue->AllocateBuffer(surface->width(), surface->height(),
+                              surface->format(), surface->usage(), 1, &slot);
+    if (ret < 0) {
       ALOGE(
-          "NativeBufferQueue::NativeBufferQueue: Failed to add buffer producer "
-          "to epoll set: %s",
-          strerror(errno));
+          "NativeBufferQueue::NativeBufferQueue: Failed to allocate buffer, "
+          "error=%d",
+          ret);
       return;
     }
 
-    Enqueue(native_buffer);
-  }
-}
-
-NativeBufferQueue::~NativeBufferQueue() {
-  if (epoll_fd_ >= 0)
-    close(epoll_fd_);
-}
-
-bool NativeBufferQueue::WaitForBuffers() {
-  ATRACE_NAME("NativeBufferQueue::WaitForBuffers");
-  // Intentionally set this to one so that we don't waste time retrieving too
-  // many buffers.
-  constexpr size_t kMaxEvents = 1;
-  std::array<epoll_event, kMaxEvents> events;
-
-  while (buffer_queue_.IsEmpty()) {
-    int num_events = epoll_wait(epoll_fd_, events.data(), events.size(), -1);
-    if (num_events < 0 && errno != EINTR) {
-      ALOGE("NativeBufferQueue:WaitForBuffers: Failed to wait for buffers: %s",
-            strerror(errno));
-      return false;
-    }
-
-    ALOGD_IF(TRACE, "NativeBufferQueue::WaitForBuffers: num_events=%d",
-             num_events);
-
-    for (int i = 0; i < num_events; i++) {
-      NativeBufferProducer* buffer =
-          static_cast<NativeBufferProducer*>(events[i].data.ptr);
-      ALOGD_IF(TRACE,
-               "NativeBufferQueue::WaitForBuffers: event %d: buffer_id=%d "
-               "events=0x%x",
-               i, buffer->buffer()->id(), events[i].events);
-
-      if (events[i].events & EPOLLIN) {
-        const int ret = buffer->GainAsync();
-        if (ret < 0) {
-          ALOGE("NativeBufferQueue::WaitForBuffers: Failed to gain buffer: %s",
-                strerror(-ret));
-          continue;
-        }
-
-        Enqueue(buffer);
-      }
-    }
+    ALOGD_IF(TRACE,
+             "NativeBufferQueue::NativeBufferQueue: New buffer allocated at "
+             "slot=%zu",
+             slot);
   }
 
-  return true;
-}
-
-void NativeBufferQueue::Enqueue(NativeBufferProducer* buf) {
-  ATRACE_NAME("NativeBufferQueue::Enqueue");
-  if (buffer_queue_.IsFull()) {
-    ALOGE("NativeBufferQueue::Enqueue: Queue is full!");
-    return;
-  }
-
-  buffer_queue_.Append(buf);
+  producer_queue_ = std::move(queue);
 }
 
 NativeBufferProducer* NativeBufferQueue::Dequeue() {
   ATRACE_NAME("NativeBufferQueue::Dequeue");
-  ALOGD_IF(TRACE, "NativeBufferQueue::Dequeue: count=%zd",
-           buffer_queue_.GetSize());
 
-  if (buffer_queue_.IsEmpty() && !WaitForBuffers())
-    return nullptr;
+  // This never times out.
+  size_t slot;
+  pdx::LocalHandle fence;
+  std::shared_ptr<BufferProducer> buffer =
+      producer_queue_->Dequeue(-1, &slot, &fence);
 
-  NativeBufferProducer* buf = buffer_queue_.Front();
-  buffer_queue_.PopFront();
-  if (buf == nullptr) {
-    ALOGE("NativeBufferQueue::Dequeue: Buffer at tail was nullptr!!!");
-    return nullptr;
+  if (buffers_[slot] == nullptr) {
+    buffers_[slot] = new NativeBufferProducer(buffer, display_, slot);
   }
 
-  return buf;
-}
-
-size_t NativeBufferQueue::GetFreeBufferCount() const {
-  return buffer_queue_.GetSize();
-}
-
-size_t NativeBufferQueue::GetQueueCapacity() const {
-  return buffer_queue_.GetCapacity();
+  ALOGD_IF(TRACE,
+           "NativeBufferQueue::Dequeue: dequeue buffer at slot=%zu, buffer=%p",
+           slot, buffers_[slot].get());
+  return buffers_[slot].get();
 }
 
 }  // namespace dvr
diff --git a/libs/vr/libdvrcommon/include/private/dvr/platform_defines.h b/libs/vr/libdvrcommon/include/private/dvr/platform_defines.h
index 71d4c8c..2176903 100644
--- a/libs/vr/libdvrcommon/include/private/dvr/platform_defines.h
+++ b/libs/vr/libdvrcommon/include/private/dvr/platform_defines.h
@@ -1,10 +1,11 @@
 #ifndef ANDROID_DVR_PLATFORM_DEFINES_H_
 #define ANDROID_DVR_PLATFORM_DEFINES_H_
 
+#include <hardware/gralloc1.h>
 // Platform-specific macros and defines.
 
-// QCOM's GRALLOC_USAGE_PRIVATE_ALLOC_UBWC usage bit.
-#define GRALLOC_USAGE_QCOM_FRAMEBUFFER_COMPRESSION GRALLOC_USAGE_PRIVATE_1
+// QCOM's GRALLOC_USAGE_PRIVATE_ALLOC_UBWC usage bits.
+#define GRALLOC_USAGE_QCOM_FRAMEBUFFER_COMPRESSION GRALLOC_USAGE_PRIVATE_1 | GRALLOC1_PRODUCER_USAGE_PRIVATE_0
 
 // QCOM bit to use the ADSP heap. This carveout heap is accessible to Linux,
 // Hexagon DSPs, and the GPU.
diff --git a/libs/vr/libeds/Android.bp b/libs/vr/libeds/Android.bp
index a9df847..187cbbf 100644
--- a/libs/vr/libeds/Android.bp
+++ b/libs/vr/libeds/Android.bp
@@ -36,6 +36,8 @@
     "libEGL",
     "libGLESv1_CM",
     "libGLESv2",
+    "libui",
+    "libutils",
     "libvulkan",
 ]
 
@@ -79,7 +81,8 @@
         "libgmock",
         "libeds",
     ] + staticLibraries + [
-        "libbufferhub"
+        "libbufferhub",
+        "libbufferhubqueue",
     ],
 
 }
diff --git a/libs/vr/libpdx/private/pdx/rpc/function_traits.h b/libs/vr/libpdx/private/pdx/rpc/function_traits.h
index 5fdad72..7641b0a 100644
--- a/libs/vr/libpdx/private/pdx/rpc/function_traits.h
+++ b/libs/vr/libpdx/private/pdx/rpc/function_traits.h
@@ -43,6 +43,12 @@
       SignatureType<ConditionalRewrite<Return_, ReturnType>(
           ConditionalRewrite<Args_, Params>...)>;
 
+  template <template <typename> class Wrapper, typename ReturnType,
+            typename... Params>
+  using RewriteSignatureWrapReturn =
+      SignatureType<Wrapper<ConditionalRewrite<Return_, ReturnType>>(
+          ConditionalRewrite<Args_, Params>...)>;
+
   template <typename ReturnType>
   using RewriteReturn =
       SignatureType<ConditionalRewrite<Return_, ReturnType>(Args_...)>;
diff --git a/libs/vr/libpdx/private/pdx/rpc/remote_method.h b/libs/vr/libpdx/private/pdx/rpc/remote_method.h
index 679503c..3eca9e5 100644
--- a/libs/vr/libpdx/private/pdx/rpc/remote_method.h
+++ b/libs/vr/libpdx/private/pdx/rpc/remote_method.h
@@ -10,6 +10,7 @@
 #include <pdx/rpc/payload.h>
 #include <pdx/rpc/remote_method_type.h>
 #include <pdx/service.h>
+#include <pdx/status.h>
 
 namespace android {
 namespace pdx {
@@ -157,6 +158,25 @@
            strerror(-ret));
 }
 
+// Overload for Status<void> return types.
+template <typename RemoteMethodType>
+void RemoteMethodReturn(Message& message, const Status<void>& return_value) {
+  if (return_value)
+    RemoteMethodReturn<RemoteMethodType>(message, 0);
+  else
+    RemoteMethodError(message, return_value.error());
+}
+
+// Overload for Status<T> return types. This overload forwards the underlying
+// value or error within the Status<T>.
+template <typename RemoteMethodType, typename Return>
+void RemoteMethodReturn(Message& message, const Status<Return>& return_value) {
+  if (return_value)
+    RemoteMethodReturn<RemoteMethodType, Return>(message, return_value.get());
+  else
+    RemoteMethodError(message, return_value.error());
+}
+
 // Dispatches a method by deserializing arguments from the given Message, with
 // compile-time interface check. Overload for void return types.
 template <typename RemoteMethodType, typename Class, typename... Args,
@@ -193,117 +213,6 @@
 }
 
 // Dispatches a method by deserializing arguments from the given Message, with
-// compile-time interface check. Overload for int return types.
-template <typename RemoteMethodType, typename Class, typename... Args,
-          typename = EnableIfNotVoidMethod<RemoteMethodType>>
-void DispatchRemoteMethod(Class& instance,
-                          int (Class::*method)(Message&, Args...),
-                          Message& message,
-                          std::size_t max_capacity = InitialBufferCapacity) {
-  using Signature = typename RemoteMethodType::template RewriteArgs<Args...>;
-  rpc::ServicePayload<ReceiveBuffer> payload(message);
-  payload.Resize(max_capacity);
-
-  auto size = message.Read(payload.Data(), payload.Size());
-  if (size < 0) {
-    RemoteMethodError(message, -size);
-    return;
-  }
-
-  payload.Resize(size);
-
-  ErrorType error;
-  auto decoder = MakeArgumentDecoder<Signature>(&payload);
-  auto arguments = decoder.DecodeArguments(&error);
-  if (error) {
-    RemoteMethodError(message, EIO);
-    return;
-  }
-
-  auto return_value =
-      UnpackArguments<Class, Signature>(instance, method, message, arguments)
-          .Invoke();
-  // Return the value to the caller unless the message was moved.
-  if (message)
-    RemoteMethodReturn<RemoteMethodType>(message, return_value);
-}
-
-// Dispatches a method by deserializing arguments from the given Message, with
-// compile-time interface check. Overload for FileHandle return types.
-template <typename RemoteMethodType, FileHandleMode Mode, typename Class,
-          typename... Args, typename = EnableIfNotVoidMethod<RemoteMethodType>>
-void DispatchRemoteMethod(Class& instance,
-                          FileHandle<Mode> (Class::*method)(Message&, Args...),
-                          Message& message,
-                          std::size_t max_capacity = InitialBufferCapacity) {
-  using Signature =
-      typename RemoteMethodType::template RewriteSignature<FileHandle<Mode>,
-                                                           Args...>;
-  rpc::ServicePayload<ReceiveBuffer> payload(message);
-  payload.Resize(max_capacity);
-
-  auto size = message.Read(payload.Data(), payload.Size());
-  if (size < 0) {
-    RemoteMethodError(message, -size);
-    return;
-  }
-
-  payload.Resize(size);
-
-  ErrorType error;
-  auto decoder = MakeArgumentDecoder<Signature>(&payload);
-  auto arguments = decoder.DecodeArguments(&error);
-  if (error) {
-    RemoteMethodError(message, EIO);
-    return;
-  }
-
-  auto return_value =
-      UnpackArguments<Class, Signature>(instance, method, message, arguments)
-          .Invoke();
-  // Return the value to the caller unless the message was moved.
-  if (message)
-    RemoteMethodReturn<RemoteMethodType>(message, return_value);
-}
-
-// Dispatches a method by deserializing arguments from the given Message, with
-// compile-time interface check. Overload for ChannelHandle return types.
-template <typename RemoteMethodType, ChannelHandleMode Mode, typename Class,
-          typename... Args, typename = EnableIfNotVoidMethod<RemoteMethodType>>
-void DispatchRemoteMethod(
-    Class& instance, ChannelHandle<Mode> (Class::*method)(Message&, Args...),
-    Message& message, std::size_t max_capacity = InitialBufferCapacity) {
-  using Signature =
-      typename RemoteMethodType::template RewriteSignature<ChannelHandle<Mode>,
-                                                           Args...>;
-  rpc::ServicePayload<ReceiveBuffer> payload(message);
-  payload.Resize(max_capacity);
-
-  auto size = message.Read(payload.Data(), payload.Size());
-  if (size < 0) {
-    RemoteMethodError(message, -size);
-    return;
-  }
-
-  payload.Resize(size);
-
-  ErrorType error;
-  auto decoder = MakeArgumentDecoder<Signature>(&payload);
-  auto arguments = decoder.DecodeArguments(&error);
-  if (error) {
-    RemoteMethodError(message, EIO);
-    return;
-  }
-
-  auto return_value =
-      UnpackArguments<Class, Signature>(instance, method, message, arguments)
-          .Invoke();
-  // Return the value to the caller unless the message was moved.
-  if (message)
-    RemoteMethodReturn<RemoteMethodType>(message, return_value);
-}
-
-// Dispatches a method by deserializing arguments from the given Message, with
 // compile-time interface signature check. Overload for generic return types.
 template <typename RemoteMethodType, typename Class, typename Return,
           typename... Args, typename = EnableIfNotVoidMethod<RemoteMethodType>>
@@ -340,6 +249,46 @@
     RemoteMethodReturn<RemoteMethodType>(message, return_value);
 }
 
+// Dispatches a method by deserializing arguments from the given Message, with
+// compile-time interface signature check. Overload for Status<T> return types.
+template <typename RemoteMethodType, typename Class, typename Return,
+          typename... Args, typename = EnableIfNotVoidMethod<RemoteMethodType>>
+void DispatchRemoteMethod(Class& instance,
+                          Status<Return> (Class::*method)(Message&, Args...),
+                          Message& message,
+                          std::size_t max_capacity = InitialBufferCapacity) {
+  using Signature =
+      typename RemoteMethodType::template RewriteSignature<Return, Args...>;
+  using InvokeSignature =
+      typename RemoteMethodType::template RewriteSignatureWrapReturn<
+          Status, Return, Args...>;
+  rpc::ServicePayload<ReceiveBuffer> payload(message);
+  payload.Resize(max_capacity);
+
+  auto size = message.Read(payload.Data(), payload.Size());
+  if (size < 0) {
+    RemoteMethodError(message, -size);
+    return;
+  }
+
+  payload.Resize(size);
+
+  ErrorType error;
+  auto decoder = MakeArgumentDecoder<Signature>(&payload);
+  auto arguments = decoder.DecodeArguments(&error);
+  if (error) {
+    RemoteMethodError(message, EIO);
+    return;
+  }
+
+  auto return_value = UnpackArguments<Class, InvokeSignature>(
+                          instance, method, message, arguments)
+                          .Invoke();
+  // Return the value to the caller unless the message was moved.
+  if (message)
+    RemoteMethodReturn<RemoteMethodType>(message, return_value);
+}
+
 #ifdef __clang__
 // Overloads to handle Void argument type without exploding clang.
 
@@ -354,41 +303,6 @@
     RemoteMethodReturn<RemoteMethodType>(message, 0);
 }
 
-// Overload for int return type.
-template <typename RemoteMethodType, typename Class,
-          typename = EnableIfVoidMethod<RemoteMethodType>>
-void DispatchRemoteMethod(Class& instance, int (Class::*method)(Message&),
-                          Message& message) {
-  const int return_value = (instance.*method)(message);
-  // Return the value to the caller unless the message was moved.
-  if (message)
-    RemoteMethodReturn<RemoteMethodType>(message, return_value);
-}
-
-// Overload for FileHandle return type.
-template <typename RemoteMethodType, typename Class, FileHandleMode Mode,
-          typename = EnableIfVoidMethod<RemoteMethodType>>
-void DispatchRemoteMethod(Class& instance,
-                          FileHandle<Mode> (Class::*method)(Message&),
-                          Message& message) {
-  FileHandle<Mode> return_value = (instance.*method)(message);
-  // Return the value to the caller unless the message was moved.
-  if (message)
-    RemoteMethodReturn<RemoteMethodType>(message, return_value);
-}
-
-// Overload for ChannelHandle return types.
-template <typename RemoteMethodType, typename Class, ChannelHandleMode Mode,
-          typename = EnableIfVoidMethod<RemoteMethodType>>
-void DispatchRemoteMethod(Class& instance,
-                          ChannelHandle<Mode> (Class::*method)(Message&),
-                          Message& message) {
-  ChannelHandle<Mode> return_value = (instance.*method)(message);
-  // Return the value to the caller unless the message was moved.
-  if (message)
-    RemoteMethodReturn<RemoteMethodType>(message, return_value);
-}
-
 // Overload for generic return type.
 template <typename RemoteMethodType, typename Class, typename Return,
           typename = EnableIfVoidMethod<RemoteMethodType>>
@@ -399,6 +313,18 @@
   if (message)
     RemoteMethodReturn<RemoteMethodType>(message, return_value);
 }
+
+// Overload for Status<T> return type.
+template <typename RemoteMethodType, typename Class, typename Return,
+          typename = EnableIfVoidMethod<RemoteMethodType>>
+void DispatchRemoteMethod(Class& instance,
+                          Status<Return> (Class::*method)(Message&),
+                          Message& message) {
+  auto return_value = (instance.*method)(message);
+  // Return the value to the caller unless the message was moved.
+  if (message)
+    RemoteMethodReturn<RemoteMethodType>(message, return_value);
+}
 #endif
 
 }  // namespace rpc
diff --git a/libs/vr/libpdx/private/pdx/rpc/remote_method_type.h b/libs/vr/libpdx/private/pdx/rpc/remote_method_type.h
index de9a3cc..cf9a189 100644
--- a/libs/vr/libpdx/private/pdx/rpc/remote_method_type.h
+++ b/libs/vr/libpdx/private/pdx/rpc/remote_method_type.h
@@ -31,6 +31,12 @@
   using RewriteSignature =
       typename Traits::template RewriteSignature<ReturnType, Params...>;
 
+  template <template <typename> class Wrapper, typename ReturnType,
+            typename... Params>
+  using RewriteSignatureWrapReturn =
+      typename Traits::template RewriteSignatureWrapReturn<Wrapper, ReturnType,
+                                                           Params...>;
+
   template <typename ReturnType>
   using RewriteReturn = typename Traits::template RewriteReturn<ReturnType>;
 };
diff --git a/libs/vr/libpdx/service.cpp b/libs/vr/libpdx/service.cpp
index daf9af8..d2804d5 100644
--- a/libs/vr/libpdx/service.cpp
+++ b/libs/vr/libpdx/service.cpp
@@ -129,7 +129,7 @@
   PDX_TRACE_NAME("Message::PushFileHandle");
   if (auto svc = service_.lock()) {
     ErrnoGuard errno_guard;
-    return ReturnCodeOrError(svc->endpoint()->PushFileHandle(this, handle));
+    return svc->endpoint()->PushFileHandle(this, handle);
   } else {
     return -ESHUTDOWN;
   }
@@ -139,7 +139,7 @@
   PDX_TRACE_NAME("Message::PushFileHandle");
   if (auto svc = service_.lock()) {
     ErrnoGuard errno_guard;
-    return ReturnCodeOrError(svc->endpoint()->PushFileHandle(this, handle));
+    return svc->endpoint()->PushFileHandle(this, handle);
   } else {
     return -ESHUTDOWN;
   }
@@ -149,7 +149,7 @@
   PDX_TRACE_NAME("Message::PushFileHandle");
   if (auto svc = service_.lock()) {
     ErrnoGuard errno_guard;
-    return ReturnCodeOrError(svc->endpoint()->PushFileHandle(this, handle));
+    return svc->endpoint()->PushFileHandle(this, handle);
   } else {
     return -ESHUTDOWN;
   }
@@ -159,7 +159,7 @@
   PDX_TRACE_NAME("Message::PushChannelHandle");
   if (auto svc = service_.lock()) {
     ErrnoGuard errno_guard;
-    return ReturnCodeOrError(svc->endpoint()->PushChannelHandle(this, handle));
+    return svc->endpoint()->PushChannelHandle(this, handle);
   } else {
     return -ESHUTDOWN;
   }
@@ -170,7 +170,7 @@
   PDX_TRACE_NAME("Message::PushChannelHandle");
   if (auto svc = service_.lock()) {
     ErrnoGuard errno_guard;
-    return ReturnCodeOrError(svc->endpoint()->PushChannelHandle(this, handle));
+    return svc->endpoint()->PushChannelHandle(this, handle);
   } else {
     return -ESHUTDOWN;
   }
@@ -180,7 +180,7 @@
   PDX_TRACE_NAME("Message::PushChannelHandle");
   if (auto svc = service_.lock()) {
     ErrnoGuard errno_guard;
-    return ReturnCodeOrError(svc->endpoint()->PushChannelHandle(this, handle));
+    return svc->endpoint()->PushChannelHandle(this, handle);
   } else {
     return -ESHUTDOWN;
   }
diff --git a/libs/vr/libpdx/thread_local_buffer_tests.cpp b/libs/vr/libpdx/thread_local_buffer_tests.cpp
index c6a7b0b..1747d79 100644
--- a/libs/vr/libpdx/thread_local_buffer_tests.cpp
+++ b/libs/vr/libpdx/thread_local_buffer_tests.cpp
@@ -89,8 +89,9 @@
   EXPECT_NE(id1, id2);
 }
 
+// TODO(b/36456321): Fix this and enable it again.
 // Tests that thread-local buffers are allocated at the first buffer request.
-TEST(ThreadLocalBufferTest, InitialValue) {
+TEST(ThreadLocalBufferTest, DISABLED_InitialValue) {
   struct TypeTagX;
   using SendSlotX = ThreadLocalSlot<TypeTagX, kSendBufferIndex>;
 
diff --git a/libs/vr/libpdx_uds/remote_method_tests.cpp b/libs/vr/libpdx_uds/remote_method_tests.cpp
index 299910c..9050500 100644
--- a/libs/vr/libpdx_uds/remote_method_tests.cpp
+++ b/libs/vr/libpdx_uds/remote_method_tests.cpp
@@ -23,6 +23,7 @@
 using android::pdx::BorrowedHandle;
 using android::pdx::Channel;
 using android::pdx::ClientBase;
+using android::pdx::ErrorStatus;
 using android::pdx::LocalChannelHandle;
 using android::pdx::LocalHandle;
 using android::pdx::Message;
@@ -36,6 +37,20 @@
 
 namespace {
 
+std::string Rot13(const std::string& s) {
+  std::string text = s;
+  std::transform(std::begin(text), std::end(text), std::begin(text),
+                 [](char c) -> char {
+                   if (!std::isalpha(c)) {
+                     return c;
+                   } else {
+                     const char pivot = std::isupper(c) ? 'A' : 'a';
+                     return (c - pivot + 13) % 26 + pivot;
+                   }
+                 });
+  return text;
+}
+
 // Defines a serializable user type that may be transferred between client and
 // service.
 struct TestType {
@@ -134,6 +149,7 @@
     kOpOpenFiles,
     kOpReadFile,
     kOpPushChannel,
+    kOpPositive,
   };
 
   // Methods.
@@ -161,10 +177,11 @@
                     std::pair<int, BufferWrapper<std::uint8_t*>>(
                         const std::string&, int, std::size_t));
   PDX_REMOTE_METHOD(PushChannel, kOpPushChannel, LocalChannelHandle(Void));
+  PDX_REMOTE_METHOD(Positive, kOpPositive, void(int));
 
   PDX_REMOTE_API(API, Add, Foo, Concatenate, SumVector, StringLength,
                  SendTestType, SendVector, Rot13, NoArgs, SendFile, GetFile,
-                 GetTestFdType, OpenFiles, PushChannel);
+                 GetTestFdType, OpenFiles, PushChannel, Positive);
 };
 
 constexpr char TestInterface::kClientPath[];
@@ -301,6 +318,11 @@
     return status ? 0 : -status.error();
   }
 
+  bool Positive(int test_value) {
+    auto status = InvokeRemoteMethod<TestInterface::Positive>(test_value);
+    return status.ok();
+  }
+
   int GetFd() const { return event_fd(); }
 
  private:
@@ -397,6 +419,11 @@
             *this, &TestService::OnPushChannel, message);
         return 0;
 
+      case TestInterface::Positive::Opcode:
+        DispatchRemoteMethod<TestInterface::Positive>(
+            *this, &TestService::OnPositive, message);
+        return 0;
+
       default:
         return Service::DefaultHandleMessage(message);
     }
@@ -438,18 +465,8 @@
     return return_value;
   }
 
-  std::string OnRot13(Message&, const std::string& s) {
-    std::string text = s;
-    std::transform(std::begin(text), std::end(text), std::begin(text),
-                   [](char c) -> char {
-                     if (!std::isalpha(c)) {
-                       return c;
-                     } else {
-                       const char pivot = std::isupper(c) ? 'A' : 'a';
-                       return (c - pivot + 13) % 26 + pivot;
-                     }
-                   });
-    return text;
+  Status<std::string> OnRot13(Message&, const std::string& s) {
+    return {Rot13(s)};
   }
 
   int OnNoArgs(Message&) { return 1; }
@@ -514,6 +531,13 @@
     return status.take();
   }
 
+  Status<void> OnPositive(Message& /*message*/, int test_value) {
+    if (test_value >= 0)
+      return {};
+    else
+      return ErrorStatus(EINVAL);
+  }
+
   TestService(const TestService&) = delete;
   void operator=(const TestService&) = delete;
 };
@@ -575,6 +599,10 @@
   const auto cat = client->Concatenate("This is a string", ", that it is.");
   EXPECT_EQ("This is a string, that it is.", cat);
 
+  std::string alphabet = "abcdefghijklmnopqrstuvwxyz";
+  const auto rot13_alphabet = client->Rot13(alphabet);
+  EXPECT_EQ(Rot13(alphabet), rot13_alphabet);
+
   const auto length = client->Foo(10, "123");
   EXPECT_EQ(13, length);
 
@@ -677,6 +705,21 @@
   EXPECT_GE(35, sum);
 }
 
+TEST_F(RemoteMethodTest, Positive) {
+  // Create a test service and add it to the dispatcher.
+  auto service = TestService::Create();
+  ASSERT_NE(nullptr, service);
+  ASSERT_EQ(0, dispatcher_->AddService(service));
+
+  // Create a client to service.
+  auto client = TestClient::Create();
+  ASSERT_NE(nullptr, client);
+
+  ASSERT_TRUE(client->Positive(0));
+  ASSERT_TRUE(client->Positive(1));
+  ASSERT_FALSE(client->Positive(-1));
+}
+
 TEST_F(RemoteMethodTest, AggregateLocalHandle) {
   // Create a test service and add it to the dispatcher.
   auto service = TestService::Create();
diff --git a/libs/vr/libpdx_uds/service_framework_tests.cpp b/libs/vr/libpdx_uds/service_framework_tests.cpp
index 8891600..9e31e82 100644
--- a/libs/vr/libpdx_uds/service_framework_tests.cpp
+++ b/libs/vr/libpdx_uds/service_framework_tests.cpp
@@ -26,6 +26,7 @@
 using android::pdx::Channel;
 using android::pdx::ChannelReference;
 using android::pdx::ClientBase;
+using android::pdx::ErrorStatus;
 using android::pdx::LocalChannelHandle;
 using android::pdx::LocalHandle;
 using android::pdx::Message;
@@ -379,6 +380,14 @@
                         data_array.size() * sizeof(int), nullptr, 0));
   }
 
+  Status<int> GetEventMask(int events) {
+    if (auto* client_channel = GetChannel()) {
+      return client_channel->GetEventMask(events);
+    } else {
+      return ErrorStatus(EINVAL);
+    }
+  }
+
   using ClientBase<TestClient>::event_fd;
 
   enum : size_t { kMaxPayload = MAX_IMPULSE_LENGTH };
@@ -634,7 +643,9 @@
 
   count = epoll_wait(client->event_fd(), &event, 1, -1);
   ASSERT_EQ(1, count);
-  ASSERT_TRUE((EPOLLHUP & event.events) != 0);
+  auto event_status = client->GetEventMask(event.events);
+  ASSERT_TRUE(event_status.ok());
+  ASSERT_TRUE((EPOLLHUP & event_status.get()) != 0);
 }
 
 TEST_F(ServiceFrameworkTest, LargeDataSum) {
diff --git a/libs/vr/libvr_manager/vr_manager.cpp b/libs/vr/libvr_manager/vr_manager.cpp
index d24cbb5..5cfc22e 100644
--- a/libs/vr/libvr_manager/vr_manager.cpp
+++ b/libs/vr/libvr_manager/vr_manager.cpp
@@ -53,6 +53,40 @@
   return BBinder::onTransact(code, data, reply, flags);
 }
 
+// Must be kept in sync with interface defined in
+// IPersistentVrStateCallbacks.aidl.
+
+class BpPersistentVrStateCallbacks
+    : public BpInterface<IPersistentVrStateCallbacks> {
+ public:
+  explicit BpPersistentVrStateCallbacks(const sp<IBinder>& impl)
+      : BpInterface<IPersistentVrStateCallbacks>(impl) {}
+
+  void onPersistentVrStateChanged(bool enabled) {
+    Parcel data, reply;
+    data.writeInterfaceToken(
+        IPersistentVrStateCallbacks::getInterfaceDescriptor());
+    data.writeBool(enabled);
+    remote()->transact(ON_PERSISTENT_VR_STATE_CHANGED,
+                       data, &reply, IBinder::FLAG_ONEWAY);
+  }
+};
+
+IMPLEMENT_META_INTERFACE(PersistentVrStateCallbacks,
+                         "android.service.vr.IPersistentVrStateCallbacks");
+
+status_t BnPersistentVrStateCallbacks::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+  switch(code) {
+    case ON_PERSISTENT_VR_STATE_CHANGED: {
+      CHECK_INTERFACE(IPersistentVrStateCallbacks, data, reply);
+      onPersistentVrStateChanged(data.readBool());
+      return OK;
+    }
+  }
+  return BBinder::onTransact(code, data, reply, flags);
+}
+
 // Must be kept in sync with interface defined in IVrManager.aidl.
 
 class BpVrManager : public BpInterface<IVrManager> {
@@ -74,6 +108,22 @@
     remote()->transact(UNREGISTER_LISTENER, data, NULL);
   }
 
+  void registerPersistentVrStateListener(
+      const sp<IPersistentVrStateCallbacks>& cb) override {
+    Parcel data;
+    data.writeInterfaceToken(IVrManager::getInterfaceDescriptor());
+    data.writeStrongBinder(IInterface::asBinder(cb));
+    remote()->transact(REGISTER_PERSISTENT_VR_STATE_LISTENER, data, NULL);
+  }
+
+  void unregisterPersistentVrStateListener(
+      const sp<IPersistentVrStateCallbacks>& cb) override {
+    Parcel data;
+    data.writeInterfaceToken(IVrManager::getInterfaceDescriptor());
+    data.writeStrongBinder(IInterface::asBinder(cb));
+    remote()->transact(UNREGISTER_PERSISTENT_VR_STATE_LISTENER, data, NULL);
+  }
+
   bool getVrModeState() override {
     Parcel data, reply;
     data.writeInterfaceToken(IVrManager::getInterfaceDescriptor());
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index 4ad7c23..3f79a7b 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -20,7 +20,6 @@
     "display_manager_service.cpp",
     "display_service.cpp",
     "display_surface.cpp",
-    "epoll_event_dispatcher.cpp",
     "hardware_composer.cpp",
     "screenshot_service.cpp",
     "surface_channel.cpp",
diff --git a/libs/vr/libvrflinger/display_manager_service.cpp b/libs/vr/libvrflinger/display_manager_service.cpp
index 6df1642..e07901d 100644
--- a/libs/vr/libvrflinger/display_manager_service.cpp
+++ b/libs/vr/libvrflinger/display_manager_service.cpp
@@ -82,6 +82,11 @@
           *this, &DisplayManagerService::OnUpdateSurfaces, message);
       return 0;
 
+  case DisplayManagerRPC::SetupPoseBuffer::Opcode:
+      DispatchRemoteMethod<DisplayManagerRPC::SetupPoseBuffer>(
+          *this, &DisplayManagerService::OnSetupPoseBuffer, message);
+      return 0;
+
     default:
       return Service::DefaultHandleMessage(message);
   }
@@ -91,30 +96,31 @@
     pdx::Message& /*message*/) {
   std::vector<DisplaySurfaceInfo> items;
 
-  display_service_->ForEachDisplaySurface([&items](
-      const std::shared_ptr<DisplaySurface>& surface) mutable {
-    DisplaySurfaceInfo item;
+  display_service_->ForEachDisplaySurface(
+      [&items](const std::shared_ptr<DisplaySurface>& surface) mutable {
+        DisplaySurfaceInfo item;
 
-    item.surface_id = surface->surface_id();
-    item.process_id = surface->process_id();
-    item.type = surface->type();
-    item.flags = 0;  // TODO(eieio)
-    item.client_attributes = DisplaySurfaceAttributes{
-        {DisplaySurfaceAttributeEnum::Visible,
-         DisplaySurfaceAttributeValue{surface->client_visible()}},
-        {DisplaySurfaceAttributeEnum::ZOrder,
-         DisplaySurfaceAttributeValue{surface->client_z_order()}},
-        {DisplaySurfaceAttributeEnum::Blur, DisplaySurfaceAttributeValue{0.f}}};
-    item.manager_attributes = DisplaySurfaceAttributes{
-        {DisplaySurfaceAttributeEnum::Visible,
-         DisplaySurfaceAttributeValue{surface->manager_visible()}},
-        {DisplaySurfaceAttributeEnum::ZOrder,
-         DisplaySurfaceAttributeValue{surface->manager_z_order()}},
-        {DisplaySurfaceAttributeEnum::Blur,
-         DisplaySurfaceAttributeValue{surface->manager_blur()}}};
+        item.surface_id = surface->surface_id();
+        item.process_id = surface->process_id();
+        item.type = surface->type();
+        item.flags = 0;  // TODO(eieio)
+        item.client_attributes = DisplaySurfaceAttributes{
+            {DisplaySurfaceAttributeEnum::Visible,
+             DisplaySurfaceAttributeValue{surface->client_visible()}},
+            {DisplaySurfaceAttributeEnum::ZOrder,
+             DisplaySurfaceAttributeValue{surface->client_z_order()}},
+            {DisplaySurfaceAttributeEnum::Blur,
+             DisplaySurfaceAttributeValue{0.f}}};
+        item.manager_attributes = DisplaySurfaceAttributes{
+            {DisplaySurfaceAttributeEnum::Visible,
+             DisplaySurfaceAttributeValue{surface->manager_visible()}},
+            {DisplaySurfaceAttributeEnum::ZOrder,
+             DisplaySurfaceAttributeValue{surface->manager_z_order()}},
+            {DisplaySurfaceAttributeEnum::Blur,
+             DisplaySurfaceAttributeValue{surface->manager_blur()}}};
 
-    items.push_back(item);
-  });
+        items.push_back(item);
+      });
 
   // The fact that we're in the message handler implies that display_manager_ is
   // not nullptr. No check required, unless this service becomes multi-threaded.
@@ -182,6 +188,11 @@
   return 0;
 }
 
+pdx::BorrowedChannelHandle DisplayManagerService::OnSetupPoseBuffer(
+    pdx::Message& message, size_t extended_region_size, int usage) {
+  return display_service_->SetupPoseBuffer(extended_region_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 3f83c7d..19098c2 100644
--- a/libs/vr/libvrflinger/display_manager_service.h
+++ b/libs/vr/libvrflinger/display_manager_service.h
@@ -54,6 +54,10 @@
   int OnUpdateSurfaces(pdx::Message& message,
                        const std::map<int, DisplaySurfaceAttributes>& updates);
 
+  pdx::BorrowedChannelHandle OnSetupPoseBuffer(pdx::Message& message,
+                                               size_t extended_region_size,
+                                               int usage);
+
   // Called by the display service to indicate changes to display surfaces that
   // the display manager should evaluate.
   void OnDisplaySurfaceChange();
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index bb70c5c..c079187 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -18,10 +18,20 @@
 using android::pdx::rpc::DispatchRemoteMethod;
 using android::pdx::rpc::WrapBuffer;
 
+namespace {
+
+constexpr char kPersistentPoseBufferName[] = "DvrPersistentPoseBuffer";
+const int kPersistentPoseBufferUserId = 0;
+const int kPersistentPoseBufferGroupId = 0;
+const size_t kTimingDataSizeOffset = 128;
+
+}  // anonymous namespace
+
 namespace android {
 namespace dvr {
 
-DisplayService::DisplayService() : DisplayService(nullptr) {}
+DisplayService::DisplayService()
+    : DisplayService(nullptr) {}
 
 DisplayService::DisplayService(Hwc2::Composer* hidl)
     : BASE("DisplayService", Endpoint::Create(DisplayRPC::kClientPath)),
@@ -74,23 +84,23 @@
           *this, &DisplayService::OnCreateSurface, message);
       return 0;
 
-    case DisplayRPC::EnterVrMode::Opcode:
-      DispatchRemoteMethod<DisplayRPC::EnterVrMode>(
-          *this, &DisplayService::OnEnterVrMode, message);
-      return 0;
-
-    case DisplayRPC::ExitVrMode::Opcode:
-      DispatchRemoteMethod<DisplayRPC::ExitVrMode>(
-          *this, &DisplayService::OnExitVrMode, message);
-      return 0;
-
     case DisplayRPC::SetViewerParams::Opcode:
       DispatchRemoteMethod<DisplayRPC::SetViewerParams>(
           *this, &DisplayService::OnSetViewerParams, message);
       return 0;
 
+    case DisplayRPC::GetPoseBuffer::Opcode:
+      DispatchRemoteMethod<DisplayRPC::GetPoseBuffer>(
+          *this, &DisplayService::OnGetPoseBuffer, message);
+      return 0;
+
+    case DisplayRPC::IsVrAppRunning::Opcode:
+      DispatchRemoteMethod<DisplayRPC::IsVrAppRunning>(
+          *this, &DisplayService::IsVrAppRunning, message);
+      return 0;
+
     // Direct the surface specific messages to the surface instance.
-    case DisplayRPC::AllocateBuffer::Opcode:
+    case DisplayRPC::CreateBufferQueue::Opcode:
     case DisplayRPC::SetAttributes::Opcode:
     case DisplayRPC::GetMetadataBuffer::Opcode:
     case DisplayRPC::CreateVideoMeshSurface::Opcode:
@@ -182,16 +192,6 @@
   return WrapBuffer(std::move(buffer));
 }
 
-int DisplayService::OnEnterVrMode(pdx::Message& /*message*/) {
-  hardware_composer_.Resume();
-  return 0;
-}
-
-int DisplayService::OnExitVrMode(pdx::Message& /*message*/) {
-  hardware_composer_.Suspend();
-  return 0;
-}
-
 void DisplayService::OnSetViewerParams(pdx::Message& message,
                                        const ViewerParams& view_params) {
   Compositor* compositor = hardware_composer_.GetCompositor();
@@ -254,6 +254,15 @@
   compositor->UpdateHeadMountMetrics(head_mount_metrics);
 }
 
+pdx::LocalChannelHandle DisplayService::OnGetPoseBuffer(pdx::Message& message) {
+  if (pose_buffer_) {
+    return pose_buffer_->CreateConsumer().take();
+  }
+
+  pdx::rpc::RemoteMethodError(message, EAGAIN);
+  return {};
+}
+
 // Calls the message handler for the DisplaySurface associated with this
 // channel.
 int DisplayService::HandleSurfaceMessage(pdx::Message& message) {
@@ -290,7 +299,7 @@
   return visible_surfaces;
 }
 
-int DisplayService::UpdateActiveDisplaySurfaces() {
+void DisplayService::UpdateActiveDisplaySurfaces() {
   auto visible_surfaces = GetVisibleDisplaySurfaces();
 
   // Sort the surfaces based on manager z order first, then client z order.
@@ -321,7 +330,20 @@
     if (surface->client_blur_behind())
       blur_requested = true;
   }
-  return hardware_composer_.SetDisplaySurfaces(std::move(visible_surfaces));
+
+  hardware_composer_.SetDisplaySurfaces(std::move(visible_surfaces));
+}
+
+pdx::BorrowedChannelHandle DisplayService::SetupPoseBuffer(
+    size_t extended_region_size, int usage) {
+  if (!pose_buffer_) {
+    pose_buffer_ = BufferProducer::Create(
+        kPersistentPoseBufferName, kPersistentPoseBufferUserId,
+        kPersistentPoseBufferGroupId, usage,
+        extended_region_size + kTimingDataSizeOffset);
+  }
+
+  return pose_buffer_->GetChannelHandle().Borrow();
 }
 
 void DisplayService::OnHardwareComposerRefresh() {
@@ -338,5 +360,15 @@
     update_notifier_();
 }
 
+int DisplayService::IsVrAppRunning(pdx::Message& message) {
+  bool visible = true;
+  ForEachDisplaySurface([&visible](const std::shared_ptr<DisplaySurface>& surface) {
+    if (surface->client_z_order() == 0 && !surface->IsVisible())
+      visible = false;
+  });
+
+  REPLY_SUCCESS_RETURN(message, visible, 0);
+}
+
 }  // namespace dvr
 }  // namespace android
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
index b207e4d..8e96172 100644
--- a/libs/vr/libvrflinger/display_service.h
+++ b/libs/vr/libvrflinger/display_service.h
@@ -14,7 +14,6 @@
 
 #include "acquired_buffer.h"
 #include "display_surface.h"
-#include "epoll_event_dispatcher.h"
 #include "hardware_composer.h"
 
 namespace android {
@@ -37,7 +36,10 @@
 
   // Updates the list of actively displayed surfaces. This must be called after
   // any change to client/manager attributes that affect visibility or z order.
-  int UpdateActiveDisplaySurfaces();
+  void UpdateActiveDisplaySurfaces();
+
+  pdx::BorrowedChannelHandle SetupPoseBuffer(size_t extended_region_size,
+                                             int usage);
 
   template <class A>
   void ForEachDisplaySurface(A action) const {
@@ -61,13 +63,8 @@
     return hardware_composer_.display_metrics();
   }
 
-  void SetActive(bool activated) {
-    if (activated) {
-      hardware_composer_.Resume();
-    } else {
-      hardware_composer_.Suspend();
-    }
-  }
+  void GrantDisplayOwnership() { hardware_composer_.Enable(); }
+  void SeizeDisplayOwnership() { hardware_composer_.Disable(); }
 
   void OnHardwareComposerRefresh();
 
@@ -81,14 +78,17 @@
   DisplayService(android::Hwc2::Composer* hidl);
 
   SystemDisplayMetrics OnGetMetrics(pdx::Message& message);
-  int OnCreateSurface(pdx::Message& message, int width, int height,
-                      int format, int usage, DisplaySurfaceFlags flags);
+  int OnCreateSurface(pdx::Message& message, int width, int height, int format,
+                      int usage, DisplaySurfaceFlags flags);
 
   DisplayRPC::ByteBuffer OnGetEdsCapture(pdx::Message& message);
 
-  int OnEnterVrMode(pdx::Message& message);
-  int OnExitVrMode(pdx::Message& message);
-  void OnSetViewerParams(pdx::Message& message, const ViewerParams& view_params);
+  void OnSetViewerParams(pdx::Message& message,
+                         const ViewerParams& view_params);
+  pdx::LocalChannelHandle OnGetPoseBuffer(pdx::Message& message);
+
+  // Temporary query for current VR status. Will be removed later.
+  int IsVrAppRunning(pdx::Message& message);
 
   // Called by DisplaySurface to signal that a surface property has changed and
   // the display manager should be notified.
@@ -99,9 +99,10 @@
   DisplayService(const DisplayService&) = delete;
   void operator=(const DisplayService&) = delete;
 
-  EpollEventDispatcher dispatcher_;
   HardwareComposer hardware_composer_;
   DisplayConfigurationUpdateNotifier update_notifier_;
+
+  std::unique_ptr<BufferProducer> pose_buffer_;
 };
 
 }  // namespace dvr
diff --git a/libs/vr/libvrflinger/display_surface.cpp b/libs/vr/libvrflinger/display_surface.cpp
index d427ea6..66e9925 100644
--- a/libs/vr/libvrflinger/display_surface.cpp
+++ b/libs/vr/libvrflinger/display_surface.cpp
@@ -26,7 +26,7 @@
     : SurfaceChannel(service, surface_id, SurfaceTypeEnum::Normal,
                      sizeof(DisplaySurfaceMetadata)),
       process_id_(process_id),
-      posted_buffers_(kMaxPostedBuffers),
+      acquired_buffers_(kMaxPostedBuffers),
       video_mesh_surfaces_updated_(false),
       width_(width),
       height_(height),
@@ -40,8 +40,8 @@
       manager_visible_(false),
       manager_z_order_(0),
       manager_blur_(0.0f),
-      allocated_buffer_index_(0),
-      layer_order_(0) {}
+      layer_order_(0),
+      allocated_buffer_index_(0) {}
 
 DisplaySurface::~DisplaySurface() {
   ALOGD_IF(LOCAL_TRACE,
@@ -84,71 +84,126 @@
   client_blur_behind_ = blur_behind;
 }
 
+void DisplaySurface::DequeueBuffersLocked() {
+  if (consumer_queue_ == nullptr) {
+    ALOGE(
+        "DisplaySurface::DequeueBuffersLocked: Consumer queue is not "
+        "initialized.");
+    return;
+  }
+
+  size_t slot;
+  uint64_t sequence;
+  while (true) {
+    LocalHandle acquire_fence;
+    auto buffer_consumer =
+        consumer_queue_->Dequeue(0, &slot, &sequence, &acquire_fence);
+    if (!buffer_consumer) {
+      ALOGD_IF(TRACE,
+               "DisplaySurface::DequeueBuffersLocked: We have dequeued all "
+               "available buffers.");
+      return;
+    }
+
+    // Save buffer index, associated with the buffer id so that it can be looked
+    // up later.
+    int buffer_id = buffer_consumer->id();
+    if (buffer_id_to_index_.find(buffer_id) == buffer_id_to_index_.end()) {
+      buffer_id_to_index_[buffer_id] = allocated_buffer_index_;
+      ++allocated_buffer_index_;
+    }
+
+    if (!IsVisible()) {
+      ATRACE_NAME("DropFrameOnInvisibleSurface");
+      ALOGD_IF(TRACE,
+               "DisplaySurface::DequeueBuffersLocked: Discarding buffer_id=%d "
+               "on invisible surface.",
+               buffer_consumer->id());
+      buffer_consumer->Discard();
+      continue;
+    }
+
+    if (acquired_buffers_.IsFull()) {
+      ALOGE(
+          "DisplaySurface::DequeueBuffersLocked: Posted buffers full, "
+          "overwriting.");
+      acquired_buffers_.PopBack();
+    }
+
+    acquired_buffers_.Append(
+        AcquiredBuffer(buffer_consumer, std::move(acquire_fence), sequence));
+  }
+}
+
+AcquiredBuffer DisplaySurface::AcquireCurrentBuffer() {
+  std::lock_guard<std::mutex> autolock(lock_);
+  DequeueBuffersLocked();
+
+  if (acquired_buffers_.IsEmpty()) {
+    ALOGE(
+        "DisplaySurface::AcquireCurrentBuffer: attempt to acquire buffer when "
+        "none are posted.");
+    return AcquiredBuffer();
+  }
+  AcquiredBuffer buffer = std::move(acquired_buffers_.Front());
+  acquired_buffers_.PopFront();
+  ALOGD_IF(TRACE, "DisplaySurface::AcquireCurrentBuffer: buffer: %p",
+           buffer.buffer().get());
+  return buffer;
+}
+
 AcquiredBuffer DisplaySurface::AcquireNewestAvailableBuffer(
     AcquiredBuffer* skipped_buffer) {
   std::lock_guard<std::mutex> autolock(lock_);
+  DequeueBuffersLocked();
+
   AcquiredBuffer buffer;
   int frames = 0;
   // Basic latency stopgap for when the application misses a frame:
   // If the application recovers on the 2nd or 3rd (etc) frame after
   // missing, this code will skip frames to catch up by checking if
   // the next frame is also available.
-  while (!posted_buffers_.IsEmpty() && posted_buffers_.Front().IsAvailable()) {
+  while (!acquired_buffers_.IsEmpty() &&
+         acquired_buffers_.Front().IsAvailable()) {
     // Capture the skipped buffer into the result parameter.
     // Note that this API only supports skipping one buffer per vsync.
     if (frames > 0 && skipped_buffer)
       *skipped_buffer = std::move(buffer);
     ++frames;
-    buffer = std::move(posted_buffers_.Front());
-    posted_buffers_.PopFront();
+    buffer = std::move(acquired_buffers_.Front());
+    acquired_buffers_.PopFront();
     if (frames == 2)
       break;
   }
+  ALOGD_IF(TRACE, "DisplaySurface::AcquireNewestAvailableBuffer: buffer: %p",
+           buffer.buffer().get());
   return buffer;
 }
 
-bool DisplaySurface::IsBufferAvailable() const {
+uint32_t DisplaySurface::GetRenderBufferIndex(int buffer_id) {
   std::lock_guard<std::mutex> autolock(lock_);
-  return !posted_buffers_.IsEmpty() && posted_buffers_.Front().IsAvailable();
-}
 
-bool DisplaySurface::IsBufferPosted() const {
-  std::lock_guard<std::mutex> autolock(lock_);
-  return !posted_buffers_.IsEmpty();
-}
-
-AcquiredBuffer DisplaySurface::AcquireCurrentBuffer() {
-  std::lock_guard<std::mutex> autolock(lock_);
-  if (posted_buffers_.IsEmpty()) {
-    ALOGE("Error: attempt to acquire buffer when none are posted.");
-    return AcquiredBuffer();
+  if (buffer_id_to_index_.find(buffer_id) == buffer_id_to_index_.end()) {
+    ALOGW("DisplaySurface::GetRenderBufferIndex: unknown buffer_id %d.",
+          buffer_id);
+    return 0;
   }
-  AcquiredBuffer buffer = std::move(posted_buffers_.Front());
-  posted_buffers_.PopFront();
-  return buffer;
+  return buffer_id_to_index_[buffer_id];
 }
 
-int DisplaySurface::GetConsumers(std::vector<LocalChannelHandle>* consumers) {
+bool DisplaySurface::IsBufferAvailable() {
   std::lock_guard<std::mutex> autolock(lock_);
-  std::vector<LocalChannelHandle> items;
+  DequeueBuffersLocked();
 
-  for (auto pair : buffers_) {
-    const auto& buffer = pair.second;
+  return !acquired_buffers_.IsEmpty() &&
+         acquired_buffers_.Front().IsAvailable();
+}
 
-    Status<LocalChannelHandle> consumer_channel = buffer->CreateConsumer();
-    if (!consumer_channel) {
-      ALOGE(
-          "DisplaySurface::GetConsumers: Failed to get a new consumer for "
-          "buffer %d: %s",
-          buffer->id(), consumer_channel.GetErrorMessage().c_str());
-      return -consumer_channel.error();
-    }
+bool DisplaySurface::IsBufferPosted() {
+  std::lock_guard<std::mutex> autolock(lock_);
+  DequeueBuffersLocked();
 
-    items.push_back(consumer_channel.take());
-  }
-
-  *consumers = std::move(items);
-  return 0;
+  return !acquired_buffers_.IsEmpty();
 }
 
 int DisplaySurface::HandleMessage(pdx::Message& message) {
@@ -158,9 +213,9 @@
           *this, &DisplaySurface::OnClientSetAttributes, message);
       break;
 
-    case DisplayRPC::AllocateBuffer::Opcode:
-      DispatchRemoteMethod<DisplayRPC::AllocateBuffer>(
-          *this, &DisplaySurface::OnAllocateBuffer, message);
+    case DisplayRPC::CreateBufferQueue::Opcode:
+      DispatchRemoteMethod<DisplayRPC::CreateBufferQueue>(
+          *this, &DisplaySurface::OnCreateBufferQueue, message);
       break;
 
     case DisplayRPC::CreateVideoMeshSurface::Opcode:
@@ -226,58 +281,20 @@
   return 0;
 }
 
-// Allocates a new buffer for the DisplaySurface associated with this channel.
-std::pair<uint32_t, LocalChannelHandle> DisplaySurface::OnAllocateBuffer(
-    pdx::Message& message) {
-  // Inject flag to enable framebuffer compression for the application buffers.
-  // TODO(eieio,jbates): Make this configurable per hardware platform.
-  const int usage = usage_ | GRALLOC_USAGE_QCOM_FRAMEBUFFER_COMPRESSION;
-  const int slice_count =
-      (flags_ & static_cast<int>(DisplaySurfaceFlagsEnum::SeparateGeometry))
-          ? 2
-          : 1;
+LocalChannelHandle DisplaySurface::OnCreateBufferQueue(Message& message) {
+  ATRACE_NAME("DisplaySurface::OnCreateBufferQueue");
 
-  ALOGI_IF(
-      TRACE,
-      "DisplaySurface::OnAllocateBuffer: width=%d height=%d format=%x usage=%x "
-      "slice_count=%d",
-      width_, height_, format_, usage, slice_count);
-
-  // Create a producer buffer to hand back to the sender.
-  auto producer = BufferProducer::Create(width_, height_, format_, usage,
-                                         sizeof(uint64_t), slice_count);
-  if (!producer)
-    REPLY_ERROR_RETURN(message, EINVAL, {});
-
-  // Create and import a consumer attached to the producer.
-  Status<LocalChannelHandle> consumer_channel = producer->CreateConsumer();
-  if (!consumer_channel)
-    REPLY_ERROR_RETURN(message, consumer_channel.error(), {});
-
-  std::shared_ptr<BufferConsumer> consumer =
-      BufferConsumer::Import(consumer_channel.take());
-  if (!consumer)
-    REPLY_ERROR_RETURN(message, ENOMEM, {});
-
-  // Add the consumer to this surface.
-  int err = AddConsumer(consumer);
-  if (err < 0) {
-    ALOGE("DisplaySurface::OnAllocateBuffer: failed to add consumer: buffer=%d",
-          consumer->id());
-    REPLY_ERROR_RETURN(message, -err, {});
+  if (consumer_queue_ != nullptr) {
+    ALOGE(
+        "DisplaySurface::OnCreateBufferQueue: A ProdcuerQueue has already been "
+        "created and transported to DisplayClient.");
+    REPLY_ERROR_RETURN(message, EALREADY, {});
   }
 
-  // Move the channel handle so that it doesn't get closed when the producer
-  // goes out of scope.
-  std::pair<uint32_t, LocalChannelHandle> return_value(
-      allocated_buffer_index_, std::move(producer->GetChannelHandle()));
+  auto producer = ProducerQueue::Create<uint64_t>();
+  consumer_queue_ = producer->CreateConsumerQueue();
 
-  // Save buffer index, associated with the buffer id so that it can be looked
-  // up later.
-  buffer_id_to_index_[consumer->id()] = allocated_buffer_index_;
-  ++allocated_buffer_index_;
-
-  return return_value;
+  return std::move(producer->GetChannelHandle());
 }
 
 RemoteChannelHandle DisplaySurface::OnCreateVideoMeshSurface(
@@ -319,103 +336,6 @@
   return status.take();
 }
 
-int DisplaySurface::AddConsumer(
-    const std::shared_ptr<BufferConsumer>& consumer) {
-  ALOGD_IF(TRACE, "DisplaySurface::AddConsumer: buffer_id=%d", consumer->id());
-  // Add the consumer to the epoll dispatcher, edge-triggered.
-  int err = service()->dispatcher_.AddEventHandler(
-      consumer->event_fd(), EPOLLET | EPOLLIN | EPOLLHUP,
-      std::bind(&DisplaySurface::HandleConsumerEvents,
-                std::static_pointer_cast<DisplaySurface>(shared_from_this()),
-                consumer, std::placeholders::_1));
-  if (err) {
-    ALOGE(
-        "DisplaySurface::AddConsumer: failed to add epoll event handler for "
-        "consumer: %s",
-        strerror(-err));
-    return err;
-  }
-
-  // Add the consumer to the list of buffers for this surface.
-  std::lock_guard<std::mutex> autolock(lock_);
-  buffers_.insert(std::make_pair(consumer->id(), consumer));
-  return 0;
-}
-
-void DisplaySurface::RemoveConsumer(
-    const std::shared_ptr<BufferConsumer>& consumer) {
-  ALOGD_IF(TRACE, "DisplaySurface::RemoveConsumer: buffer_id=%d",
-           consumer->id());
-  service()->dispatcher_.RemoveEventHandler(consumer->event_fd());
-
-  std::lock_guard<std::mutex> autolock(lock_);
-  buffers_.erase(consumer->id());
-}
-
-void DisplaySurface::RemoveConsumerUnlocked(
-    const std::shared_ptr<BufferConsumer>& consumer) {
-  ALOGD_IF(TRACE, "DisplaySurface::RemoveConsumerUnlocked: buffer_id=%d",
-           consumer->id());
-  service()->dispatcher_.RemoveEventHandler(consumer->event_fd());
-  buffers_.erase(consumer->id());
-}
-
-void DisplaySurface::OnPostConsumer(
-    const std::shared_ptr<BufferConsumer>& consumer) {
-  ATRACE_NAME("DisplaySurface::OnPostConsumer");
-  std::lock_guard<std::mutex> autolock(lock_);
-
-  if (!IsVisible()) {
-    ALOGD_IF(TRACE,
-             "DisplaySurface::OnPostConsumer: Discarding buffer_id=%d on "
-             "invisible surface.",
-             consumer->id());
-    consumer->Discard();
-    return;
-  }
-
-  if (posted_buffers_.IsFull()) {
-    ALOGE("Error: posted buffers full, overwriting");
-    posted_buffers_.PopBack();
-  }
-
-  int error;
-  posted_buffers_.Append(AcquiredBuffer(consumer, &error));
-
-  // Remove the consumer if the other end was closed.
-  if (posted_buffers_.Back().IsEmpty() && error == -EPIPE)
-    RemoveConsumerUnlocked(consumer);
-}
-
-void DisplaySurface::HandleConsumerEvents(
-    const std::shared_ptr<BufferConsumer>& consumer, int events) {
-  auto status = consumer->GetEventMask(events);
-  if (!status) {
-    ALOGW(
-        "DisplaySurface::HandleConsumerEvents: Failed to get event mask for "
-        "consumer: %s",
-        status.GetErrorMessage().c_str());
-    return;
-  }
-
-  events = status.get();
-  if (events & EPOLLHUP) {
-    ALOGD_IF(TRACE,
-             "DisplaySurface::HandleConsumerEvents: removing event handler for "
-             "buffer=%d",
-             consumer->id());
-    RemoveConsumer(consumer);
-  } else if (events & EPOLLIN) {
-    // BufferHub uses EPOLLIN to signal consumer ownership.
-    ALOGD_IF(TRACE,
-             "DisplaySurface::HandleConsumerEvents: posting buffer=%d for "
-             "process=%d",
-             consumer->id(), process_id_);
-
-    OnPostConsumer(consumer);
-  }
-}
-
 std::vector<std::shared_ptr<VideoMeshSurface>>
 DisplaySurface::GetVideoMeshSurfaces() {
   std::lock_guard<std::mutex> autolock(lock_);
diff --git a/libs/vr/libvrflinger/display_surface.h b/libs/vr/libvrflinger/display_surface.h
index fa34057..d31a3a9 100644
--- a/libs/vr/libvrflinger/display_surface.h
+++ b/libs/vr/libvrflinger/display_surface.h
@@ -13,7 +13,6 @@
 #include <vector>
 
 #include "acquired_buffer.h"
-#include "epoll_event_dispatcher.h"
 #include "surface_channel.h"
 #include "video_mesh_surface.h"
 
@@ -61,23 +60,9 @@
     }
   }
 
-  uint32_t GetRenderBufferIndex(int buffer_id) {
-    return buffer_id_to_index_[buffer_id];
-  }
-
-  // Gets a new set of consumers for all of the surface's buffers. These
-  // consumers are independent from the consumers maintained internally to the
-  // surface and may be passed to other processes over IPC.
-  int GetConsumers(std::vector<pdx::LocalChannelHandle>* consumers);
-
-  template <class A>
-  void ForEachBuffer(A action) {
-    std::lock_guard<std::mutex> autolock(lock_);
-    std::for_each(buffers_.begin(), buffers_.end(), action);
-  }
-
-  bool IsBufferAvailable() const;
-  bool IsBufferPosted() const;
+  uint32_t GetRenderBufferIndex(int buffer_id);
+  bool IsBufferAvailable();
+  bool IsBufferPosted();
   AcquiredBuffer AcquireCurrentBuffer();
 
   // Get the newest buffer. Up to one buffer will be skipped. If a buffer is
@@ -119,12 +104,6 @@
   // Returns whether a frame is available without locking the mutex.
   bool IsFrameAvailableNoLock() const;
 
-  // Handles epoll events for BufferHub consumers. Events are mainly generated
-  // by producers posting buffers ready for display. This handler runs on the
-  // epoll event thread.
-  void HandleConsumerEvents(const std::shared_ptr<BufferConsumer>& consumer,
-                            int events);
-
   // Dispatches display surface messages to the appropriate handlers. This
   // handler runs on the displayd message dispatch thread.
   int HandleMessage(pdx::Message& message) override;
@@ -133,33 +112,22 @@
   int OnClientSetAttributes(pdx::Message& message,
                             const DisplaySurfaceAttributes& attributes);
 
-  // Allocates a buffer with the display surface geometry and settings and
-  // returns it to the client.
-  std::pair<uint32_t, pdx::LocalChannelHandle> OnAllocateBuffer(
-      pdx::Message& message);
+  // Creates a BufferHubQueue associated with this surface and returns the PDX
+  // handle of its producer side to the client.
+  pdx::LocalChannelHandle OnCreateBufferQueue(pdx::Message& message);
 
-  // Creates a video mesh surface associated with this surface and returns it
-  // to the client.
+  // Creates a video mesh surface associated with this surface and returns its
+  // PDX handle to the client.
   pdx::RemoteChannelHandle OnCreateVideoMeshSurface(pdx::Message& message);
 
-  // Sets the current buffer for the display surface, discarding the previous
-  // buffer if it is not already claimed. Runs on the epoll event thread.
-  void OnPostConsumer(const std::shared_ptr<BufferConsumer>& consumer);
-
   // Client interface (called through IPC) to set visibility and z order.
   void ClientSetVisible(bool visible);
   void ClientSetZOrder(int z_order);
   void ClientSetExcludeFromBlur(bool exclude_from_blur);
   void ClientSetBlurBehind(bool blur_behind);
 
-  // Runs on the displayd message dispatch thread.
-  int AddConsumer(const std::shared_ptr<BufferConsumer>& consumer);
-
-  // Runs on the epoll event thread.
-  void RemoveConsumer(const std::shared_ptr<BufferConsumer>& consumer);
-
-  // Runs on the epoll and display post thread.
-  void RemoveConsumerUnlocked(const std::shared_ptr<BufferConsumer>& consumer);
+  // Dequeue all available buffers from the consumer queue.
+  void DequeueBuffersLocked();
 
   DisplaySurface(const DisplaySurface&) = delete;
   void operator=(const DisplaySurface&) = delete;
@@ -169,11 +137,16 @@
   // Synchronizes access to mutable state below between message dispatch thread,
   // epoll event thread, and frame post thread.
   mutable std::mutex lock_;
-  std::unordered_map<int, std::shared_ptr<BufferConsumer>> buffers_;
+
+  // The consumer end of a BufferHubQueue. VrFlinger allocates and controls the
+  // buffer queue and pass producer end to the app and the consumer end to
+  // compositor.
+  // TODO(jwcai) Add support for multiple buffer queues per display surface.
+  std::shared_ptr<ConsumerQueue> consumer_queue_;
 
   // In a triple-buffered surface, up to kMaxPostedBuffers buffers may be
   // posted and pending.
-  RingBuffer<AcquiredBuffer> posted_buffers_;
+  RingBuffer<AcquiredBuffer> acquired_buffers_;
 
   // Provides access to VideoMeshSurface. Here we don't want to increase
   // the reference count immediately on allocation, will leave it into
@@ -194,10 +167,10 @@
   bool manager_visible_;
   int manager_z_order_;
   float manager_blur_;
-  // The monotonically increasing index for allocated buffers in this surface.
-  uint32_t allocated_buffer_index_;
   int layer_order_;
 
+  // The monotonically increasing index for allocated buffers in this surface.
+  uint32_t allocated_buffer_index_;
   // Maps from the buffer id to the corresponding allocated buffer index.
   std::unordered_map<int, uint32_t> buffer_id_to_index_;
 };
diff --git a/libs/vr/libvrflinger/epoll_event_dispatcher.cpp b/libs/vr/libvrflinger/epoll_event_dispatcher.cpp
deleted file mode 100644
index b37e76e..0000000
--- a/libs/vr/libvrflinger/epoll_event_dispatcher.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-#include "epoll_event_dispatcher.h"
-
-#include <log/log.h>
-#include <sys/epoll.h>
-#include <sys/eventfd.h>
-#include <sys/prctl.h>
-
-#include <dvr/performance_client_api.h>
-
-namespace android {
-namespace dvr {
-
-EpollEventDispatcher::EpollEventDispatcher()
-    : exit_thread_(false), epoll_fd_(-1), event_fd_(-1) {
-  epoll_fd_ = epoll_create(64);
-  if (epoll_fd_ < 0) {
-    ALOGE("Failed to create epoll fd: %s", strerror(errno));
-    return;
-  }
-
-  event_fd_ = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
-  if (event_fd_ < 0) {
-    ALOGE("Failed to create event for epolling: %s", strerror(errno));
-    return;
-  }
-
-  // Add watch for eventfd. This should only watch for EPOLLIN, which gets set
-  // when eventfd_write occurs. Use "this" as a unique sentinal value to
-  // identify events from the event fd.
-  epoll_event event = {.events = EPOLLIN, .data = {.ptr = this}};
-  if (epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, event_fd_, &event) < 0) {
-    ALOGE("Failed to add eventfd to epoll set because: %s", strerror(errno));
-    return;
-  }
-
-  thread_ = std::thread(&EpollEventDispatcher::EventThread, this);
-}
-
-EpollEventDispatcher::~EpollEventDispatcher() {
-  Stop();
-
-  close(epoll_fd_);
-  close(event_fd_);
-}
-
-void EpollEventDispatcher::Stop() {
-  exit_thread_.store(true);
-  eventfd_write(event_fd_, 1);
-}
-
-int EpollEventDispatcher::AddEventHandler(int fd, int event_mask,
-                                          Handler handler) {
-  std::lock_guard<std::mutex> lock(lock_);
-
-  epoll_event event;
-  event.events = event_mask;
-  event.data.ptr = &(handlers_[fd] = handler);
-
-  ALOGD_IF(
-      TRACE,
-      "EpollEventDispatcher::AddEventHandler: fd=%d event_mask=0x%x handler=%p",
-      fd, event_mask, event.data.ptr);
-
-  int err = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd, &event);
-  return err < 0 ? -errno : 0;
-}
-
-int EpollEventDispatcher::RemoveEventHandler(int fd) {
-  ALOGD_IF(TRACE, "EpollEventDispatcher::RemoveEventHandler: fd=%d", fd);
-  std::lock_guard<std::mutex> lock(lock_);
-
-  epoll_event dummy;  // See BUGS in man 2 epoll_ctl.
-  if (epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, fd, &dummy) < 0) {
-    ALOGE("Failed to remove fd from epoll set because: %s", strerror(errno));
-    return -errno;
-  }
-
-  // If the fd was valid above, add it to the list of ids to remove.
-  removed_handlers_.push_back(fd);
-
-  // Wake up the event thread to clean up.
-  eventfd_write(event_fd_, 1);
-
-  return 0;
-}
-
-void EpollEventDispatcher::EventThread() {
-  prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("EpollEvent"), 0, 0, 0);
-
-  const int error = dvrSetSchedulerClass(0, "graphics");
-  LOG_ALWAYS_FATAL_IF(
-      error < 0,
-      "EpollEventDispatcher::EventThread: Failed to set scheduler class: %s",
-      strerror(-error));
-
-  const size_t kMaxNumEvents = 128;
-  epoll_event events[kMaxNumEvents];
-
-  while (!exit_thread_.load()) {
-    int num_events = epoll_wait(epoll_fd_, events, kMaxNumEvents, -1);
-    if (num_events < 0 && errno != EINTR)
-      break;
-
-    ALOGD_IF(TRACE, "EpollEventDispatcher::EventThread: num_events=%d",
-             num_events);
-
-    for (int i = 0; i < num_events; i++) {
-      ALOGD_IF(
-          TRACE,
-          "EpollEventDispatcher::EventThread: event %d: handler=%p events=0x%x",
-          i, events[i].data.ptr, events[i].events);
-
-      if (events[i].data.ptr == this) {
-        // Clear pending event on event_fd_. Serialize the read with respect to
-        // writes from other threads.
-        std::lock_guard<std::mutex> lock(lock_);
-        eventfd_t value;
-        eventfd_read(event_fd_, &value);
-      } else {
-        auto handler = reinterpret_cast<Handler*>(events[i].data.ptr);
-        if (handler)
-          (*handler)(events[i].events);
-      }
-    }
-
-    // Remove any handlers that have been posted for removal. This is done here
-    // instead of in RemoveEventHandler() to prevent races between the dispatch
-    // thread and the code requesting the removal. Handlers are guaranteed to
-    // stay alive between exiting epoll_wait() and the dispatch loop above.
-    std::lock_guard<std::mutex> lock(lock_);
-    for (auto handler_fd : removed_handlers_) {
-      ALOGD_IF(TRACE,
-               "EpollEventDispatcher::EventThread: removing handler: fd=%d",
-               handler_fd);
-      handlers_.erase(handler_fd);
-    }
-    removed_handlers_.clear();
-  }
-}
-
-}  // namespace dvr
-}  // namespace android
diff --git a/libs/vr/libvrflinger/epoll_event_dispatcher.h b/libs/vr/libvrflinger/epoll_event_dispatcher.h
deleted file mode 100644
index 43bca2e..0000000
--- a/libs/vr/libvrflinger/epoll_event_dispatcher.h
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef ANDROID_DVR_SERVICES_DISPLAYD_EPOLL_EVENT_DISPATCHER_H_
-#define ANDROID_DVR_SERVICES_DISPLAYD_EPOLL_EVENT_DISPATCHER_H_
-
-#include <sys/epoll.h>
-
-#include <atomic>
-#include <functional>
-#include <mutex>
-#include <thread>
-#include <unordered_map>
-#include <vector>
-
-namespace android {
-namespace dvr {
-
-class EpollEventDispatcher {
- public:
-  // Function type for event handlers. The handler receives a bitmask of the
-  // epoll events that occurred on the file descriptor associated with the
-  // handler.
-  using Handler = std::function<void(int)>;
-
-  EpollEventDispatcher();
-  ~EpollEventDispatcher();
-
-  // |handler| is called on the internal dispatch thread when |fd| is signaled
-  // by events in |event_mask|.
-  // Return 0 on success or a negative error code on failure.
-  int AddEventHandler(int fd, int event_mask, Handler handler);
-  int RemoveEventHandler(int fd);
-
-  void Stop();
-
- private:
-  void EventThread();
-
-  std::thread thread_;
-  std::atomic<bool> exit_thread_;
-
-  // Protects handlers_ and removed_handlers_ and serializes operations on
-  // epoll_fd_ and event_fd_.
-  std::mutex lock_;
-
-  // Maintains a map of fds to event handlers. This is primarily to keep any
-  // references alive that may be bound in the std::function instances. It is
-  // not used at dispatch time to avoid performance problems with different
-  // versions of std::unordered_map.
-  std::unordered_map<int, Handler> handlers_;
-
-  // List of fds to be removed from the map. The actual removal is performed
-  // by the event dispatch thread to avoid races.
-  std::vector<int> removed_handlers_;
-
-  int epoll_fd_;
-  int event_fd_;
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_SERVICES_DISPLAYD_EPOLL_EVENT_DISPATCHER_H_
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index f801d9b..542bbd9 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -103,12 +103,13 @@
     : initialized_(false),
       hwc2_hidl_(hwc2_hidl),
       display_transform_(HWC_TRANSFORM_NONE),
-      display_surfaces_updated_(false),
-      hardware_layers_need_update_(false),
+      active_surfaces_updated_(false),
       active_layer_count_(0),
       gpu_layer_(nullptr),
-      post_thread_state_(PostThreadState::kPaused),
-      terminate_post_thread_event_fd_(-1),
+      post_thread_enabled_(false),
+      post_thread_running_(false),
+      post_thread_quit_requested_(false),
+      post_thread_interrupt_event_fd_(-1),
       backlight_brightness_fd_(-1),
       primary_display_vsync_event_fd_(-1),
       primary_display_wait_pp_fd_(-1),
@@ -124,7 +125,12 @@
 }
 
 HardwareComposer::~HardwareComposer(void) {
-  Suspend();
+  std::unique_lock<std::mutex> lock(post_thread_mutex_);
+  if (post_thread_.joinable()) {
+    post_thread_quit_requested_ = true;
+    post_thread_cond_var_.notify_all();
+    post_thread_.join();
+  }
 }
 
 bool HardwareComposer::Initialize() {
@@ -167,24 +173,56 @@
   display_transform_ = HWC_TRANSFORM_NONE;
   display_metrics_ = native_display_metrics_;
 
+  post_thread_interrupt_event_fd_.Reset(
+      eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
+  LOG_ALWAYS_FATAL_IF(
+      !post_thread_interrupt_event_fd_,
+      "HardwareComposer: Failed to create interrupt event fd : %s",
+      strerror(errno));
+
+  post_thread_ = std::thread(&HardwareComposer::PostThread, this);
+
   initialized_ = true;
 
   return initialized_;
 }
 
-bool HardwareComposer::Resume() {
-  std::lock_guard<std::mutex> post_thread_lock(post_thread_state_mutex_);
-  if (post_thread_state_ == PostThreadState::kRunning) {
-    return false;
+void HardwareComposer::Enable() {
+  std::lock_guard<std::mutex> lock(post_thread_mutex_);
+  post_thread_enabled_ = true;
+  post_thread_cond_var_.notify_all();
+}
+
+void HardwareComposer::Disable() {
+  std::unique_lock<std::mutex> lock(post_thread_mutex_);
+  post_thread_enabled_ = false;
+  if (post_thread_running_) {
+    // Write to the interrupt fd to get fast interrupt of the post thread
+    int error = eventfd_write(post_thread_interrupt_event_fd_.Get(), 1);
+    ALOGW_IF(error,
+             "HardwareComposer::Disable: could not write post "
+             "thread interrupt event fd : %s",
+             strerror(errno));
+
+    post_thread_cond_var_.wait(lock, [this] { return !post_thread_running_; });
+
+    // Read the interrupt fd to clear its state
+    uint64_t interrupt_count= 0;
+    error = eventfd_read(post_thread_interrupt_event_fd_.Get(),
+                         &interrupt_count);
+    ALOGW_IF(error,
+             "HardwareComposer::Disable: could not read post "
+             "thread interrupt event fd : %s",
+             strerror(errno));
   }
+}
 
-  std::lock_guard<std::mutex> layer_lock(layer_mutex_);
+bool HardwareComposer::PostThreadHasWork() {
+  return !display_surfaces_.empty() ||
+      (active_surfaces_updated_ && !active_surfaces_.empty());
+}
 
-  int32_t ret = HWC2_ERROR_NONE;
-
-  // Always turn off vsync when we start.
-  EnableVsync(false);
-
+void HardwareComposer::OnPostThreadResumed() {
   constexpr int format = HAL_PIXEL_FORMAT_RGBA_8888;
   constexpr int usage =
       GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER;
@@ -198,97 +236,33 @@
     layer->Initialize(hwc2_hidl_.get(), &native_display_metrics_);
   }
 
-#if ENABLE_BACKLIGHT_BRIGHTNESS
-  // TODO(hendrikw): This isn't required at the moment. It's possible that there
-  //                 is another method to access this when needed.
-  // Open the backlight brightness control sysfs node.
-  backlight_brightness_fd_ = LocalHandle(kBacklightBrightnessSysFile, O_RDWR);
-  ALOGW_IF(!backlight_brightness_fd_,
-           "HardwareComposer: Failed to open backlight brightness control: %s",
-           strerror(errno));
-#endif // ENABLE_BACKLIGHT_BRIGHTNESS
-
-  // Open the vsync event node for the primary display.
-  // TODO(eieio): Move this into a platform-specific class.
-  primary_display_vsync_event_fd_ =
-      LocalHandle(kPrimaryDisplayVSyncEventFile, O_RDONLY);
-  ALOGE_IF(!primary_display_vsync_event_fd_,
-           "HardwareComposer: Failed to open vsync event node for primary "
-           "display: %s",
-           strerror(errno));
-
-  // Open the wait pingpong status node for the primary display.
-  // TODO(eieio): Move this into a platform-specific class.
-  primary_display_wait_pp_fd_ =
-      LocalHandle(kPrimaryDisplayWaitPPEventFile, O_RDONLY);
-  ALOGE_IF(
-      !primary_display_wait_pp_fd_,
-      "HardwareComposer: Failed to open wait_pp node for primary display: %s",
-      strerror(errno));
-
-  // Create a timerfd based on CLOCK_MONOTINIC.
-  vsync_sleep_timer_fd_.Reset(timerfd_create(CLOCK_MONOTONIC, 0));
-  LOG_ALWAYS_FATAL_IF(
-      !vsync_sleep_timer_fd_,
-      "HardwareComposer: Failed to create vsync sleep timerfd: %s",
-      strerror(errno));
-
   // Connect to pose service.
   pose_client_ = dvrPoseCreate();
   ALOGE_IF(!pose_client_, "HardwareComposer: Failed to create pose client");
 
-  terminate_post_thread_event_fd_.Reset(
-      eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
-  LOG_ALWAYS_FATAL_IF(
-      !terminate_post_thread_event_fd_,
-      "HardwareComposer: Failed to create terminate PostThread event fd : %s",
-      strerror(errno));
+  EnableVsync(true);
 
-  post_thread_state_ = PostThreadState::kRunning;
-  post_thread_state_cond_var_.notify_all();
+  // TODO(skiazyk): We need to do something about accessing this directly,
+  // supposedly there is a backlight service on the way.
+  // TODO(steventhomas): When we change the backlight setting, will surface
+  // flinger (or something else) set it back to its original value once we give
+  // control of the display back to surface flinger?
+  SetBacklightBrightness(255);
 
-  // If get_id() is the default thread::id object, it has not been created yet
-  if (post_thread_.get_id() == std::thread::id()) {
-    post_thread_ = std::thread(&HardwareComposer::PostThread, this);
-  } else {
-    UpdateDisplayState();
-  }
+  // Initialize the GPU compositor.
+  LOG_ALWAYS_FATAL_IF(!compositor_.Initialize(GetHmdDisplayMetrics()),
+                      "Failed to initialize the compositor");
 
-  return true;
+  // Trigger target-specific performance mode change.
+  property_set(kDvrPerformanceProperty, "performance");
 }
 
-bool HardwareComposer::Suspend() {
-  std::unique_lock<std::mutex> post_thread_lock(post_thread_state_mutex_);
-  if (post_thread_state_ == PostThreadState::kPaused) {
-    return false;
-  }
-
-  post_thread_state_ = PostThreadState::kPauseRequested;
-
-  int error = eventfd_write(terminate_post_thread_event_fd_.Get(), 1);
-  ALOGE_IF(error,
-           "HardwareComposer::Suspend: could not write post "
-           "thread termination event fd : %d",
-           error);
-
-  post_thread_state_cond_var_.wait(
-      post_thread_lock,
-      [this] { return post_thread_state_ == PostThreadState::kPaused; });
-  terminate_post_thread_event_fd_.Close();
-
-  // Wait for any pending layer operations to finish
-  std::lock_guard<std::mutex> layer_lock(layer_mutex_);
-
-  EnableVsync(false);
-
-  backlight_brightness_fd_.Close();
-  primary_display_vsync_event_fd_.Close();
-  primary_display_wait_pp_fd_.Close();
-  vsync_sleep_timer_fd_.Close();
+void HardwareComposer::OnPostThreadPaused() {
   retire_fence_fds_.clear();
   gpu_layer_ = nullptr;
 
-  // We have to destroy the layers before we close the hwc device
+  // We have to destroy the layers to fully clear hwc device state before
+  // handing off back to surface flinger
   for (size_t i = 0; i < kMaxHardwareLayers; ++i) {
     layers_[i]->Reset();
   }
@@ -297,12 +271,26 @@
 
   framebuffer_target_.reset();
 
-  //hwc2_hidl_.reset();
+  display_surfaces_.clear();
+  compositor_surfaces_.clear();
 
-  if (pose_client_)
+  // Since we're clearing display_surfaces_ we'll need an update.
+  active_surfaces_updated_ = true;
+
+  if (pose_client_) {
     dvrPoseDestroy(pose_client_);
+    pose_client_ = nullptr;
+  }
 
-  return true;
+  EnableVsync(false);
+
+  frame_time_history_.ResetWithSeed(GuessFrameTime(0));
+  frame_time_backlog_.clear();
+
+  compositor_.Shutdown();
+
+  // Trigger target-specific performance mode change.
+  property_set(kDvrPerformanceProperty, "idle");
 }
 
 DisplayMetrics HardwareComposer::GetHmdDisplayMetrics() const {
@@ -519,82 +507,51 @@
   }
 }
 
-// TODO(skiazyk): This is a work-around for the fact that we currently do not
-// handle the case when new surfaces are introduced when displayd is not
-// in an active state. A proper-solution will require re-structuring
-// displayd a little, but hopefully this is sufficient for now.
-// For example, could this be handled in |UpdateLayerSettings| instead?
-void HardwareComposer::UpdateDisplayState() {
-  const bool has_display_surfaces = display_surfaces_.size() > 0;
-
-  if (has_display_surfaces) {
-    EnableVsync(true);
-  }
-
-  // TODO(skiazyk): We need to do something about accessing this directly,
-  // supposedly there is a backlight service on the way.
-  SetBacklightBrightness(255);
-
-  // Trigger target-specific performance mode change.
-  property_set(kDvrPerformanceProperty, has_display_surfaces ? "performance" : "idle");
-}
-
-int HardwareComposer::SetDisplaySurfaces(
+void HardwareComposer::SetDisplaySurfaces(
     std::vector<std::shared_ptr<DisplaySurface>> surfaces) {
-  // The double lock is necessary because we access both the display surfaces
-  // and post_thread_state_.
-  std::lock_guard<std::mutex> post_thread_state_lock(post_thread_state_mutex_);
-  std::lock_guard<std::mutex> layer_lock(layer_mutex_);
-
   ALOGI("HardwareComposer::SetDisplaySurfaces: surface count=%zd",
         surfaces.size());
+  std::unique_lock<std::mutex> lock(post_thread_mutex_);
+  active_surfaces_ = std::move(surfaces);
+  active_surfaces_updated_ = true;
+  if (post_thread_enabled_)
+    post_thread_cond_var_.notify_all();
+}
 
-  // Figure out whether we need to update hardware layers. If this surface
-  // change does not add or remove hardware layers we can avoid display hiccups
-  // by gracefully updating only the GPU compositor layers.
-  // hardware_layers_need_update_ is reset to false by the Post thread.
-  int old_gpu_layer_count = 0;
-  int new_gpu_layer_count = 0;
-  // Look for new hardware layers and count new GPU layers.
-  for (const auto& surface : surfaces) {
-    if (!(surface->flags() &
-          DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_DISTORTION))
-      ++new_gpu_layer_count;
-    else if (std::find(display_surfaces_.begin(), display_surfaces_.end(),
-                       surface) == display_surfaces_.end())
-      // This is a new hardware layer, we need to update.
-      hardware_layers_need_update_ = true;
+int HardwareComposer::PostThreadPollInterruptible(int event_fd,
+                                                  int requested_events) {
+  pollfd pfd[2] = {
+      {
+          .fd = event_fd,
+          .events = static_cast<short>(requested_events),
+          .revents = 0,
+      },
+      {
+          .fd = post_thread_interrupt_event_fd_.Get(),
+          .events = POLLPRI | POLLIN,
+          .revents = 0,
+      },
+  };
+  int ret, error;
+  do {
+    ret = poll(pfd, 2, -1);
+    error = errno;
+    ALOGW_IF(ret < 0,
+             "HardwareComposer::PostThreadPollInterruptible: Error during "
+             "poll(): %s (%d)",
+             strerror(error), error);
+  } while (ret < 0 && error == EINTR);
+
+  if (ret < 0) {
+    return -error;
+  } else if (pfd[0].revents != 0) {
+    return 0;
+  } else if (pfd[1].revents != 0) {
+    ALOGI("VrHwcPost thread interrupted");
+    return kPostThreadInterrupted;
+  } else {
+    return 0;
   }
-  // Look for deleted hardware layers or compositor layers.
-  for (const auto& surface : display_surfaces_) {
-    if (!(surface->flags() &
-          DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_DISTORTION))
-      ++old_gpu_layer_count;
-    else if (std::find(surfaces.begin(), surfaces.end(), surface) ==
-             surfaces.end())
-      // This is a deleted hardware layer, we need to update.
-      hardware_layers_need_update_ = true;
-  }
-  // Check for compositor hardware layer transition.
-  if ((!old_gpu_layer_count && new_gpu_layer_count) ||
-      (old_gpu_layer_count && !new_gpu_layer_count))
-    hardware_layers_need_update_ = true;
-
-  display_surfaces_ = std::move(surfaces);
-  display_surfaces_updated_ = true;
-
-  // Set the chosen layer order for all surfaces.
-  for (size_t i = 0; i < display_surfaces_.size(); ++i) {
-    display_surfaces_[i]->SetLayerOrder(static_cast<int>(i));
-  }
-
-  // TODO(skiazyk): fix this so that it is handled seamlessly with dormant/non-
-  // dormant state.
-  if (post_thread_state_ == PostThreadState::kRunning) {
-    UpdateDisplayState();
-  }
-
-  return 0;
 }
 
 // Reads the value of the display driver wait_pingpong state. Returns 0 or 1
@@ -690,35 +647,10 @@
 // Blocks until the next vsync event is signaled by the display driver.
 // TODO(eieio): This is pretty driver specific, this should be moved to a
 // separate class eventually.
-int HardwareComposer::BlockUntilVSync(/*out*/ bool* suspend_requested) {
-  *suspend_requested = false;
-  const int event_fd = primary_display_vsync_event_fd_.Get();
-  pollfd pfd[2] = {
-      {
-          .fd = event_fd, .events = POLLPRI, .revents = 0,
-      },
-      // This extra event fd is to ensure that we can break out of this loop to
-      // pause the thread even when vsync is disabled, and thus no events on the
-      // vsync fd are being generated.
-      {
-          .fd = terminate_post_thread_event_fd_.Get(),
-          .events = POLLPRI | POLLIN,
-          .revents = 0,
-      },
-  };
-  int ret, error;
-  do {
-    ret = poll(pfd, 2, -1);
-    error = errno;
-    ALOGW_IF(ret < 0,
-             "HardwareComposer::BlockUntilVSync: Error while waiting for vsync "
-             "event: %s (%d)",
-             strerror(error), error);
-  } while (ret < 0 && error == EINTR);
-
-  if (ret >= 0 && pfd[1].revents != 0)
-    *suspend_requested = true;
-  return ret < 0 ? -error : 0;
+int HardwareComposer::BlockUntilVSync() {
+  return PostThreadPollInterruptible(primary_display_vsync_event_fd_.Get(),
+                                     // There will be a POLLPRI event on vsync
+                                     POLLPRI);
 }
 
 // Waits for the next vsync and returns the timestamp of the vsync event. If
@@ -740,9 +672,8 @@
 
     if (error == -EAGAIN) {
       // Vsync was turned off, wait for the next vsync event.
-      bool suspend_requested = false;
-      error = BlockUntilVSync(&suspend_requested);
-      if (error < 0 || suspend_requested)
+      error = BlockUntilVSync();
+      if (error < 0 || error == kPostThreadInterrupted)
         return error;
 
       // Try again to get the timestamp for this new vsync interval.
@@ -765,13 +696,14 @@
 
     if (distance_to_vsync_est > threshold_ns) {
       // Wait for vsync event notification.
-      bool suspend_requested = false;
-      error = BlockUntilVSync(&suspend_requested);
-      if (error < 0 || suspend_requested)
+      error = BlockUntilVSync();
+      if (error < 0 || error == kPostThreadInterrupted)
         return error;
     } else {
-      // Sleep for a short time before retrying.
-      std::this_thread::sleep_for(std::chrono::milliseconds(1));
+      // Sleep for a short time (1 millisecond) before retrying.
+      error = SleepUntil(GetSystemClockNs() + 1000000);
+      if (error < 0 || error == kPostThreadInterrupted)
+        return error;
     }
   }
 }
@@ -791,21 +723,12 @@
     return -error;
   }
 
-  // Wait for the timer by reading the expiration count.
-  uint64_t expiration_count;
-  ret = read(timer_fd, &expiration_count, sizeof(expiration_count));
-  if (ret < 0) {
-    ALOGE("HardwareComposer::SleepUntil: Failed to wait for timerfd: %s",
-          strerror(error));
-    return -error;
-  }
-
-  return 0;
+  return PostThreadPollInterruptible(timer_fd, POLLIN);
 }
 
 void HardwareComposer::PostThread() {
   // NOLINTNEXTLINE(runtime/int)
-  prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("PostThread"), 0, 0, 0);
+  prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("VrHwcPost"), 0, 0, 0);
 
   // Set the scheduler to SCHED_FIFO with high priority.
   int error = dvrSetSchedulerClass(0, "graphics:high");
@@ -819,12 +742,40 @@
       "HardwareComposer::PostThread: Failed to set cpu partition: %s",
       strerror(-error));
 
-  // Force the layers to be setup at least once.
-  display_surfaces_updated_ = true;
+#if ENABLE_BACKLIGHT_BRIGHTNESS
+  // TODO(hendrikw): This isn't required at the moment. It's possible that there
+  //                 is another method to access this when needed.
+  // Open the backlight brightness control sysfs node.
+  backlight_brightness_fd_ = LocalHandle(kBacklightBrightnessSysFile, O_RDWR);
+  ALOGW_IF(!backlight_brightness_fd_,
+           "HardwareComposer: Failed to open backlight brightness control: %s",
+           strerror(errno));
+#endif // ENABLE_BACKLIGHT_BRIGHTNESS
 
-  // Initialize the GPU compositor.
-  LOG_ALWAYS_FATAL_IF(!compositor_.Initialize(GetHmdDisplayMetrics()),
-                      "Failed to initialize the compositor");
+  // Open the vsync event node for the primary display.
+  // TODO(eieio): Move this into a platform-specific class.
+  primary_display_vsync_event_fd_ =
+      LocalHandle(kPrimaryDisplayVSyncEventFile, O_RDONLY);
+  ALOGE_IF(!primary_display_vsync_event_fd_,
+           "HardwareComposer: Failed to open vsync event node for primary "
+           "display: %s",
+           strerror(errno));
+
+  // Open the wait pingpong status node for the primary display.
+  // TODO(eieio): Move this into a platform-specific class.
+  primary_display_wait_pp_fd_ =
+      LocalHandle(kPrimaryDisplayWaitPPEventFile, O_RDONLY);
+  ALOGW_IF(
+      !primary_display_wait_pp_fd_,
+      "HardwareComposer: Failed to open wait_pp node for primary display: %s",
+      strerror(errno));
+
+  // Create a timerfd based on CLOCK_MONOTINIC.
+  vsync_sleep_timer_fd_.Reset(timerfd_create(CLOCK_MONOTONIC, 0));
+  LOG_ALWAYS_FATAL_IF(
+      !vsync_sleep_timer_fd_,
+      "HardwareComposer: Failed to create vsync sleep timerfd: %s",
+      strerror(errno));
 
   const int64_t ns_per_frame = display_metrics_.vsync_period_ns;
   const int64_t photon_offset_ns = GetPosePredictionTimeOffset(ns_per_frame);
@@ -838,41 +789,48 @@
   right_eye_photon_offset_ns =
       property_get_int64(kRightEyeOffsetProperty, right_eye_photon_offset_ns);
 
-  // The list of surfaces the compositor should attempt to render. This is set
-  // at the start of each frame.
-  std::vector<std::shared_ptr<DisplaySurface>> compositor_surfaces;
-  compositor_surfaces.reserve(2);
+  compositor_surfaces_.reserve(2);
 
-  // Our history of frame times. This is used to get a better estimate of how
-  // long the next frame will take, to set a schedule for EDS.
-  FrameTimeHistory frame_time_history;
-
-  // The backlog is used to allow us to start rendering the next frame before
-  // the previous frame has finished, and still get an accurate measurement of
-  // frame duration.
-  std::vector<FrameTimeMeasurementRecord> frame_time_backlog;
   constexpr int kFrameTimeBacklogMax = 2;
-  frame_time_backlog.reserve(kFrameTimeBacklogMax);
+  frame_time_backlog_.reserve(kFrameTimeBacklogMax);
 
   // Storage for retrieving fence info.
   FenceInfoBuffer fence_info_buffer;
 
+  bool was_running = false;
+
   while (1) {
     ATRACE_NAME("HardwareComposer::PostThread");
 
     {
-      std::unique_lock<std::mutex> post_thread_lock(post_thread_state_mutex_);
-      if (post_thread_state_ == PostThreadState::kPauseRequested) {
-        ALOGI("HardwareComposer::PostThread: Post thread pause requested.");
-        post_thread_state_ = PostThreadState::kPaused;
-        post_thread_state_cond_var_.notify_all();
-        post_thread_state_cond_var_.wait(
-            post_thread_lock,
-            [this] { return post_thread_state_ == PostThreadState::kRunning; });
-        // The layers will need to be updated since they were deleted previously
-        display_surfaces_updated_ = true;
-        hardware_layers_need_update_ = true;
+      std::unique_lock<std::mutex> lock(post_thread_mutex_);
+      while (!post_thread_enabled_ || post_thread_quit_requested_ ||
+             !PostThreadHasWork()) {
+        if (was_running) {
+          const char* pause_reason = "unknown";
+          if (!post_thread_enabled_)
+            pause_reason = "disabled";
+          else if (post_thread_quit_requested_)
+            pause_reason = "quit requested";
+          else if (!PostThreadHasWork())
+            pause_reason = "no work";
+          ALOGI("VrHwcPost thread paused. Reason: %s.", pause_reason);
+          OnPostThreadPaused();
+          was_running = false;
+        }
+        post_thread_running_ = false;
+        post_thread_cond_var_.notify_all();
+        if (post_thread_quit_requested_)
+          return;
+        post_thread_cond_var_.wait(lock);
       }
+      post_thread_running_ = true;
+    }
+
+    if (!was_running) {
+      ALOGI("VrHwcPost thread resumed");
+      OnPostThreadResumed();
+      was_running = true;
     }
 
     int64_t vsync_timestamp = 0;
@@ -887,22 +845,13 @@
           error < 0,
           "HardwareComposer::PostThread: Failed to wait for vsync event: %s",
           strerror(-error));
-
       // Don't bother processing this frame if a pause was requested
-      std::lock_guard<std::mutex> post_thread_lock(post_thread_state_mutex_);
-      if (post_thread_state_ == PostThreadState::kPauseRequested) {
+      if (error == kPostThreadInterrupted)
         continue;
-      }
     }
 
     ++vsync_count_;
 
-    static double last_print_time = -1;
-    double current_time = GetSystemClockSec();
-    if (last_print_time < 0 || current_time - last_print_time > 3) {
-      last_print_time = current_time;
-    }
-
     if (pose_client_) {
       // Signal the pose service with vsync info.
       // Display timestamp is in the middle of scanout.
@@ -911,24 +860,24 @@
                                 ns_per_frame, right_eye_photon_offset_ns);
     }
 
-    bool layer_config_changed = UpdateLayerConfig(&compositor_surfaces);
+    bool layer_config_changed = UpdateLayerConfig();
 
-    if (layer_config_changed) {
-      frame_time_history.ResetWithSeed(
-          GuessFrameTime(compositor_surfaces.size()));
-      frame_time_backlog.clear();
+    if (!was_running || layer_config_changed) {
+      frame_time_history_.ResetWithSeed(
+          GuessFrameTime(compositor_surfaces_.size()));
+      frame_time_backlog_.clear();
     } else {
-      UpdateFrameTimeHistory(&frame_time_backlog, kFrameTimeBacklogMax,
-                             &fence_info_buffer, &frame_time_history);
+      UpdateFrameTimeHistory(&frame_time_backlog_, kFrameTimeBacklogMax,
+                             &fence_info_buffer, &frame_time_history_);
     }
 
     // Get our current best estimate at how long the next frame will take to
     // render, based on how long previous frames took to render. Use this
     // estimate to decide when to wake up for EDS.
     int64_t frame_time_estimate =
-        frame_time_history.GetSampleCount() == 0
-            ? GuessFrameTime(compositor_surfaces.size())
-            : frame_time_history.GetAverage();
+        frame_time_history_.GetSampleCount() == 0
+            ? GuessFrameTime(compositor_surfaces_.size())
+            : frame_time_history_.GetAverage();
     frame_time_estimate = std::max(frame_time_estimate, kFrameTimeEstimateMin);
     DebugHudData::data.hwc_latency = frame_time_estimate;
 
@@ -958,9 +907,9 @@
 
         // There are several reasons we might skip a frame, but one possibility
         // is we mispredicted the frame time. Clear out the frame time history.
-        frame_time_history.ResetWithSeed(
-            GuessFrameTime(compositor_surfaces.size()));
-        frame_time_backlog.clear();
+        frame_time_history_.ResetWithSeed(
+            GuessFrameTime(compositor_surfaces_.size()));
+        frame_time_backlog_.clear();
         DebugHudData::data.hwc_frame_stats.SkipFrame();
 
         continue;
@@ -974,6 +923,8 @@
         error = SleepUntil(display_time_est - frame_time_estimate);
         ALOGE_IF(error < 0, "HardwareComposer::PostThread: Failed to sleep: %s",
                  strerror(-error));
+        if (error == kPostThreadInterrupted)
+          continue;
       }
     }
 
@@ -992,7 +943,7 @@
     // permanently backed up.
     PostLayers(layer_config_changed);
 
-    PostCompositorBuffers(compositor_surfaces);
+    PostCompositorBuffers();
 
     if (gpu_layer_ != nullptr) {
       // Note, with scanline racing, this draw is timed along with the post
@@ -1000,55 +951,88 @@
       LocalHandle frame_fence_fd;
       compositor_.DrawFrame(vsync_count_ + 1, &frame_fence_fd);
       if (frame_fence_fd) {
-        LOG_ALWAYS_FATAL_IF(frame_time_backlog.size() >= kFrameTimeBacklogMax,
+        LOG_ALWAYS_FATAL_IF(frame_time_backlog_.size() >= kFrameTimeBacklogMax,
                             "Frame time backlog exceeds capacity");
-        frame_time_backlog.push_back(
+        frame_time_backlog_.push_back(
             {frame_start_time, std::move(frame_fence_fd)});
       }
     } else if (!layer_config_changed) {
-      frame_time_history.AddSample(GetSystemClockNs() - frame_start_time);
+      frame_time_history_.AddSample(GetSystemClockNs() - frame_start_time);
     }
 
     HandlePendingScreenshots();
   }
-
-  // TODO(skiazyk): Currently the compositor is not fully releasing its EGL
-  // context, which seems to prevent the thread from exiting properly.
-  // This shouldn't be too hard to address, I just don't have time right now.
-  compositor_.Shutdown();
 }
 
-bool HardwareComposer::UpdateLayerConfig(
-    std::vector<std::shared_ptr<DisplaySurface>>* compositor_surfaces) {
-  std::lock_guard<std::mutex> layer_lock(layer_mutex_);
+bool HardwareComposer::UpdateLayerConfig() {
+  std::vector<std::shared_ptr<DisplaySurface>> old_display_surfaces;
+  {
+    std::lock_guard<std::mutex> lock(post_thread_mutex_);
+    if (!active_surfaces_updated_)
+      return false;
+    old_display_surfaces = display_surfaces_;
+    display_surfaces_ = active_surfaces_;
+    active_surfaces_updated_ = false;
+  }
 
-  if (!display_surfaces_updated_)
-    return false;
-
-  display_surfaces_updated_ = false;
   DebugHudData::data.ResetLayers();
 
+  // Figure out whether we need to update hardware layers. If this surface
+  // change does not add or remove hardware layers we can avoid display hiccups
+  // by gracefully updating only the GPU compositor layers.
+  int old_gpu_layer_count = 0;
+  int new_gpu_layer_count = 0;
+  bool hardware_layers_need_update = false;
+  // Look for new hardware layers and count new GPU layers.
+  for (const auto& surface : display_surfaces_) {
+    if (!(surface->flags() &
+          DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_DISTORTION))
+      ++new_gpu_layer_count;
+    else if (std::find(old_display_surfaces.begin(), old_display_surfaces.end(),
+                       surface) == old_display_surfaces.end())
+      // This is a new hardware layer, we need to update.
+      hardware_layers_need_update = true;
+  }
+  // Look for deleted hardware layers or compositor layers.
+  for (const auto& surface : old_display_surfaces) {
+    if (!(surface->flags() &
+          DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_DISTORTION))
+      ++old_gpu_layer_count;
+    else if (std::find(display_surfaces_.begin(), display_surfaces_.end(),
+                       surface) == display_surfaces_.end())
+      // This is a deleted hardware layer, we need to update.
+      hardware_layers_need_update = true;
+  }
+  // Check for compositor hardware layer transition.
+  if ((!old_gpu_layer_count && new_gpu_layer_count) ||
+      (old_gpu_layer_count && !new_gpu_layer_count))
+    hardware_layers_need_update = true;
+
+  // Set the chosen layer order for all surfaces.
+  for (size_t i = 0; i < display_surfaces_.size(); ++i) {
+    display_surfaces_[i]->SetLayerOrder(static_cast<int>(i));
+  }
+
   // Update compositor layers.
   {
     ATRACE_NAME("UpdateLayerConfig_GpuLayers");
     compositor_.UpdateSurfaces(display_surfaces_);
-    compositor_surfaces->clear();
+    compositor_surfaces_.clear();
     for (size_t i = 0; i < display_surfaces_.size(); ++i) {
       const auto& surface = display_surfaces_[i];
       if (!(surface->flags() &
             DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_DISTORTION)) {
-        compositor_surfaces->push_back(surface);
+        compositor_surfaces_.push_back(surface);
       }
     }
   }
 
-  if (!hardware_layers_need_update_)
+  if (!hardware_layers_need_update)
     return true;
 
   // Update hardware layers.
 
   ATRACE_NAME("UpdateLayerConfig_HwLayers");
-  hardware_layers_need_update_ = false;
 
   // Update the display layers in a non-destructive fashion.
 
@@ -1179,10 +1163,9 @@
   return true;
 }
 
-void HardwareComposer::PostCompositorBuffers(
-    const std::vector<std::shared_ptr<DisplaySurface>>& compositor_surfaces) {
+void HardwareComposer::PostCompositorBuffers() {
   ATRACE_NAME("PostCompositorBuffers");
-  for (const auto& surface : compositor_surfaces) {
+  for (const auto& surface : compositor_surfaces_) {
     compositor_.PostBuffer(surface);
   }
 }
@@ -1485,6 +1468,8 @@
     handle = acquired_buffer_.buffer()->native_handle();
     acquire_fence_fd_.Reset(acquired_buffer_.ClaimAcquireFence().Release());
   } else {
+    // TODO(jwcai) Note: this is the GPU compositor's layer, and we need the
+    // mechanism to accept distorted layers from VrCore.
     right = direct_buffer_->width();
     bottom = direct_buffer_->height();
     handle = direct_buffer_->handle();
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index e2a8b90..e570cb6 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -176,6 +176,12 @@
 
 // HardwareComposer encapsulates the hardware composer HAL, exposing a
 // simplified API to post buffers to the display.
+//
+// HardwareComposer is accessed by both the vr flinger dispatcher thread and the
+// surface flinger main thread, in addition to internally running a separate
+// thread for compositing/EDS and posting layers to the HAL. When changing how
+// variables are used or adding new state think carefully about which threads
+// will access the state and whether it needs to be synchronized.
 class HardwareComposer {
  public:
   // Type for vsync callback.
@@ -193,8 +199,12 @@
 
   bool IsInitialized() const { return initialized_; }
 
-  bool Suspend();
-  bool Resume();
+  // Start the post thread if there's work to do (i.e. visible layers). This
+  // should only be called from surface flinger's main thread.
+  void Enable();
+  // Pause the post thread, blocking until the post thread has signaled that
+  // it's paused. This should only be called from surface flinger's main thread.
+  void Disable();
 
   // Get the HMD display metrics for the current display.
   DisplayMetrics GetHmdDisplayMetrics() const;
@@ -219,12 +229,9 @@
     return native_display_metrics_;
   }
 
-  std::shared_ptr<IonBuffer> framebuffer_target() const {
-    return framebuffer_target_;
-  }
-
   // Set the display surface stack to compose to the display each frame.
-  int SetDisplaySurfaces(std::vector<std::shared_ptr<DisplaySurface>> surfaces);
+  void SetDisplaySurfaces(
+      std::vector<std::shared_ptr<DisplaySurface>> surfaces);
 
   Compositor* GetCompositor() { return &compositor_; }
 
@@ -266,8 +273,21 @@
   void PostLayers(bool is_geometry_changed);
   void PostThread();
 
+  // Check to see if we have a value written to post_thread_interrupt_event_fd_,
+  // indicating a control thread interrupted the post thread. This clears the
+  // post_thread_interrupt_event_fd_ state in the process. Returns true if an
+  // interrupt was requested.
+  bool CheckPostThreadInterruptEventFd();
+  // Blocks until either event_fd becomes readable, or we're interrupted by a
+  // control thread. Any errors are returned as negative errno values. If we're
+  // interrupted, kPostThreadInterrupted will be returned.
+  int PostThreadPollInterruptible(int event_fd, int requested_events);
+
+  // BlockUntilVSync, WaitForVSync, and SleepUntil are all blocking calls made
+  // on the post thread that can be interrupted by a control thread. If
+  // interrupted, these calls return kPostThreadInterrupted.
   int ReadWaitPPState();
-  int BlockUntilVSync(/*out*/ bool* suspend_requested);
+  int BlockUntilVSync();
   int ReadVSyncTimestamp(int64_t* timestamp);
   int WaitForVSync(int64_t* timestamp);
   int SleepUntil(int64_t wakeup_timestamp);
@@ -275,12 +295,18 @@
   bool IsFramePendingInDriver() { return ReadWaitPPState() == 1; }
 
   // Returns true if the layer config changed, false otherwise
-  bool UpdateLayerConfig(
-      std::vector<std::shared_ptr<DisplaySurface>>* compositor_surfaces);
-  void PostCompositorBuffers(
-      const std::vector<std::shared_ptr<DisplaySurface>>& compositor_surfaces);
+  bool UpdateLayerConfig();
+  void PostCompositorBuffers();
 
-  void UpdateDisplayState();
+  // Return true if the post thread has work to do (i.e. there are visible
+  // surfaces to post to the screen). Must be called with post_thread_mutex_
+  // locked. Called only from the post thread.
+  bool PostThreadHasWork();
+
+  // Called on the post thread when the post thread is resumed.
+  void OnPostThreadResumed();
+  // Called on the post thread when the post thread is paused or quits.
+  void OnPostThreadPaused();
 
   struct FrameTimeMeasurementRecord {
     int64_t start_time;
@@ -324,14 +350,28 @@
   // Buffer for the background layer required by hardware composer.
   std::shared_ptr<IonBuffer> framebuffer_target_;
 
-  // Protects access to the display surfaces and logical layers.
-  std::mutex layer_mutex_;
+  // Protects access to variables used by the post thread and one of the control
+  // threads (either the vr flinger dispatcher thread or the surface flinger
+  // main thread). This includes active_surfaces_, active_surfaces_updated_,
+  // post_thread_enabled_, post_thread_running_, and
+  // post_thread_quit_requested_.
+  std::mutex post_thread_mutex_;
 
-  // Active display surfaces configured by the display manager.
+  // Surfaces configured by the display manager. Written by the vr flinger
+  // dispatcher thread, read by the post thread.
+  std::vector<std::shared_ptr<DisplaySurface>> active_surfaces_;
+  // active_surfaces_updated_ is set to true by the vr flinger dispatcher thread
+  // when the list of active surfaces changes. active_surfaces_updated_ will be
+  // set back to false by the post thread when it processes the update.
+  bool active_surfaces_updated_;
+
+  // The surfaces displayed by the post thread. Used exclusively by the post
+  // thread.
   std::vector<std::shared_ptr<DisplaySurface>> display_surfaces_;
-  std::vector<std::shared_ptr<DisplaySurface>> added_display_surfaces_;
-  bool display_surfaces_updated_;
-  bool hardware_layers_need_update_;
+
+  // The surfaces rendered by the compositor. Used exclusively by the post
+  // thread.
+  std::vector<std::shared_ptr<DisplaySurface>> compositor_surfaces_;
 
   // Layer array for handling buffer flow into hardware composer layers.
   // Note that the first array is the actual storage for the layer objects,
@@ -352,31 +392,22 @@
   // hand buffers to post processing and the results to hardware composer.
   std::thread post_thread_;
 
-  enum class PostThreadState {
-    // post_thread_state_ starts off paused. When suspending, the control thread
-    // will block until post_thread_state_ == kPaused, indicating the post
-    // thread has completed the transition to paused (most importantly: no more
-    // hardware composer calls).
-    kPaused,
-    // post_thread_state_ is set to kRunning by the control thread (either
-    // surface flinger's main thread or the vr flinger dispatcher thread). The
-    // post thread blocks until post_thread_state_ == kRunning.
-    kRunning,
-    // Set by the control thread to indicate the post thread should pause. The
-    // post thread will change post_thread_state_ from kPauseRequested to
-    // kPaused when it stops.
-    kPauseRequested
-  };
-  // Control variables to control the state of the post thread
-  PostThreadState post_thread_state_;
-  // Used to wake the post thread up while it's waiting for vsync, for faster
-  // transition to the paused state.
-  pdx::LocalHandle terminate_post_thread_event_fd_;
-  // post_thread_state_mutex_ should be held before checking or modifying
-  // post_thread_state_.
-  std::mutex post_thread_state_mutex_;
+  // Set to true if the post thread is allowed to run. Surface flinger and vr
+  // flinger share access to the display, and vr flinger shouldn't use the
+  // display while surface flinger is using it. While surface flinger owns the
+  // display, post_thread_enabled_ will be set to false to indicate the post
+  // thread shouldn't run.
+  bool post_thread_enabled_;
+  // Set to true by the post thread if it's currently running.
+  bool post_thread_running_;
+  // Set to true if the post thread should quit. Only set when destroying the
+  // HardwareComposer instance.
+  bool post_thread_quit_requested_;
+  // Used to wake the post thread up while it's waiting for vsync or sleeping
+  // until EDS preemption, for faster transition to the paused state.
+  pdx::LocalHandle post_thread_interrupt_event_fd_;
   // Used to communicate between the control thread and the post thread.
-  std::condition_variable post_thread_state_cond_var_;
+  std::condition_variable post_thread_cond_var_;
 
   // Backlight LED brightness sysfs node.
   pdx::LocalHandle backlight_brightness_fd_;
@@ -410,6 +441,17 @@
   // out to display frame boundaries, so we need to tell it about vsyncs.
   DvrPose* pose_client_;
 
+  // Our history of frame times. This is used to get a better estimate of how
+  // long the next frame will take, to set a schedule for EDS.
+  FrameTimeHistory frame_time_history_;
+
+  // The backlog is used to allow us to start rendering the next frame before
+  // the previous frame has finished, and still get an accurate measurement of
+  // frame duration.
+  std::vector<FrameTimeMeasurementRecord> frame_time_backlog_;
+
+  static constexpr int kPostThreadInterrupted = 1;
+
   static void HwcRefresh(hwc2_callback_data_t data, hwc2_display_t display);
   static void HwcVSync(hwc2_callback_data_t data, hwc2_display_t display,
                        int64_t timestamp);
diff --git a/libs/vr/libvrflinger/include/dvr/vr_flinger.h b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
index 17dce96..145852e 100644
--- a/libs/vr/libvrflinger/include/dvr/vr_flinger.h
+++ b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
@@ -4,6 +4,9 @@
 #include <thread>
 #include <memory>
 
+#include <pdx/default_transport/service_dispatcher.h>
+#include <vr/vr_manager/vr_manager.h>
+
 namespace android {
 
 namespace Hwc2 {
@@ -16,16 +19,39 @@
 
 class VrFlinger {
  public:
-  VrFlinger();
-  int Run(Hwc2::Composer* hidl);
+  using RequestDisplayCallback = std::function<void(bool)>;
+  static std::unique_ptr<VrFlinger> Create(
+      Hwc2::Composer* hidl, RequestDisplayCallback request_display_callback);
+  ~VrFlinger();
 
-  void EnterVrMode();
-  void ExitVrMode();
+  // These functions are all called on surface flinger's main thread.
+  void OnBootFinished();
+  void GrantDisplayOwnership();
+  void SeizeDisplayOwnership();
+
+  // Called on a binder thread.
   void OnHardwareComposerRefresh();
 
  private:
-  std::thread displayd_thread_;
+  VrFlinger();
+  bool Init(Hwc2::Composer* hidl,
+            RequestDisplayCallback request_display_callback);
+
+  // Needs to be a separate class for binder's ref counting
+  class PersistentVrStateCallback : public BnPersistentVrStateCallbacks {
+   public:
+    PersistentVrStateCallback(RequestDisplayCallback request_display_callback)
+        : request_display_callback_(request_display_callback) {}
+    void onPersistentVrStateChanged(bool enabled) override;
+   private:
+    RequestDisplayCallback request_display_callback_;
+  };
+
+  std::thread dispatcher_thread_;
+  std::unique_ptr<android::pdx::ServiceDispatcher> dispatcher_;
   std::shared_ptr<android::dvr::DisplayService> display_service_;
+  sp<PersistentVrStateCallback> persistent_vr_state_callback_;
+  RequestDisplayCallback request_display_callback_;
 };
 
 } // namespace dvr
diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp
index 9163e71..21226db 100644
--- a/libs/vr/libvrflinger/vr_flinger.cpp
+++ b/libs/vr/libvrflinger/vr_flinger.cpp
@@ -9,11 +9,13 @@
 #include <unistd.h>
 #include <memory>
 
+#include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
 #include <log/log.h>
 #include <cutils/properties.h>
 #include <cutils/sched_policy.h>
 #include <private/dvr/display_client.h>
+#include <sys/prctl.h>
 #include <sys/resource.h>
 
 #include <pdx/default_transport/service_dispatcher.h>
@@ -29,11 +31,37 @@
 namespace android {
 namespace dvr {
 
+std::unique_ptr<VrFlinger> VrFlinger::Create(
+    Hwc2::Composer* hidl, RequestDisplayCallback request_display_callback) {
+  std::unique_ptr<VrFlinger> vr_flinger(new VrFlinger);
+  if (vr_flinger->Init(hidl, request_display_callback))
+    return vr_flinger;
+  else
+    return nullptr;
+}
+
 VrFlinger::VrFlinger() {}
 
-int VrFlinger::Run(Hwc2::Composer* hidl) {
-  if (!hidl)
-    return EINVAL;
+VrFlinger::~VrFlinger() {
+  if (persistent_vr_state_callback_.get()) {
+    sp<IVrManager> vr_manager = interface_cast<IVrManager>(
+        defaultServiceManager()->checkService(String16("vrmanager")));
+    if (vr_manager.get()) {
+      vr_manager->unregisterPersistentVrStateListener(
+          persistent_vr_state_callback_);
+    }
+  }
+
+  if (dispatcher_)
+    dispatcher_->SetCanceled(true);
+  if (dispatcher_thread_.joinable())
+    dispatcher_thread_.join();
+}
+
+bool VrFlinger::Init(Hwc2::Composer* hidl,
+                     RequestDisplayCallback request_display_callback) {
+  if (!hidl || !request_display_callback)
+    return false;
 
   std::shared_ptr<android::pdx::Service> service;
 
@@ -47,25 +75,27 @@
 
   android::ProcessState::self()->startThreadPool();
 
-  std::shared_ptr<android::pdx::ServiceDispatcher> dispatcher =
+  request_display_callback_ = request_display_callback;
+
+  dispatcher_ =
       android::pdx::default_transport::ServiceDispatcher::Create();
-  CHECK_ERROR(!dispatcher, error, "Failed to create service dispatcher.");
+  CHECK_ERROR(!dispatcher_, error, "Failed to create service dispatcher.");
 
   display_service_ = android::dvr::DisplayService::Create(hidl);
   CHECK_ERROR(!display_service_, error, "Failed to create display service.");
-  dispatcher->AddService(display_service_);
+  dispatcher_->AddService(display_service_);
 
   service = android::dvr::DisplayManagerService::Create(display_service_);
   CHECK_ERROR(!service, error, "Failed to create display manager service.");
-  dispatcher->AddService(service);
+  dispatcher_->AddService(service);
 
   service = android::dvr::ScreenshotService::Create();
   CHECK_ERROR(!service, error, "Failed to create screenshot service.");
-  dispatcher->AddService(service);
+  dispatcher_->AddService(service);
 
   service = android::dvr::VSyncService::Create();
   CHECK_ERROR(!service, error, "Failed to create vsync service.");
-  dispatcher->AddService(service);
+  dispatcher_->AddService(service);
 
   display_service_->SetVSyncCallback(
       std::bind(&android::dvr::VSyncService::VSyncEvent,
@@ -73,45 +103,51 @@
                 std::placeholders::_1, std::placeholders::_2,
                 std::placeholders::_3, std::placeholders::_4));
 
-  displayd_thread_ = std::thread([this, dispatcher]() {
+  dispatcher_thread_ = std::thread([this]() {
+    prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("VrDispatch"), 0, 0, 0);
     ALOGI("Entering message loop.");
 
-    int ret = dispatcher->EnterDispatchLoop();
+    int ret = dispatcher_->EnterDispatchLoop();
     if (ret < 0) {
       ALOGE("Dispatch loop exited because: %s\n", strerror(-ret));
     }
   });
 
-  return NO_ERROR;
+  return true;
 
 error:
-  display_service_.reset();
-
-  return -1;
+  return false;
 }
 
-void VrFlinger::EnterVrMode() {
-  if (display_service_) {
-    display_service_->SetActive(true);
+void VrFlinger::OnBootFinished() {
+  sp<IVrManager> vr_manager = interface_cast<IVrManager>(
+      defaultServiceManager()->checkService(String16("vrmanager")));
+  if (vr_manager.get()) {
+    persistent_vr_state_callback_ =
+        new PersistentVrStateCallback(request_display_callback_);
+    vr_manager->registerPersistentVrStateListener(
+        persistent_vr_state_callback_);
   } else {
-    ALOGE("Failed to enter VR mode : Display service is not started.");
+    ALOGE("Unable to register vr flinger for persistent vr mode changes");
   }
 }
 
-void VrFlinger::ExitVrMode() {
-  if (display_service_) {
-    display_service_->SetActive(false);
-  } else {
-    ALOGE("Failed to exit VR mode : Display service is not started.");
-  }
+void VrFlinger::GrantDisplayOwnership() {
+  display_service_->GrantDisplayOwnership();
+}
+
+void VrFlinger::SeizeDisplayOwnership() {
+  display_service_->SeizeDisplayOwnership();
 }
 
 void VrFlinger::OnHardwareComposerRefresh() {
-  if (display_service_) {
-    display_service_->OnHardwareComposerRefresh();
-  } else {
-    ALOGE("OnHardwareComposerRefresh failed : Display service is not started.");
-  }
+  display_service_->OnHardwareComposerRefresh();
+}
+
+void VrFlinger::PersistentVrStateCallback::onPersistentVrStateChanged(
+    bool enabled) {
+  ALOGV("Notified persistent vr mode is %s", enabled ? "on" : "off");
+  request_display_callback_(enabled);
 }
 
 }  // namespace dvr
diff --git a/libs/vr/libvrsensor/Android.bp b/libs/vr/libvrsensor/Android.bp
index 376630e..6d48f18 100644
--- a/libs/vr/libvrsensor/Android.bp
+++ b/libs/vr/libvrsensor/Android.bp
@@ -23,6 +23,7 @@
 
 staticLibraries = [
     "libbufferhub",
+    "libbufferhubqueue",
     "libdvrcommon",
     "libpdx_default_transport",
 ]
@@ -33,6 +34,7 @@
     "libhardware",
     "liblog",
     "libutils",
+    "libui",
 ]
 
 cc_library {
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 4c4cd4e..bf831a7 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -605,20 +605,6 @@
 #endif
 #endif
 
-#ifndef EGL_ANDROID_create_native_client_buffer
-#define EGL_ANDROID_create_native_client_buffer 1
-#define EGL_LAYER_COUNT_ANDROID 0x3434
-#define EGL_NATIVE_BUFFER_USAGE_ANDROID   0x3143
-#define EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID   0x00000001
-#define EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID   0x00000002
-#define EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID   0x00000004
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLClientBuffer eglCreateNativeClientBufferANDROID (const EGLint *attrib_list);
-#else
-typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLCREATENATIVECLIENTBUFFERANDROID) (const EGLint *attrib_list);
-#endif
-#endif
-
 #ifndef EGL_ANDROID_get_native_client_buffer
 #define EGL_ANDROID_get_native_client_buffer 1
 struct AHardwareBuffer;
@@ -652,9 +638,8 @@
 #define EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3155
 #define EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID 0x3156
 #define EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3157
-#define EGL_DISPLAY_RETIRE_TIME_ANDROID 0x3158
-#define EGL_DEQUEUE_READY_TIME_ANDROID 0x3159
-#define EGL_READS_DONE_TIME_ANDROID 0x315A
+#define EGL_DEQUEUE_READY_TIME_ANDROID 0x3158
+#define EGL_READS_DONE_TIME_ANDROID 0x3159
 #ifdef EGL_EGLEXT_PROTOTYPES
 EGLAPI EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR *frameId);
 EGLAPI EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy, EGLSurface surface, EGLint numTimestamps, const EGLint *names, EGLnsecsANDROID *values);
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index d124c89..b00d401 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -2075,7 +2075,6 @@
     nsecs_t* gpuCompositionDoneTime = nullptr;
     nsecs_t* lastRefreshStartTime = nullptr;
     nsecs_t* displayPresentTime = nullptr;
-    nsecs_t* displayRetireTime = nullptr;
     nsecs_t* dequeueReadyTime = nullptr;
     nsecs_t* releaseTime = nullptr;
 
@@ -2102,9 +2101,6 @@
             case EGL_DISPLAY_PRESENT_TIME_ANDROID:
                 displayPresentTime = &values[i];
                 break;
-            case EGL_DISPLAY_RETIRE_TIME_ANDROID:
-                displayRetireTime = &values[i];
-                break;
             case EGL_DEQUEUE_READY_TIME_ANDROID:
                 dequeueReadyTime = &values[i];
                 break;
@@ -2119,7 +2115,7 @@
     int ret = native_window_get_frame_timestamps(s->getNativeWindow(), frameId,
             requestedPresentTime, acquireTime, latchTime, firstRefreshStartTime,
             lastRefreshStartTime, gpuCompositionDoneTime, displayPresentTime,
-            displayRetireTime, dequeueReadyTime, releaseTime);
+            dequeueReadyTime, releaseTime);
 
     switch (ret) {
         case 0:
@@ -2170,19 +2166,10 @@
         case EGL_FIRST_COMPOSITION_START_TIME_ANDROID:
         case EGL_LAST_COMPOSITION_START_TIME_ANDROID:
         case EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID:
+        case EGL_DISPLAY_PRESENT_TIME_ANDROID:
         case EGL_DEQUEUE_READY_TIME_ANDROID:
         case EGL_READS_DONE_TIME_ANDROID:
             return EGL_TRUE;
-        case EGL_DISPLAY_PRESENT_TIME_ANDROID: {
-            int value = 0;
-            window->query(window, NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT, &value);
-            return value == 0 ? EGL_FALSE : EGL_TRUE;
-        }
-        case EGL_DISPLAY_RETIRE_TIME_ANDROID: {
-            int value = 0;
-            window->query(window, NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_RETIRE, &value);
-            return value == 0 ? EGL_FALSE : EGL_TRUE;
-        }
         default:
             return EGL_FALSE;
     }
diff --git a/opengl/specs/EGL_ANDROID_create_native_client_buffer.txt b/opengl/specs/EGL_ANDROID_create_native_client_buffer.txt
deleted file mode 100644
index 4c5551c..0000000
--- a/opengl/specs/EGL_ANDROID_create_native_client_buffer.txt
+++ /dev/null
@@ -1,199 +0,0 @@
-Name
-
-    ANDROID_create_native_client_buffer
-
-Name Strings
-
-    EGL_ANDROID_create_native_client_buffer
-
-Contributors
-
-    Craig Donner
-
-Contact
-
-    Craig Donner, Google Inc. (cdonner 'at' google.com)
-
-Status
-
-    Draft
-
-Version
-
-    Version 1.1, October 26, 2016
-
-Number
-
-    EGL Extension #XXX
-
-Dependencies
-
-    Requires EGL 1.2.
-
-    EGL_ANDROID_image_native_buffer and EGL_KHR_image_base are required.
-
-    This extension is written against the wording of the EGL 1.2
-    Specification as modified by EGL_KHR_image_base and
-    EGL_ANDROID_image_native_buffer.
-
-Overview
-
-    This extension allows creating an EGLClientBuffer backed by an Android
-    window buffer (struct ANativeWindowBuffer) which can be later used to
-    create an EGLImage.
-
-New Types
-
-    None.
-
-New Procedures and Functions
-
-EGLClientBuffer eglCreateNativeClientBufferANDROID(
-                        const EGLint *attrib_list)
-
-New Tokens
-
-    EGL_NATIVE_BUFFER_LAYER_COUNT_ANDROID 0x3434
-    EGL_NATIVE_BUFFER_USAGE_ANDROID 0x3143
-    EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID 0x00000001
-    EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID 0x00000002
-    EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID 0x00000004
-
-Changes to Chapter 3 of the EGL 1.2 Specification (EGL Functions and Errors)
-
-    Add the following to section 2.5.1 "EGLImage Specification" (as modified by
-    the EGL_KHR_image_base and EGL_ANDROID_image_native_buffer specifications),
-    below the description of eglCreateImageKHR:
-
-   "The command
-
-        EGLClientBuffer eglCreateNativeClientBufferANDROID(
-                                const EGLint *attrib_list)
-
-    may be used to create an EGLClientBuffer backed by an ANativeWindowBuffer
-    struct. EGL implementations must guarantee that the lifetime of the
-    returned EGLClientBuffer is at least as long as the EGLImage(s) it is bound
-    to, following the lifetime semantics described below in section 2.5.2; the
-    EGLClientBuffer must be destroyed no earlier than when all of its associated
-    EGLImages are destroyed by eglDestroyImageKHR. <attrib_list> is a list of
-    attribute-value pairs which is used to specify the dimensions, format, and
-    usage of the underlying buffer structure. If <attrib_list> is non-NULL, the
-    last attribute specified in the list must be EGL_NONE.
-
-    Attribute names accepted in <attrib_list> are shown in Table aaa,
-    together with the <target> for which each attribute name is valid, and
-    the default value used for each attribute if it is not included in
-    <attrib_list>.
-
-      +---------------------------------+----------------------+---------------+
-      | Attribute                       | Description          | Default Value |
-      |                                 |                      |               |
-      +---------------------------------+----------------------+---------------+
-      | EGL_NONE                        | Marks the end of the | N/A           |
-      |                                 | attribute-value list |               |
-      | EGL_WIDTH                       | The width of the     | 0             |
-      |                                 | buffer data          |               |
-      | EGL_HEIGHT                      | The height of the    | 0             |
-      |                                 | buffer data          |               |
-      | EGL_RED_SIZE                    | The bits of Red in   | 0             |
-      |                                 | the color buffer     |               |
-      | EGL_GREEN_SIZE                  | The bits of Green in | 0             |
-      |                                 | the color buffer     |               |
-      | EGL_BLUE_SIZE                   | The bits of Blue in  | 0             |
-      |                                 | the color buffer     |               |
-      | EGL_ALPHA_SIZE                  | The bits of Alpha in | 0             |
-      |                                 | the color buffer     |               |
-      |                                 | buffer data          |               |
-      | EGL_LAYER_COUNT_ANDROID         | The number of image  | 1             |
-      |                                 | layers in the buffer |               |
-      | EGL_NATIVE_BUFFER_USAGE_ANDROID | The usage bits of    | 0             |
-      |                                 | the buffer data      |               |
-      +---------------------------------+----------------------+---------------+
-       Table aaa.  Legal attributes for eglCreateNativeClientBufferANDROID
-       <attrib_list> parameter.
-
-    The maximum width and height may depend on the amount of available memory,
-    which may also depend on the format and usage flags. The values of
-    EGL_RED_SIZE, EGL_GREEN_SIZE, and EGL_BLUE_SIZE must be non-zero and
-    correspond to a valid pixel format for the implementation. If EGL_ALPHA_SIZE
-    is non-zero then the combination of all four sizes must correspond to a
-    valid pixel format for the implementation. The value of
-    EGL_LAYER_COUNT_ANDROID must be a valid number of image layers for the
-    implementation. The EGL_NATIVE_BUFFER_USAGE_ANDROID flag may include any of
-    the following bits:
-
-        EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID: Indicates that the
-        created buffer must have a hardware-protected path to external display
-        sink. If a hardware-protected path is not available, then either don't
-        composite only this buffer (preferred) to the external sink, or (less
-        desirable) do not route the entire composition to the external sink.
-
-        EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID: The buffer will be
-        used to create a color-renderable texture.
-
-        EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID: The buffer will be used to
-        create a filterable texture.
-
-    Errors
-
-        If eglCreateNativeClientBufferANDROID fails, NULL will be returned, no
-        memory will be allocated, and one of the following errors will be
-        generated:
-
-       * If the value of EGL_WIDTH or EGL_HEIGHT is not positive, the error
-         EGL_BAD_PARAMETER is generated.
-
-       * If the combination of the values of EGL_RED_SIZE, EGL_GREEN_SIZE,
-         EGL_BLUE_SIZE, and EGL_ALPHA_SIZE is not a valid pixel format for the
-         EGL implementation, the error EGL_BAD_PARAMETER is generated.
-
-       * If the value of EGL_NATIVE_BUFFER_ANDROID is not a valid combination
-         of gralloc usage flags for the EGL implementation, or is incompatible
-         with the value of EGL_FORMAT, the error EGL_BAD_PARAMETER is
-         Generated.
-
-Issues
-
-    1. Should this extension define what combinations of formats and usage flags
-    EGL implementations are required to support?
-
-    RESOLVED: Partially.
-
-    The set of valid color combinations is implementation-specific and may
-    depend on additional EGL extensions, but generally RGB565 and RGBA888 should
-    be supported. The particular valid combinations for a given Android version
-    and implementation should be documented by that version.
-
-    2. Should there be an eglDestroyNativeClientBufferANDROID to destroy the
-    client buffers created by this extension?
-
-    RESOLVED: No.
-
-    A destroy function would add several complications:
-
-        a) ANativeWindowBuffer is a reference counted object, may be used
-           outside of EGL.
-        b) The same buffer may back multiple EGLImages, though this usage may
-           result in undefined behavior.
-        c) The interactions between the lifetimes of EGLImages and their
-           EGLClientBuffers would become needlessly complex.
-
-    Because ANativeWindowBuffer is a reference counted object, implementations
-    of this extension should ensure the buffer has a lifetime at least as long
-    as a generated EGLImage (via EGL_ANDROID_image_native_buffer). The simplest
-    method is to increment the reference count of the buffer in
-    eglCreateImagKHR, and then decrement it in eglDestroyImageKHR. This should
-    ensure proper lifetime semantics.
-
-Revision History
-
-#3 (Craig Donner, October 26, 2016)
-    - Added EGL_LAYER_COUNT_ANDROID for creating buffers that back texture
-    arrays.
-
-#2 (Craig Donner, April 15, 2016)
-    - Set color formats and usage bits explicitly using additional attributes,
-    and add value for new token EGL_NATIVE_BUFFER_USAGE_ANDROID.
-
-#1 (Craig Donner, January 19, 2016)
-    - Initial draft.
diff --git a/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
index e32d9e6..61b9b66 100644
--- a/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
+++ b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
@@ -46,8 +46,8 @@
     and display of window surfaces.
 
     Some examples of how this might be used:
-        - The display present or retire time can be used to calculate end-to-end
-          latency of the entire graphics pipeline.
+        - The display present time can be used to calculate end-to-end latency
+          of the entire graphics pipeline.
         - The queue time and rendering complete time can be used to determine
           how long the application's rendering took to complete. Likewise, the
           composition start time and finish time can be used to determine how
@@ -92,9 +92,8 @@
     EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3155
     EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID 0x3156
     EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3157
-    EGL_DISPLAY_RETIRE_TIME_ANDROID 0x3158
-    EGL_DEQUEUE_READY_TIME_ANDROID 0x3159
-    EGL_READS_DONE_TIME_ANDROID 0x315A
+    EGL_DEQUEUE_READY_TIME_ANDROID 0x3158
+    EGL_READS_DONE_TIME_ANDROID 0x3159
 
 Add to the list of supported tokens for eglSurfaceAttrib in section 3.5.6
 "Surface Attributes", page 43:
@@ -195,8 +194,6 @@
           didn't do any rendering.
         - EGL_DISPLAY_PRESENT_TIME_ANDROID - The time at which this frame
           started to scan out to the physical display.
-        - EGL_DISPLAY_RETIRE_TIME_ANDROID - The time at which this frame was
-          replaced by the next frame on-screen.
         - EGL_DEQUEUE_READY_TIME_ANDROID - The time when the buffer became
           available for reuse as a buffer the client can target without
           blocking. This is generally the point when all read commands of the
@@ -225,6 +222,9 @@
 
 Revision History
 
+#6 (Brian Anderson, March 16, 2017)
+    - Remove DISPLAY_RETIRE_TIME_ANDROID.
+
 #5 (Brian Anderson, January 13, 2017)
     - Add eglGetCompositorTimingANDROID.
 
diff --git a/opengl/specs/README b/opengl/specs/README
index a7a9785..e922740 100644
--- a/opengl/specs/README
+++ b/opengl/specs/README
@@ -9,7 +9,6 @@
 0x3140               EGL_NATIVE_BUFFER_ANDROID (EGL_ANDROID_image_native_buffer)
 0x3141               EGL_PLATFORM_ANDROID_KHR (KHR_platform_android)
 0x3142               EGL_RECORDABLE_ANDROID (EGL_ANDROID_recordable)
-0x3143               EGL_NATIVE_BUFFER_USAGE_ANDROID (EGL_ANDROID_create_native_client_buffer)
 0x3144               EGL_SYNC_NATIVE_FENCE_ANDROID (EGL_ANDROID_native_fence_sync)
 0x3145               EGL_SYNC_NATIVE_FENCE_FD_ANDROID (EGL_ANDROID_native_fence_sync)
 0x3146               EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID (EGL_ANDROID_native_fence_sync)
@@ -30,7 +29,6 @@
 0x3155               EGL_LAST_COMPOSITION_START_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
 0x3156               EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
 0x3157               EGL_DISPLAY_PRESENT_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3158               EGL_DISPLAY_RETIRE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x3159               EGL_DEQUEUE_READY_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x315A               EGL_READS_DONE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
-0x315B - 0x315F      (unused)
+0x3158               EGL_DEQUEUE_READY_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x3159               EGL_READS_DONE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps)
+0x315A - 0x315F      (unused)
diff --git a/services/batteryservice/IBatteryPropertiesRegistrar.cpp b/services/batteryservice/IBatteryPropertiesRegistrar.cpp
index 1fdda43..01a65ae 100644
--- a/services/batteryservice/IBatteryPropertiesRegistrar.cpp
+++ b/services/batteryservice/IBatteryPropertiesRegistrar.cpp
@@ -60,6 +60,12 @@
                 val->readFromParcel(&reply);
             return ret;
         }
+
+        void scheduleUpdate() {
+            Parcel data;
+            data.writeInterfaceToken(IBatteryPropertiesRegistrar::getInterfaceDescriptor());
+            remote()->transact(SCHEDULE_UPDATE, data, NULL);
+        }
 };
 
 IMPLEMENT_META_INTERFACE(BatteryPropertiesRegistrar, "android.os.IBatteryPropertiesRegistrar");
@@ -97,6 +103,12 @@
             val.writeToParcel(reply);
             return OK;
         }
+
+        case SCHEDULE_UPDATE: {
+            CHECK_INTERFACE(IBatteryPropertiesRegistrar, data, reply);
+            scheduleUpdate();
+            return OK;
+        }
     }
     return BBinder::onTransact(code, data, reply, flags);
 };
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index b8ca812..22a4616 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -2416,7 +2416,7 @@
             struct KeyReplacement replacement = {keyCode, args->deviceId};
             mReplacedKeys.add(replacement, newKeyCode);
             keyCode = newKeyCode;
-            metaState &= ~AMETA_META_ON;
+            metaState &= ~(AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
         }
     } else if (args->action == AKEY_EVENT_ACTION_UP) {
         // In order to maintain a consistent stream of up and down events, check to see if the key
@@ -2428,7 +2428,7 @@
         if (index >= 0) {
             keyCode = mReplacedKeys.valueAt(index);
             mReplacedKeys.removeItemsAt(index);
-            metaState &= ~AMETA_META_ON;
+            metaState &= ~(AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
         }
     }
 
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index a6ea750..647a4c0 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -53,7 +53,6 @@
     LOCAL_CFLAGS += -DUSE_HWC2
     LOCAL_SRC_FILES += \
         SurfaceFlinger.cpp \
-        VrStateCallbacks.cpp \
         DisplayHardware/HWComposer.cpp
     ifeq ($(TARGET_USES_HWC2ON1ADAPTER), true)
         LOCAL_CFLAGS += -DBYPASS_IHWC
@@ -65,10 +64,6 @@
         DisplayHardware/HWComposer_hwc1.cpp
 endif
 
-ifneq ($(NUM_FRAMEBUFFER_SURFACE_BUFFERS),)
-    LOCAL_CFLAGS += -DNUM_FRAMEBUFFER_SURFACE_BUFFERS=$(NUM_FRAMEBUFFER_SURFACE_BUFFERS)
-endif
-
 LOCAL_CFLAGS += -fvisibility=hidden -Werror=format
 
 LOCAL_HEADER_LIBRARIES := \
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 11df4e2..c3b48ca 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -64,9 +64,8 @@
 using namespace android::hardware::configstore;
 using namespace android::hardware::configstore::V1_0;
 
-static bool useTripleFramebuffer = getBool<
-        ISurfaceFlingerConfigs,
-        &ISurfaceFlingerConfigs::useTripleFramebuffer>(false);
+static bool useTripleFramebuffer = getInt64< ISurfaceFlingerConfigs,
+        &ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2) == 3;
 
 #if !defined(EGL_EGLEXT_PROTOTYPES) || !defined(EGL_ANDROID_swap_rectangle)
 // Dummy implementation in case it is missing.
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 9a0e94e..1b598f8 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -40,10 +40,7 @@
 
 #include "FramebufferSurface.h"
 #include "HWComposer.h"
-
-#ifndef NUM_FRAMEBUFFER_SURFACE_BUFFERS
-#define NUM_FRAMEBUFFER_SURFACE_BUFFERS (2)
-#endif
+#include "../SurfaceFlinger.h"
 
 // ----------------------------------------------------------------------------
 namespace android {
@@ -88,7 +85,8 @@
     mConsumer->setDefaultBufferFormat(mHwc.getFormat(disp));
     mConsumer->setDefaultBufferSize(mHwc.getWidth(disp), mHwc.getHeight(disp));
 #endif
-    mConsumer->setMaxAcquiredBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS - 1);
+    mConsumer->setMaxAcquiredBufferCount(
+            SurfaceFlinger::maxFrameBufferAcquiredBuffers - 1);
 }
 
 status_t FramebufferSurface::beginFrame(bool /*mustRecompose*/) {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 23b7a45..09434f6 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -617,10 +617,6 @@
     return mDisplayData[displayId].lastPresentFence;
 }
 
-bool HWComposer::presentFenceRepresentsStartOfScanout() const {
-    return mAdapter ? false : true;
-}
-
 sp<Fence> HWComposer::getLayerReleaseFence(int32_t displayId,
         const std::shared_ptr<HWC2::Layer>& layer) const {
     if (!isValidDisplay(displayId)) {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 117db4a..81f1619 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -126,11 +126,6 @@
     // get the present fence received from the last call to present.
     sp<Fence> getPresentFence(int32_t displayId) const;
 
-    // Returns true if the present fence represents the start of the display
-    // controller's scan out. This should be true for all HWC2 implementations,
-    // except for the wrapper around HWC1 implementations.
-    bool presentFenceRepresentsStartOfScanout() const;
-
     // Get last release fence for the given layer
     sp<Fence> getLayerReleaseFence(int32_t displayId,
             const std::shared_ptr<HWC2::Layer>& layer) const;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 861a7d9..ac7e083 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -595,7 +595,7 @@
     const State& s(getDrawingState());
 #ifdef USE_HWC2
     auto blendMode = HWC2::BlendMode::None;
-    if (!isOpaque(s) || s.alpha != 1.0f) {
+    if (!isOpaque(s) || getAlpha() != 1.0f) {
         blendMode = mPremultipliedAlpha ?
                 HWC2::BlendMode::Premultiplied : HWC2::BlendMode::Coverage;
     }
@@ -604,7 +604,7 @@
              " %s (%d)", mName.string(), to_string(blendMode).c_str(),
              to_string(error).c_str(), static_cast<int32_t>(error));
 #else
-    if (!isOpaque(s) || s.alpha != 0xFF) {
+    if (!isOpaque(s) || getAlpha() != 0xFF) {
         layer.setBlending(mPremultipliedAlpha ?
                 HWC_BLENDING_PREMULT :
                 HWC_BLENDING_COVERAGE);
@@ -678,9 +678,10 @@
         hwcInfo.sourceCrop = sourceCrop;
     }
 
-    error = hwcLayer->setPlaneAlpha(s.alpha);
+    float alpha = getAlpha();
+    error = hwcLayer->setPlaneAlpha(alpha);
     ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set plane alpha %.3f: "
-            "%s (%d)", mName.string(), s.alpha, to_string(error).c_str(),
+            "%s (%d)", mName.string(), alpha, to_string(error).c_str(),
             static_cast<int32_t>(error));
 
     error = hwcLayer->setZOrder(z);
@@ -698,7 +699,7 @@
     const Transform& tr(hw->getTransform());
     layer.setFrame(tr.transform(frame));
     layer.setCrop(computeCrop(hw));
-    layer.setPlaneAlpha(s.alpha);
+    layer.setPlaneAlpha(getAlpha());
 #endif
 
     /*
@@ -1147,7 +1148,7 @@
     texCoords[3] = vec2(right, 1.0f - top);
 
     RenderEngine& engine(mFlinger->getRenderEngine());
-    engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s), s.alpha);
+    engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s), getAlpha());
     engine.drawMesh(mMesh);
     engine.disableBlending();
 }
@@ -1753,11 +1754,15 @@
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
-bool Layer::setFinalCrop(const Rect& crop) {
+
+bool Layer::setFinalCrop(const Rect& crop, bool immediate) {
     if (mCurrentState.finalCrop == crop)
         return false;
     mCurrentState.sequence++;
-    mCurrentState.finalCrop = crop;
+    mCurrentState.requestedFinalCrop = crop;
+    if (immediate) {
+        mCurrentState.finalCrop = crop;
+    }
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
@@ -1883,7 +1888,6 @@
 
 bool Layer::onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
         const std::shared_ptr<FenceTime>& presentFence,
-        const std::shared_ptr<FenceTime>& retireFence,
         const CompositorTiming& compositorTiming) {
     mAcquireTimeline.updateSignalTimes();
     mReleaseTimeline.updateSignalTimes();
@@ -1898,10 +1902,6 @@
         Mutex::Autolock lock(mFrameEventHistoryMutex);
         mFrameEventHistory.addPostComposition(mCurrentFrameNumber,
                 glDoneFence, presentFence, compositorTiming);
-        if (mPreviousFrameNumber != 0) {
-            mFrameEventHistory.addRetire(mPreviousFrameNumber,
-                    retireFence);
-        }
     }
 
     // Update mFrameTracker.
@@ -1921,9 +1921,6 @@
     if (presentFence->isValid()) {
         mFrameTracker.setActualPresentFence(
                 std::shared_ptr<FenceTime>(presentFence));
-    } else if (retireFence->isValid()) {
-        mFrameTracker.setActualPresentFence(
-                std::shared_ptr<FenceTime>(retireFence));
     } else {
         // The HWC doesn't support present fences, so use the refresh
         // timestamp instead.
@@ -1965,12 +1962,11 @@
 }
 
 bool Layer::isVisible() const {
-    const Layer::State& s(mDrawingState);
 #ifdef USE_HWC2
-    return !(isHiddenByPolicy()) && s.alpha > 0.0f
+    return !(isHiddenByPolicy()) && getAlpha() > 0.0f
             && (mActiveBuffer != NULL || mSidebandStream != NULL);
 #else
-    return !(isHiddenByPolicy()) && s.alpha
+    return !(isHiddenByPolicy()) && getAlpha()
             && (mActiveBuffer != NULL || mSidebandStream != NULL);
 #endif
 }
@@ -2527,6 +2523,24 @@
     return t * getDrawingState().active.transform;
 }
 
+#ifdef USE_HWC2
+float Layer::getAlpha() const {
+    const auto& p = getParent();
+
+    float parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0;
+    return parentAlpha * getDrawingState().alpha;
+}
+#else
+uint8_t Layer::getAlpha() const {
+    const auto& p = getParent();
+
+    float parentAlpha = (p != nullptr) ? (p->getAlpha() / 255.0f) : 1.0;
+    float drawingAlpha = getDrawingState().alpha / 255.0f;
+    drawingAlpha = drawingAlpha * parentAlpha;
+    return static_cast<uint8_t>(std::round(drawingAlpha * 255));
+}
+#endif
+
 void Layer::commitChildList() {
     for (size_t i = 0; i < mCurrentChildren.size(); i++) {
         const auto& child = mCurrentChildren[i];
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index afe6074..e21be8b 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -135,6 +135,7 @@
 
         // finalCrop is expressed in display space coordinate.
         Rect finalCrop;
+        Rect requestedFinalCrop;
 
         // If set, defers this state update until the identified Layer
         // receives a frame with the given frameNumber
@@ -163,7 +164,14 @@
     status_t setBuffers(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags);
 
     // modify current state
+
+    // These members of state (position, crop, and finalCrop)
+    // may be updated immediately or have the update delayed
+    // until a pending surface resize completes (if applicable).
     bool setPosition(float x, float y, bool immediate);
+    bool setCrop(const Rect& crop, bool immediate);
+    bool setFinalCrop(const Rect& crop, bool immediate);
+
     bool setLayer(int32_t z);
     bool setSize(uint32_t w, uint32_t h);
 #ifdef USE_HWC2
@@ -174,8 +182,6 @@
     bool setMatrix(const layer_state_t::matrix22_t& matrix);
     bool setTransparentRegionHint(const Region& transparent);
     bool setFlags(uint8_t flags, uint8_t mask);
-    bool setCrop(const Rect& crop, bool immediate);
-    bool setFinalCrop(const Rect& crop);
     bool setLayerStack(uint32_t layerStack);
     bool setDataSpace(android_dataspace dataSpace);
     uint32_t getLayerStack() const;
@@ -308,7 +314,6 @@
      */
     bool onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
             const std::shared_ptr<FenceTime>& presentFence,
-            const std::shared_ptr<FenceTime>& retireFence,
             const CompositorTiming& compositorTiming);
 
 #ifdef USE_HWC2
@@ -454,6 +459,15 @@
 
     Transform getTransform() const;
 
+    // Returns the Alpha of the Surface, accounting for the Alpha
+    // of parent Surfaces in the hierarchy (alpha's will be multiplied
+    // down the hierarchy).
+#ifdef USE_HWC2
+    float getAlpha() const;
+#else
+    uint8_t getAlpha() const;
+#endif
+
     void traverseInReverseZOrder(const std::function<void(Layer*)>& exec);
     void traverseInZOrder(const std::function<void(Layer*)>& exec);
 
diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp
index 5ca7d39..0b302eb 100644
--- a/services/surfaceflinger/LayerRejecter.cpp
+++ b/services/surfaceflinger/LayerRejecter.cpp
@@ -120,6 +120,11 @@
         mCurrent.crop = mFront.requestedCrop;
         mRecomputeVisibleRegions = true;
     }
+    if (mFront.finalCrop != mFront.requestedFinalCrop) {
+        mFront.finalCrop = mFront.requestedFinalCrop;
+        mCurrent.finalCrop = mFront.requestedFinalCrop;
+        mRecomputeVisibleRegions = true;
+    }
     mFreezePositionUpdates = false;
 
     return false;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 06dd903..f82b363 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -73,7 +73,6 @@
 #include "LayerDim.h"
 #include "MonitoredProducer.h"
 #include "SurfaceFlinger.h"
-#include "VrStateCallbacks.h"
 
 #include "DisplayHardware/FramebufferSurface.h"
 #include "DisplayHardware/HWComposer.h"
@@ -118,6 +117,8 @@
 bool SurfaceFlinger::useHwcForRgbToYuv;
 uint64_t SurfaceFlinger::maxVirtualDisplaySize;
 bool SurfaceFlinger::hasSyncFramework;
+bool SurfaceFlinger::useVrFlinger;
+int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
 
 SurfaceFlinger::SurfaceFlinger()
     :   BnSurfaceComposer(),
@@ -136,7 +137,6 @@
         mVisibleRegionsDirty(false),
         mGeometryInvalid(false),
         mAnimCompositionPending(false),
-        mVrModeSupported(0),
         mDebugRegion(0),
         mDebugDDMS(0),
         mDebugDisableHWC(0),
@@ -156,10 +156,8 @@
         mFrameBuckets(),
         mTotalTime(0),
         mLastSwapTime(0),
-        mNumLayers(0)
-#ifdef USE_HWC2
-        ,mEnterVrMode(false)
-#endif
+        mNumLayers(0),
+        mVrFlingerRequestsDisplay(false)
 {
     ALOGI("SurfaceFlinger is starting");
 
@@ -184,13 +182,16 @@
     maxVirtualDisplaySize = getUInt64<ISurfaceFlingerConfigs,
             &ISurfaceFlingerConfigs::maxVirtualDisplaySize>(0);
 
+    // Vr flinger is only enabled on Daydream ready devices.
+    useVrFlinger = getBool< ISurfaceFlingerConfigs,
+            &ISurfaceFlingerConfigs::useVrFlinger>(false);
+
+    maxFrameBufferAcquiredBuffers = getInt64< ISurfaceFlingerConfigs,
+            &ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2);
+
     // debugging stuff...
     char value[PROPERTY_VALUE_MAX];
 
-    // TODO (urbanus): remove once b/35319396 is fixed.
-    property_get("ro.boot.vr", value, "0");
-    mVrModeSupported = atoi(value);
-
     property_get("ro.bq.gpu_to_cpu_unsupported", value, "0");
     mGpuToCpuSupported = !atoi(value);
 
@@ -231,14 +232,6 @@
     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
     eglTerminate(display);
-
-    if (mVrStateCallbacks.get()) {
-        sp<IVrManager> vrManagerService = interface_cast<IVrManager>(
-            defaultServiceManager()->checkService(String16("vrmanager")));
-        if (vrManagerService.get()) {
-            vrManagerService->unregisterListener(mVrStateCallbacks);
-        }
-    }
 }
 
 void SurfaceFlinger::binderDied(const wp<IBinder>& /* who */)
@@ -365,6 +358,10 @@
         window->linkToDeath(static_cast<IBinder::DeathRecipient*>(this));
     }
 
+    if (mVrFlinger) {
+      mVrFlinger->OnBootFinished();
+    }
+
     // stop boot animation
     // formerly we would just kill the process, but we now ask it to exit so it
     // can choose where to stop the animation.
@@ -373,13 +370,6 @@
     const int LOGTAG_SF_STOP_BOOTANIM = 60110;
     LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
                    ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
-
-    sp<IVrManager> vrManagerService = interface_cast<IVrManager>(
-        defaultServiceManager()->checkService(String16("vrmanager")));
-    if (vrManagerService.get()) {
-        mVrStateCallbacks = new VrStateCallbacks(*this);
-        vrManagerService->registerListener(mVrStateCallbacks);
-    }
 }
 
 void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
@@ -575,13 +565,26 @@
     // Drop the state lock while we initialize the hardware composer. We drop
     // the lock because on creation, it will call back into SurfaceFlinger to
     // initialize the primary display.
-    LOG_ALWAYS_FATAL_IF(mEnterVrMode, "Starting in vr mode is not currently supported.");
+    LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
+        "Starting with vr flinger active is not currently supported.");
     mRealHwc = new HWComposer(false);
     mHwc = mRealHwc;
     mHwc->setEventHandler(static_cast<HWComposer::EventHandler*>(this));
 
     Mutex::Autolock _l(mStateLock);
 
+    if (useVrFlinger) {
+        auto vrFlingerRequestDisplayCallback = [this] (bool requestDisplay) {
+            mVrFlingerRequestsDisplay = requestDisplay;
+            signalTransaction();
+        };
+        mVrFlinger = dvr::VrFlinger::Create(mHwc->getComposer(),
+                                            vrFlingerRequestDisplayCallback);
+        if (!mVrFlinger) {
+            ALOGE("Failed to start vrflinger");
+        }
+    }
+
     // retrieve the EGL context that was selected/created
     mEGLContext = mRenderEngine->getEGLContext();
 
@@ -643,23 +646,6 @@
     return mGraphicBufferProducerList.indexOf(surfaceTextureBinder) >= 0;
 }
 
-status_t SurfaceFlinger::getSupportedFrameTimestamps(
-        std::vector<FrameEvent>* outSupported) const {
-    *outSupported = {
-        FrameEvent::REQUESTED_PRESENT,
-        FrameEvent::ACQUIRE,
-        FrameEvent::LATCH,
-        FrameEvent::FIRST_REFRESH_START,
-        FrameEvent::LAST_REFRESH_START,
-        FrameEvent::GPU_COMPOSITION_DONE,
-        getHwComposer().presentFenceRepresentsStartOfScanout() ?
-                FrameEvent::DISPLAY_PRESENT : FrameEvent::DISPLAY_RETIRE,
-        FrameEvent::DEQUEUE_READY,
-        FrameEvent::RELEASE,
-    };
-    return NO_ERROR;
-}
-
 status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
         Vector<DisplayInfo>* configs) {
     if ((configs == NULL) || (display.get() == NULL)) {
@@ -1213,14 +1199,17 @@
     // transition.
     mDrawingState.displays.clear();
     mDisplays.clear();
+    initializeDisplays();
 }
 
-void SurfaceFlinger::updateVrMode() {
-    bool enteringVrMode = mEnterVrMode;
-    if (enteringVrMode == mHwc->isUsingVrComposer()) {
+void SurfaceFlinger::updateVrFlinger() {
+    if (!mVrFlinger)
+        return;
+    bool vrFlingerRequestsDisplay = mVrFlingerRequestsDisplay;
+    if (vrFlingerRequestsDisplay == mHwc->isUsingVrComposer()) {
         return;
     }
-    if (enteringVrMode && !mVrHwc) {
+    if (vrFlingerRequestsDisplay && !mVrHwc) {
         // Construct new HWComposer without holding any locks.
         mVrHwc = new HWComposer(true);
         ALOGV("Vr HWC created");
@@ -1228,25 +1217,13 @@
     {
         Mutex::Autolock _l(mStateLock);
 
-        if (enteringVrMode) {
-            // Start vrflinger thread, if it hasn't been started already.
-            if (!mVrFlinger) {
-                mVrFlinger = std::make_unique<dvr::VrFlinger>();
-                int err = mVrFlinger->Run(mHwc->getComposer());
-                if (err != NO_ERROR) {
-                    ALOGE("Failed to run vrflinger: %s (%d)", strerror(-err), err);
-                    mVrFlinger.reset();
-                    mEnterVrMode = false;
-                    return;
-                }
-            }
-
+        if (vrFlingerRequestsDisplay) {
             resetHwc();
 
             mHwc = mVrHwc;
-            mVrFlinger->EnterVrMode();
+            mVrFlinger->GrantDisplayOwnership();
         } else {
-            mVrFlinger->ExitVrMode();
+            mVrFlinger->SeizeDisplayOwnership();
 
             resetHwc();
 
@@ -1268,12 +1245,6 @@
     ATRACE_CALL();
     switch (what) {
         case MessageQueue::INVALIDATE: {
-            // TODO(eieio): Tied to a conditional until SELinux issues
-            // are resolved.
-            if (mVrModeSupported) {
-                updateVrMode();
-            }
-
             bool frameMissed = !mHadClientComposition &&
                     mPreviousPresentFence != Fence::NO_FENCE &&
                     (mPreviousPresentFence->getSignalTime() ==
@@ -1285,6 +1256,11 @@
                 break;
             }
 
+            // Now that we're going to make it to the handleMessageTransaction()
+            // call below it's safe to call updateVrFlinger(), which will
+            // potentially trigger a display handoff.
+            updateVrFlinger();
+
             bool refreshNeeded = handleMessageTransaction();
             refreshNeeded |= handleMessageInvalidate();
             refreshNeeded |= mRepaintEverything;
@@ -1484,19 +1460,11 @@
     }
     mGlCompositionDoneTimeline.updateSignalTimes();
 
-    sp<Fence> displayFence = mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);
-    auto displayFenceTime = std::make_shared<FenceTime>(displayFence);
-    mDisplayTimeline.push(displayFenceTime);
+    sp<Fence> presentFence = mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);
+    auto presentFenceTime = std::make_shared<FenceTime>(presentFence);
+    mDisplayTimeline.push(presentFenceTime);
     mDisplayTimeline.updateSignalTimes();
 
-    const std::shared_ptr<FenceTime>* presentFenceTime = &FenceTime::NO_FENCE;
-    const std::shared_ptr<FenceTime>* retireFenceTime = &FenceTime::NO_FENCE;
-    if (mHwc->presentFenceRepresentsStartOfScanout()) {
-        presentFenceTime = &displayFenceTime;
-    } else {
-        retireFenceTime = &displayFenceTime;
-    }
-
     nsecs_t vsyncPhase = mPrimaryDispSync.computeNextRefresh(0);
     nsecs_t vsyncInterval = mPrimaryDispSync.getPeriod();
 
@@ -1504,7 +1472,7 @@
     // when we started doing work for this frame, but that should be okay
     // since updateCompositorTiming has snapping logic.
     updateCompositorTiming(
-        vsyncPhase, vsyncInterval, refreshStartTime, displayFenceTime);
+        vsyncPhase, vsyncInterval, refreshStartTime, presentFenceTime);
     CompositorTiming compositorTiming;
     {
         std::lock_guard<std::mutex> lock(mCompositorTimingLock);
@@ -1513,15 +1481,15 @@
 
     mDrawingState.traverseInZOrder([&](Layer* layer) {
         bool frameLatched = layer->onPostComposition(glCompositionDoneFenceTime,
-                *presentFenceTime, *retireFenceTime, compositorTiming);
+                presentFenceTime, compositorTiming);
         if (frameLatched) {
             recordBufferingStats(layer->getName().string(),
                     layer->getOccupancyHistory(false));
         }
     });
 
-    if (displayFence->isValid()) {
-        if (mPrimaryDispSync.addPresentFence(displayFence)) {
+    if (presentFence->isValid()) {
+        if (mPrimaryDispSync.addPresentFence(presentFence)) {
             enableHardwareVsync();
         } else {
             disableHardwareVsync(false);
@@ -1537,9 +1505,9 @@
     if (mAnimCompositionPending) {
         mAnimCompositionPending = false;
 
-        if (displayFenceTime->isValid()) {
+        if (presentFenceTime->isValid()) {
             mAnimFrameTracker.setActualPresentFence(
-                    std::move(displayFenceTime));
+                    std::move(presentFenceTime));
         } else {
             // The HWC doesn't support present fences, so use the refresh
             // timestamp instead.
@@ -2798,7 +2766,7 @@
                 flags |= eTraversalNeeded;
         }
         if (what & layer_state_t::eFinalCropChanged) {
-            if (layer->setFinalCrop(s.finalCrop))
+            if (layer->setFinalCrop(s.finalCrop, !geometryAppliesWithResize))
                 flags |= eTraversalNeeded;
         }
         if (what & layer_state_t::eLayerStackChanged) {
@@ -3262,6 +3230,8 @@
     result.appendFormat(" FORCE_HWC_FOR_RBG_TO_YUV=%d", useHwcForRgbToYuv);
     result.appendFormat(" MAX_VIRT_DISPLAY_DIM=%" PRIu64, maxVirtualDisplaySize);
     result.appendFormat(" RUNNING_WITHOUT_SYNC_FRAMEWORK=%d", !hasSyncFramework);
+    result.appendFormat(" NUM_FRAMEBUFFER_SURFACE_BUFFERS=%" PRId64,
+                        maxFrameBufferAcquiredBuffers);
     result.append("]");
 }
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 921ecf6..581bbfd 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -84,7 +84,6 @@
 class EventControlThread;
 class VSyncSource;
 class InjectVSyncSource;
-class VrStateCallbacks;
 
 namespace dvr {
 class VrFlinger;
@@ -148,6 +147,10 @@
     // Equal to min(max_height, max_width).
     static uint64_t maxVirtualDisplaySize;
 
+    // Controls the number of buffers SurfaceFlinger will allocate for use in
+    // FramebufferSurface
+    static int64_t maxFrameBufferAcquiredBuffers;
+
     static char const* getServiceName() ANDROID_API {
         return "SurfaceFlinger";
     }
@@ -211,7 +214,6 @@
     friend class EventThread;
     friend class Layer;
     friend class MonitoredProducer;
-    friend class VrStateCallbacks;
 
     // This value is specified in number of frames.  Log frame stats at most
     // every half hour.
@@ -256,8 +258,6 @@
     virtual void bootFinished();
     virtual bool authenticateSurfaceTexture(
         const sp<IGraphicBufferProducer>& bufferProducer) const;
-    virtual status_t getSupportedFrameTimestamps(
-            std::vector<FrameEvent>* outSupported) const;
     virtual sp<IDisplayEventConnection> createDisplayEventConnection();
     virtual status_t captureScreen(const sp<IBinder>& display,
             const sp<IGraphicBufferProducer>& producer,
@@ -532,9 +532,8 @@
     void clearHwcLayers(const LayerVector& layers);
     void resetHwc();
 
-    // Check to see if we should change to or from vr mode, and if so, perform
-    // the handoff.
-    void updateVrMode();
+    // Check to see if we should handoff to vr flinger.
+    void updateVrFlinger();
 #endif
 
     /* ------------------------------------------------------------------------
@@ -604,7 +603,6 @@
     DefaultKeyedVector< wp<IBinder>, sp<DisplayDevice> > mDisplays;
 
     // don't use a lock for these, we don't care
-    int mVrModeSupported;
     int mDebugRegion;
     int mDebugDDMS;
     int mDebugDisableHWC;
@@ -701,9 +699,8 @@
     status_t CheckTransactCodeCredentials(uint32_t code);
 
 #ifdef USE_HWC2
-    sp<VrStateCallbacks> mVrStateCallbacks;
-
-    std::atomic<bool> mEnterVrMode;
+    std::atomic<bool> mVrFlingerRequestsDisplay;
+    static bool useVrFlinger;
 #endif
     };
 }; // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index e8147cf..c26847f 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -116,6 +116,7 @@
 bool SurfaceFlinger::useHwcForRgbToYuv;
 uint64_t SurfaceFlinger::maxVirtualDisplaySize;
 bool SurfaceFlinger::hasSyncFramework;
+int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
 
 SurfaceFlinger::SurfaceFlinger()
     :   BnSurfaceComposer(),
@@ -175,6 +176,9 @@
     useHwcForRgbToYuv = getBool< ISurfaceFlingerConfigs,
             &ISurfaceFlingerConfigs::useHwcForRGBtoYUV>(false);
 
+    maxFrameBufferAcquiredBuffers = getInt64< ISurfaceFlingerConfigs,
+            &ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2);
+
     char value[PROPERTY_VALUE_MAX];
 
     property_get("ro.bq.gpu_to_cpu_unsupported", value, "0");
@@ -643,22 +647,6 @@
     return mGraphicBufferProducerList.indexOf(surfaceTextureBinder) >= 0;
 }
 
-status_t SurfaceFlinger::getSupportedFrameTimestamps(
-        std::vector<FrameEvent>* outSupported) const {
-    *outSupported = {
-        FrameEvent::REQUESTED_PRESENT,
-        FrameEvent::ACQUIRE,
-        FrameEvent::LATCH,
-        FrameEvent::FIRST_REFRESH_START,
-        FrameEvent::LAST_REFRESH_START,
-        FrameEvent::GPU_COMPOSITION_DONE,
-        FrameEvent::DISPLAY_RETIRE,
-        FrameEvent::DEQUEUE_READY,
-        FrameEvent::RELEASE,
-    };
-    return NO_ERROR;
-}
-
 status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
         Vector<DisplayInfo>* configs) {
     if ((configs == NULL) || (display.get() == NULL)) {
@@ -1261,9 +1249,8 @@
     }
     mGlCompositionDoneTimeline.updateSignalTimes();
 
-    sp<Fence> displayFence = mHwc->getDisplayFence(HWC_DISPLAY_PRIMARY);
-    const std::shared_ptr<FenceTime>& presentFenceTime = FenceTime::NO_FENCE;
-    auto retireFenceTime = std::make_shared<FenceTime>(displayFence);
+    sp<Fence> retireFence = mHwc->getDisplayFence(HWC_DISPLAY_PRIMARY);
+    auto retireFenceTime = std::make_shared<FenceTime>(retireFence);
     mDisplayTimeline.push(retireFenceTime);
     mDisplayTimeline.updateSignalTimes();
 
@@ -1282,16 +1269,18 @@
     }
 
     mDrawingState.traverseInZOrder([&](Layer* layer) {
+        // TODO(brianderson): The retire fence is incorrectly passed in as the
+        // present fence. Fix this if this file lives on.
         bool frameLatched = layer->onPostComposition(glCompositionDoneFenceTime,
-                presentFenceTime, retireFenceTime, compositorTiming);
+                retireFenceTime, compositorTiming);
         if (frameLatched) {
             recordBufferingStats(layer->getName().string(),
                     layer->getOccupancyHistory(false));
         }
     });
 
-    if (displayFence->isValid()) {
-        if (mPrimaryDispSync.addPresentFence(displayFence)) {
+    if (retireFence->isValid()) {
+        if (mPrimaryDispSync.addPresentFence(retireFence)) {
             enableHardwareVsync();
         } else {
             disableHardwareVsync(false);
@@ -2575,7 +2564,7 @@
                 flags |= eTraversalNeeded;
         }
         if (what & layer_state_t::eFinalCropChanged) {
-            if (layer->setFinalCrop(s.finalCrop))
+            if (layer->setFinalCrop(s.finalCrop, !geometryAppliesWithResize))
                 flags |= eTraversalNeeded;
         }
         if (what & layer_state_t::eLayerStackChanged) {
@@ -3039,6 +3028,8 @@
     result.appendFormat(" FORCE_HWC_FOR_RBG_TO_YUV=%d", useHwcForRgbToYuv);
     result.appendFormat(" MAX_VIRT_DISPLAY_DIM=%" PRIu64, maxVirtualDisplaySize);
     result.appendFormat(" RUNNING_WITHOUT_SYNC_FRAMEWORK=%d", !hasSyncFramework);
+    result.appendFormat(" NUM_FRAMEBUFFER_SURFACE_BUFFERS=%" PRId64,
+                        maxFrameBufferAcquiredBuffers);
     result.append("]");
 }
 
diff --git a/services/surfaceflinger/VrStateCallbacks.cpp b/services/surfaceflinger/VrStateCallbacks.cpp
deleted file mode 100644
index a924def..0000000
--- a/services/surfaceflinger/VrStateCallbacks.cpp
+++ /dev/null
@@ -1,30 +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 "VrStateCallbacks.h"
-#include "SurfaceFlinger.h"
-
-namespace android {
-
-VrStateCallbacks::VrStateCallbacks(SurfaceFlinger& flinger)
-    : mFlinger(flinger) {}
-
-void VrStateCallbacks::onVrStateChanged(bool enabled) {
-    mFlinger.mEnterVrMode = enabled;
-    mFlinger.signalTransaction();
-}
-
-} // namespace android
diff --git a/services/surfaceflinger/VrStateCallbacks.h b/services/surfaceflinger/VrStateCallbacks.h
deleted file mode 100644
index 4e655d3..0000000
--- a/services/surfaceflinger/VrStateCallbacks.h
+++ /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.
- */
-
-#ifndef ANDROID_VR_STATE_CALLBACKS_H
-#define ANDROID_VR_STATE_CALLBACKS_H
-
-#include <vr/vr_manager/vr_manager.h>
-
-namespace android {
-
-class SurfaceFlinger;
-
-class VrStateCallbacks : public BnVrStateCallbacks {
-public:
-    VrStateCallbacks(SurfaceFlinger& flinger);
-    void onVrStateChanged(bool enabled) override;
-
-private:
-    SurfaceFlinger& mFlinger;
-};
-
-} // namespace android
-
-#endif // ANDROID_VR_STATE_CALLBACKS_H
diff --git a/services/surfaceflinger/tests/Android.mk b/services/surfaceflinger/tests/Android.mk
index f46ce8a..16041da 100644
--- a/services/surfaceflinger/tests/Android.mk
+++ b/services/surfaceflinger/tests/Android.mk
@@ -28,6 +28,8 @@
 
 LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
 
+LOCAL_TEST_DATA = SurfaceFlinger_test.filter
+
 # Build the binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
 # to integrate with auto-test framework.
 include $(BUILD_NATIVE_TEST)
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
new file mode 100644
index 0000000..915b5cd
--- /dev/null
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -0,0 +1,5 @@
+{
+        "presubmit": {
+            "filter": "LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*" 
+        }
+}
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index aeb557a..a46ba48 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -470,6 +470,141 @@
     }
 }
 
+class GeometryLatchingTest : public LayerUpdateTest {
+protected:
+    void EXPECT_INITIAL_STATE(const char * trace) {
+        SCOPED_TRACE(trace);
+        ScreenCapture::captureScreen(&sc);
+        // We find the leading edge of the FG surface.
+        sc->expectFGColor(127, 127);
+        sc->expectBGColor(128, 128);
+    }
+    void completeFGResize() {
+        fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
+        waitForPostedBuffers();
+    }
+    void restoreInitialState() {
+        SurfaceComposerClient::openGlobalTransaction();
+        mFGSurfaceControl->setSize(64, 64);
+        mFGSurfaceControl->setPosition(64, 64);
+        mFGSurfaceControl->setCrop(Rect(0, 0, 64, 64));
+        mFGSurfaceControl->setFinalCrop(Rect(0, 0, -1, -1));
+        SurfaceComposerClient::closeGlobalTransaction(true);
+
+        EXPECT_INITIAL_STATE("After restoring initial state");
+    }
+    sp<ScreenCapture> sc;
+};
+
+TEST_F(GeometryLatchingTest, SurfacePositionLatching) {
+    EXPECT_INITIAL_STATE("before anything");
+
+    // By default position can be updated even while
+    // a resize is pending.
+    SurfaceComposerClient::openGlobalTransaction();
+    mFGSurfaceControl->setSize(32, 32);
+    mFGSurfaceControl->setPosition(100, 100);
+    SurfaceComposerClient::closeGlobalTransaction(true);
+
+    {
+        SCOPED_TRACE("After moving surface");
+        ScreenCapture::captureScreen(&sc);
+        // If we moved, the FG Surface should cover up what was previously BG
+        // however if we didn't move the FG wouldn't be large enough now.
+        sc->expectFGColor(163, 163);
+    }
+
+    restoreInitialState();
+
+    // Now we repeat with setGeometryAppliesWithResize
+    // and verify the position DOESN'T latch.
+    SurfaceComposerClient::openGlobalTransaction();
+    mFGSurfaceControl->setGeometryAppliesWithResize();
+    mFGSurfaceControl->setSize(32, 32);
+    mFGSurfaceControl->setPosition(100, 100);
+    SurfaceComposerClient::closeGlobalTransaction(true);
+
+    {
+        SCOPED_TRACE("While resize is pending");
+        ScreenCapture::captureScreen(&sc);
+        // This time we shouldn't have moved, so the BG color
+        // should still be visible.
+        sc->expectBGColor(128, 128);
+    }
+
+    completeFGResize();
+
+    {
+        SCOPED_TRACE("After the resize");
+        ScreenCapture::captureScreen(&sc);
+        // But after the resize completes, we should move
+        // and the FG should be visible here.
+        sc->expectFGColor(128, 128);
+    }
+}
+
+class CropLatchingTest : public GeometryLatchingTest {
+protected:
+    void EXPECT_CROPPED_STATE(const char* trace) {
+        SCOPED_TRACE(trace);
+        ScreenCapture::captureScreen(&sc);
+        // The edge should be moved back one pixel by our crop.
+        sc->expectFGColor(126, 126);
+        sc->expectBGColor(127, 127);
+        sc->expectBGColor(128, 128);
+    }
+};
+
+TEST_F(CropLatchingTest, CropLatching) {
+    EXPECT_INITIAL_STATE("before anything");
+    // Normally the crop applies immediately even while a resize is pending.
+    SurfaceComposerClient::openGlobalTransaction();
+    mFGSurfaceControl->setSize(128, 128);
+    mFGSurfaceControl->setCrop(Rect(0, 0, 63, 63));
+    SurfaceComposerClient::closeGlobalTransaction(true);
+
+    EXPECT_CROPPED_STATE("after setting crop (without geometryAppliesWithResize)");
+
+    restoreInitialState();
+
+    SurfaceComposerClient::openGlobalTransaction();
+    mFGSurfaceControl->setSize(128, 128);
+    mFGSurfaceControl->setGeometryAppliesWithResize();
+    mFGSurfaceControl->setCrop(Rect(0, 0, 63, 63));
+    SurfaceComposerClient::closeGlobalTransaction(true);
+
+    EXPECT_INITIAL_STATE("after setting crop (with geometryAppliesWithResize)");
+
+    completeFGResize();
+
+    EXPECT_CROPPED_STATE("after the resize finishes");
+}
+
+TEST_F(CropLatchingTest, FinalCropLatching) {
+    EXPECT_INITIAL_STATE("before anything");
+    // Normally the crop applies immediately even while a resize is pending.
+    SurfaceComposerClient::openGlobalTransaction();
+    mFGSurfaceControl->setSize(128, 128);
+    mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
+    SurfaceComposerClient::closeGlobalTransaction(true);
+
+    EXPECT_CROPPED_STATE("after setting crop (without geometryAppliesWithResize)");
+
+    restoreInitialState();
+
+    SurfaceComposerClient::openGlobalTransaction();
+    mFGSurfaceControl->setSize(128, 128);
+    mFGSurfaceControl->setGeometryAppliesWithResize();
+    mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
+    SurfaceComposerClient::closeGlobalTransaction(true);
+
+    EXPECT_INITIAL_STATE("after setting crop (with geometryAppliesWithResize)");
+
+    completeFGResize();
+
+    EXPECT_CROPPED_STATE("after the resize finishes");
+}
+
 TEST_F(LayerUpdateTest, DeferredTransactionTest) {
     sp<ScreenCapture> sc;
     {
@@ -629,6 +764,45 @@
     }
 }
 
+TEST_F(ChildLayerTest, ChildLayerAlpha) {
+    fillSurfaceRGBA8(mBGSurfaceControl, 0, 0, 254);
+    fillSurfaceRGBA8(mFGSurfaceControl, 254, 0, 0);
+    fillSurfaceRGBA8(mChild, 0, 254, 0);
+    waitForPostedBuffers();
+
+    SurfaceComposerClient::openGlobalTransaction();
+    mChild->show();
+    mChild->setPosition(0, 0);
+    mFGSurfaceControl->setPosition(0, 0);
+    SurfaceComposerClient::closeGlobalTransaction(true);
+
+    {
+        ScreenCapture::captureScreen(&mCapture);
+        // Unblended child color
+        mCapture->checkPixel(0, 0, 0, 254, 0);
+    }
+
+    SurfaceComposerClient::openGlobalTransaction();
+    ASSERT_EQ(NO_ERROR, mChild->setAlpha(0.5));
+    SurfaceComposerClient::closeGlobalTransaction(true);
+
+    {
+        ScreenCapture::captureScreen(&mCapture);
+        // Child and BG blended.
+        mCapture->checkPixel(0, 0, 127, 127, 0);
+    }
+
+    SurfaceComposerClient::openGlobalTransaction();
+    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setAlpha(0.5));
+    SurfaceComposerClient::closeGlobalTransaction(true);
+
+    {
+        ScreenCapture::captureScreen(&mCapture);
+        // Child and BG blended.
+        mCapture->checkPixel(0, 0, 95, 64, 95);
+    }
+}
+
 TEST_F(ChildLayerTest, ReparentChildren) {
     SurfaceComposerClient::openGlobalTransaction();
     mChild->show();
@@ -677,11 +851,11 @@
 
     SurfaceComposerClient::openGlobalTransaction();
     mFGSurfaceControl->detachChildren();
-    SurfaceComposerClient::closeGlobalTransaction();
+    SurfaceComposerClient::closeGlobalTransaction(true);
 
     SurfaceComposerClient::openGlobalTransaction();
     mChild->hide();
-    SurfaceComposerClient::closeGlobalTransaction();
+    SurfaceComposerClient::closeGlobalTransaction(true);
 
     // Nothing should have changed.
     {
diff --git a/services/vr/bufferhubd/Android.mk b/services/vr/bufferhubd/Android.mk
index 0db909c..c1a0b6f 100644
--- a/services/vr/bufferhubd/Android.mk
+++ b/services/vr/bufferhubd/Android.mk
@@ -34,7 +34,8 @@
 	liblog \
 	libsync \
 	libutils \
-	libgui
+        libgui \
+        libui
 
 include $(CLEAR_VARS)
 # Don't strip symbols so we see stack traces in logcat.
diff --git a/services/vr/bufferhubd/buffer_hub.cpp b/services/vr/bufferhubd/buffer_hub.cpp
index 0906476..80efcf8 100644
--- a/services/vr/bufferhubd/buffer_hub.cpp
+++ b/services/vr/bufferhubd/buffer_hub.cpp
@@ -29,7 +29,7 @@
 BufferHubService::~BufferHubService() {}
 
 bool BufferHubService::IsInitialized() const {
-  return BASE::IsInitialized() && IonBuffer::GetGrallocModule();
+  return BASE::IsInitialized();
 }
 
 std::string BufferHubService::DumpState(size_t /*max_length*/) {
diff --git a/services/vr/bufferhubd/bufferhubd.rc b/services/vr/bufferhubd/bufferhubd.rc
index ceedf1a..65b7293 100644
--- a/services/vr/bufferhubd/bufferhubd.rc
+++ b/services/vr/bufferhubd/bufferhubd.rc
@@ -2,5 +2,5 @@
   class core
   user system
   group system
-  cpuset /
+  writepid /dev/cpuset/tasks
 
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
new file mode 100644
index 0000000..1601c7f
--- /dev/null
+++ b/services/vr/hardware_composer/Android.bp
@@ -0,0 +1,121 @@
+cc_library_static {
+  name: "libvr_hwc-binder",
+  srcs: [
+    "aidl/android/dvr/IVrComposer.aidl",
+    "aidl/android/dvr/IVrComposerCallback.aidl",
+    "aidl/android/dvr/parcelable_composer_frame.cpp",
+    "aidl/android/dvr/parcelable_composer_layer.cpp",
+    "aidl/android/dvr/parcelable_unique_fd.cpp",
+  ],
+  aidl: {
+    include_dirs: ["frameworks/native/services/vr/hardware_composer/aidl"],
+    export_aidl_headers: true,
+  },
+  export_include_dirs: ["aidl"],
+  shared_libs: [
+    "libbinder",
+    "libui",
+    "libutils",
+    "libvrhwc",
+  ],
+}
+
+cc_library_static {
+  name: "libvr_hwc-impl",
+  srcs: [
+    "vr_composer.cpp",
+  ],
+  static_libs: [
+    "libvr_hwc-binder",
+  ],
+  shared_libs: [
+    "libbase",
+    "libbinder",
+    "liblog",
+    "libui",
+    "libutils",
+    "libvrhwc",
+  ],
+  export_shared_lib_headers: [
+    "libvrhwc",
+  ],
+  cflags: [
+    "-DLOG_TAG=\"vr_hwc\"",
+  ],
+}
+
+cc_binary {
+  name: "vr_hwc",
+  srcs: [
+    "vr_hardware_composer_service.cpp"
+  ],
+  static_libs: [
+    "libvr_hwc-impl",
+    // NOTE: This needs to be included after the *-impl lib otherwise the
+    // symbols in the *-binder library get optimized out.
+    "libvr_hwc-binder",
+  ],
+  shared_libs: [
+    "android.dvr.composer@1.0",
+    "android.hardware.graphics.composer@2.1",
+    "libbase",
+    "libbinder",
+    "liblog",
+    "libhardware",
+    "libhwbinder",
+    "libui",
+    "libutils",
+    "libvrhwc",
+  ],
+  cflags: [
+    "-DLOG_TAG=\"vr_hwc\"",
+  ],
+  init_rc: [
+    "vr_hwc.rc",
+  ],
+}
+
+cc_library_static {
+  name: "libdvr_hwc",
+  srcs: [
+    "dvr_hardware_composer_client.cpp",
+  ],
+  static_libs: [
+    "libvr_hwc-impl",
+    // NOTE: This needs to be included after the *-impl lib otherwise the
+    // symbols in the *-binder library get optimized out.
+    "libvr_hwc-binder",
+  ],
+  shared_libs: [
+    "libbase",
+    "libbinder",
+    "liblog",
+    "libnativewindow",
+    "libui",
+    "libutils",
+  ],
+  export_include_dirs: ["private"],
+  export_shared_lib_headers: [
+    "libnativewindow",
+  ],
+}
+
+cc_test {
+  name: "vr_hwc_test",
+  gtest: true,
+  srcs: ["tests/vr_composer_test.cpp"],
+  static_libs: [
+    "libgtest",
+    "libvr_hwc-impl",
+    // NOTE: This needs to be included after the *-impl lib otherwise the
+    // symbols in the *-binder library get optimized out.
+    "libvr_hwc-binder",
+  ],
+  shared_libs: [
+    "libbase",
+    "libbinder",
+    "liblog",
+    "libui",
+    "libutils",
+  ],
+}
diff --git a/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl b/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl
new file mode 100644
index 0000000..5fd5c36
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/IVrComposer.aidl
@@ -0,0 +1,20 @@
+package android.dvr;
+
+import android.dvr.IVrComposerCallback;
+
+/**
+ * Service interface exposed by VR HWC exposed to system apps which allows one
+ * system app to connect to get SurfaceFlinger's outputs (all displays). This
+ * is active when SurfaceFlinger is in VR mode, where all 2D output is
+ * redirected to VR HWC.
+ *
+ * @hide */
+interface IVrComposer
+{
+  const String SERVICE_NAME = "vr_hwc";
+
+  /**
+   * Registers a callback used to receive frame notifications.
+   */
+  void registerObserver(in IVrComposerCallback callback);
+}
diff --git a/services/vr/hardware_composer/aidl/android/dvr/IVrComposerCallback.aidl b/services/vr/hardware_composer/aidl/android/dvr/IVrComposerCallback.aidl
new file mode 100644
index 0000000..aa70de1
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/IVrComposerCallback.aidl
@@ -0,0 +1,22 @@
+package android.dvr;
+
+import android.dvr.ParcelableComposerFrame;
+import android.dvr.ParcelableUniqueFd;
+
+/**
+ * A system app will implement and register this callback with VRComposer
+ * to receive the layers SurfaceFlinger presented when in VR mode.
+ *
+ * @hide */
+interface IVrComposerCallback {
+  /**
+   * Called by the VR HWC service when a new frame is ready to be presented.
+   *
+   * @param frame The new frame VR HWC wants to present.
+   * @return A fence FD used to signal when the previous frame is no longer
+   * used by the client. This may be an invalid fence (-1) if the client is not
+   * using the previous frame, in which case the previous frame may be re-used
+   * at any point in time.
+   */
+  ParcelableUniqueFd onNewFrame(in ParcelableComposerFrame frame);
+}
diff --git a/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerFrame.aidl b/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerFrame.aidl
new file mode 100644
index 0000000..84abc19
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerFrame.aidl
@@ -0,0 +1,3 @@
+package android.dvr;
+
+parcelable ParcelableComposerFrame cpp_header "android/dvr/parcelable_composer_frame.h";
diff --git a/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerLayer.aidl b/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerLayer.aidl
new file mode 100644
index 0000000..a200345
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/ParcelableComposerLayer.aidl
@@ -0,0 +1,3 @@
+package android.dvr;
+
+parcelable ParcelableComposerLayer cpp_header "android/dvr/parcelable_composer_layer.h";
diff --git a/services/vr/hardware_composer/aidl/android/dvr/ParcelableUniqueFd.aidl b/services/vr/hardware_composer/aidl/android/dvr/ParcelableUniqueFd.aidl
new file mode 100644
index 0000000..eee9d13
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/ParcelableUniqueFd.aidl
@@ -0,0 +1,3 @@
+package android.dvr;
+
+parcelable ParcelableUniqueFd cpp_header "android/dvr/parcelable_unique_fd.h";
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp
new file mode 100644
index 0000000..cb3e49d
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp
@@ -0,0 +1,53 @@
+#include "aidl/android/dvr/parcelable_composer_frame.h"
+
+#include <binder/Parcel.h>
+
+#include "aidl/android/dvr/parcelable_composer_layer.h"
+
+namespace android {
+namespace dvr {
+
+ParcelableComposerFrame::ParcelableComposerFrame() {}
+
+ParcelableComposerFrame::ParcelableComposerFrame(
+    const ComposerView::Frame& frame)
+    : frame_(frame) {}
+
+ParcelableComposerFrame::~ParcelableComposerFrame() {}
+
+status_t ParcelableComposerFrame::writeToParcel(Parcel* parcel) const {
+  status_t ret = parcel->writeUint64(frame_.display_id);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeBool(frame_.removed);
+  if (ret != OK) return ret;
+
+  std::vector<ParcelableComposerLayer> layers;
+  for (size_t i = 0; i < frame_.layers.size(); ++i)
+    layers.push_back(ParcelableComposerLayer(frame_.layers[i]));
+
+  ret = parcel->writeParcelableVector(layers);
+
+  return ret;
+}
+
+status_t ParcelableComposerFrame::readFromParcel(const Parcel* parcel) {
+  status_t ret = parcel->readUint64(&frame_.display_id);
+  if (ret != OK) return ret;
+
+  ret = parcel->readBool(&frame_.removed);
+  if (ret != OK) return ret;
+
+  std::vector<ParcelableComposerLayer> layers;
+  ret = parcel->readParcelableVector(&layers);
+  if (ret != OK) return ret;
+
+  frame_.layers.clear();
+  for (size_t i = 0; i < layers.size(); ++i)
+    frame_.layers.push_back(layers[i].layer());
+
+  return ret;
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.h b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.h
new file mode 100644
index 0000000..b478bb5
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.h
@@ -0,0 +1,28 @@
+#ifndef ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_FRAME_H
+#define ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_FRAME_H
+
+#include <binder/Parcelable.h>
+#include <impl/vr_hwc.h>
+
+namespace android {
+namespace dvr {
+
+class ParcelableComposerFrame : public Parcelable {
+ public:
+  ParcelableComposerFrame();
+  ParcelableComposerFrame(const ComposerView::Frame& frame);
+  ~ParcelableComposerFrame() override;
+
+  ComposerView::Frame frame() const { return frame_; }
+
+  status_t writeToParcel(Parcel* parcel) const override;
+  status_t readFromParcel(const Parcel* parcel) override;
+
+ private:
+  ComposerView::Frame frame_;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_FRAME_H
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp
new file mode 100644
index 0000000..34e2b7e
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp
@@ -0,0 +1,166 @@
+#include "aidl/android/dvr/parcelable_composer_layer.h"
+
+#include <binder/Parcel.h>
+#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferMapper.h>
+
+namespace android {
+namespace dvr {
+namespace {
+
+sp<GraphicBuffer> GetBufferFromHandle(native_handle_t* handle) {
+  uint32_t width = 0, height = 0, stride = 0, layer_count = 1;
+  uint64_t producer_usage = 0, consumer_usage = 0;
+  int32_t format = 0;
+
+  GraphicBufferMapper& mapper = GraphicBufferMapper::get();
+  // Need to register |handle| otherwise we can't read its properties.
+  if (mapper.registerBuffer(handle) != OK) {
+    ALOGE("Failed to register buffer");
+    return nullptr;
+  }
+
+  if (mapper.getDimensions(handle, &width, &height) ||
+      mapper.getStride(handle, &stride) ||
+      mapper.getFormat(handle, &format) ||
+      mapper.getProducerUsage(handle, &producer_usage) ||
+      mapper.getConsumerUsage(handle, &consumer_usage)) {
+    ALOGE("Failed to read handle properties");
+    return nullptr;
+  }
+
+  // This will only succeed if gralloc has GRALLOC1_CAPABILITY_LAYERED_BUFFERS
+  // capability. Otherwise assume a count of 1.
+  mapper.getLayerCount(handle, &layer_count);
+
+  sp<GraphicBuffer> buffer = new GraphicBuffer(
+      width, height, format, layer_count, producer_usage, consumer_usage,
+      stride, handle, true);
+
+  return buffer;
+}
+
+}  // namespace
+
+ParcelableComposerLayer::ParcelableComposerLayer() {}
+
+ParcelableComposerLayer::ParcelableComposerLayer(
+    const ComposerView::ComposerLayer& layer) : layer_(layer) {}
+
+ParcelableComposerLayer::~ParcelableComposerLayer() {}
+
+status_t ParcelableComposerLayer::writeToParcel(Parcel* parcel) const {
+  status_t ret = parcel->writeUint64(layer_.id);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeNativeHandle(layer_.buffer->getNativeBuffer()->handle);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeBool(layer_.fence->isValid());
+  if (ret != OK) return ret;
+
+  if (layer_.fence->isValid()) {
+    ret = parcel->writeFileDescriptor(layer_.fence->dup(), true);
+    if (ret != OK) return ret;
+  }
+
+  ret = parcel->writeInt32(layer_.display_frame.left);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeInt32(layer_.display_frame.top);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeInt32(layer_.display_frame.right);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeInt32(layer_.display_frame.bottom);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeFloat(layer_.crop.left);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeFloat(layer_.crop.top);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeFloat(layer_.crop.right);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeFloat(layer_.crop.bottom);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeInt32(static_cast<int32_t>(layer_.blend_mode));
+  if (ret != OK) return ret;
+
+  ret = parcel->writeFloat(layer_.alpha);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeUint32(layer_.type);
+  if (ret != OK) return ret;
+
+  ret = parcel->writeUint32(layer_.app_id);
+  if (ret != OK) return ret;
+
+  return OK;
+}
+
+status_t ParcelableComposerLayer::readFromParcel(const Parcel* parcel) {
+  status_t ret = parcel->readUint64(&layer_.id);
+  if (ret != OK) return ret;
+
+  native_handle* handle = parcel->readNativeHandle();
+  if (!handle) return BAD_VALUE;
+
+  layer_.buffer = GetBufferFromHandle(handle);
+  if (!layer_.buffer.get()) return BAD_VALUE;
+
+  bool has_fence = 0;
+  ret = parcel->readBool(&has_fence);
+  if (ret != OK) return ret;
+
+  if (has_fence)
+    layer_.fence = new Fence(dup(parcel->readFileDescriptor()));
+  else
+    layer_.fence = new Fence();
+
+  ret = parcel->readInt32(&layer_.display_frame.left);
+  if (ret != OK) return ret;
+
+  ret = parcel->readInt32(&layer_.display_frame.top);
+  if (ret != OK) return ret;
+
+  ret = parcel->readInt32(&layer_.display_frame.right);
+  if (ret != OK) return ret;
+
+  ret = parcel->readInt32(&layer_.display_frame.bottom);
+  if (ret != OK) return ret;
+
+  ret = parcel->readFloat(&layer_.crop.left);
+  if (ret != OK) return ret;
+
+  ret = parcel->readFloat(&layer_.crop.top);
+  if (ret != OK) return ret;
+
+  ret = parcel->readFloat(&layer_.crop.right);
+  if (ret != OK) return ret;
+
+  ret = parcel->readFloat(&layer_.crop.bottom);
+  if (ret != OK) return ret;
+
+  ret = parcel->readInt32(reinterpret_cast<int32_t*>(&layer_.blend_mode));
+  if (ret != OK) return ret;
+
+  ret = parcel->readFloat(&layer_.alpha);
+  if (ret != OK) return ret;
+
+  ret = parcel->readUint32(&layer_.type);
+  if (ret != OK) return ret;
+
+  ret = parcel->readUint32(&layer_.app_id);
+  if (ret != OK) return ret;
+
+  return OK;
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.h b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.h
new file mode 100644
index 0000000..4cf48f1
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.h
@@ -0,0 +1,30 @@
+#ifndef ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_LAYER_H
+#define ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_LAYER_H
+
+#include <binder/Parcelable.h>
+#include <impl/vr_hwc.h>
+
+#include <memory>
+
+namespace android {
+namespace dvr {
+
+class ParcelableComposerLayer : public Parcelable {
+ public:
+  ParcelableComposerLayer();
+  ParcelableComposerLayer(const ComposerView::ComposerLayer& layer);
+  ~ParcelableComposerLayer() override;
+
+  ComposerView::ComposerLayer layer() const { return layer_; }
+
+  status_t writeToParcel(Parcel* parcel) const override;
+  status_t readFromParcel(const Parcel* parcel) override;
+
+ private:
+  ComposerView::ComposerLayer layer_;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_COMPOSER_LAYER_H
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.cpp b/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.cpp
new file mode 100644
index 0000000..9486f3c
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.cpp
@@ -0,0 +1,37 @@
+#include "android/dvr/parcelable_unique_fd.h"
+
+#include <binder/Parcel.h>
+
+namespace android {
+namespace dvr {
+
+ParcelableUniqueFd::ParcelableUniqueFd() {}
+
+ParcelableUniqueFd::ParcelableUniqueFd(const base::unique_fd& fence)
+    : fence_(dup(fence.get())) {}
+
+ParcelableUniqueFd::~ParcelableUniqueFd() {}
+
+status_t ParcelableUniqueFd::writeToParcel(Parcel* parcel) const {
+  status_t ret = parcel->writeBool(fence_.get() >= 0);
+  if (ret != OK) return ret;
+
+  if (fence_.get() >= 0)
+    ret = parcel->writeUniqueFileDescriptor(fence_);
+
+  return ret;
+}
+
+status_t ParcelableUniqueFd::readFromParcel(const Parcel* parcel) {
+  bool has_fence = 0;
+  status_t ret = parcel->readBool(&has_fence);
+  if (ret != OK) return ret;
+
+  if (has_fence)
+    ret = parcel->readUniqueFileDescriptor(&fence_);
+
+  return ret;
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.h b/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.h
new file mode 100644
index 0000000..daf9e6d
--- /dev/null
+++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.h
@@ -0,0 +1,34 @@
+#ifndef ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_UNIQUE_FD_H
+#define ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_UNIQUE_FD_H
+
+#include <android-base/unique_fd.h>
+#include <binder/Parcelable.h>
+
+namespace android {
+namespace dvr {
+
+// Provide a wrapper to serialized base::unique_fd. The wrapper also handles the
+// case where the FD is invalid (-1), unlike FileDescriptor which expects a
+// valid FD.
+class ParcelableUniqueFd : public Parcelable {
+ public:
+  ParcelableUniqueFd();
+  ParcelableUniqueFd(const base::unique_fd& fence);
+  ~ParcelableUniqueFd() override;
+
+  void set_fence(const base::unique_fd& fence) {
+    fence_.reset(dup(fence.get()));
+  }
+  base::unique_fd fence() const { return base::unique_fd(dup(fence_.get())); }
+
+  status_t writeToParcel(Parcel* parcel) const override;
+  status_t readFromParcel(const Parcel* parcel) override;
+
+ private:
+  base::unique_fd fence_;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_HARDWARE_COMPOSER_AIDL_ANDROID_DVR_PARCELABLE_UNIQUE_FD_H
diff --git a/services/vr/hardware_composer/dvr_hardware_composer_client.cpp b/services/vr/hardware_composer/dvr_hardware_composer_client.cpp
new file mode 100644
index 0000000..39fa9fc
--- /dev/null
+++ b/services/vr/hardware_composer/dvr_hardware_composer_client.cpp
@@ -0,0 +1,136 @@
+#include "private/android/dvr_hardware_composer_client.h"
+
+#include <android/dvr/IVrComposer.h>
+#include <android/dvr/BnVrComposerCallback.h>
+#include <binder/IServiceManager.h>
+#include <private/android/AHardwareBufferHelpers.h>
+
+#include <memory>
+
+struct DvrHwcFrame {
+  android::dvr::ComposerView::Frame frame;
+};
+
+namespace {
+
+class HwcCallback : public android::dvr::BnVrComposerCallback {
+ public:
+  explicit HwcCallback(DvrHwcOnFrameCallback callback);
+  ~HwcCallback() override;
+
+  std::unique_ptr<DvrHwcFrame> DequeueFrame();
+
+ private:
+  // android::dvr::BnVrComposerCallback:
+  android::binder::Status onNewFrame(
+      const android::dvr::ParcelableComposerFrame& frame,
+      android::dvr::ParcelableUniqueFd* fence) override;
+
+  DvrHwcOnFrameCallback callback_;
+
+  HwcCallback(const HwcCallback&) = delete;
+  void operator=(const HwcCallback&) = delete;
+};
+
+HwcCallback::HwcCallback(DvrHwcOnFrameCallback callback)
+    : callback_(callback) {}
+
+HwcCallback::~HwcCallback() {}
+
+android::binder::Status HwcCallback::onNewFrame(
+    const android::dvr::ParcelableComposerFrame& frame,
+    android::dvr::ParcelableUniqueFd* fence) {
+  std::unique_ptr<DvrHwcFrame> dvr_frame(new DvrHwcFrame());
+  dvr_frame->frame = frame.frame();
+
+  fence->set_fence(android::base::unique_fd(callback_(dvr_frame.release())));
+  return android::binder::Status::ok();
+}
+
+}  // namespace
+
+struct DvrHwcClient {
+  android::sp<android::dvr::IVrComposer> composer;
+  android::sp<HwcCallback> callback;
+};
+
+DvrHwcClient* dvrHwcCreateClient(DvrHwcOnFrameCallback callback) {
+  std::unique_ptr<DvrHwcClient> client(new DvrHwcClient());
+
+  android::sp<android::IServiceManager> sm(android::defaultServiceManager());
+  client->composer = android::interface_cast<android::dvr::IVrComposer>(
+      sm->getService(android::dvr::IVrComposer::SERVICE_NAME()));
+  if (!client->composer.get())
+    return nullptr;
+
+  client->callback = new HwcCallback(callback);
+  android::binder::Status status = client->composer->registerObserver(
+      client->callback);
+  if (!status.isOk())
+    return nullptr;
+
+  return client.release();
+}
+
+void dvrHwcFrameDestroy(DvrHwcFrame* frame) {
+  delete frame;
+}
+
+Display dvrHwcFrameGetDisplayId(DvrHwcFrame* frame) {
+  return frame->frame.display_id;
+}
+
+size_t dvrHwcFrameGetLayerCount(DvrHwcFrame* frame) {
+  return frame->frame.layers.size();
+}
+
+Layer dvrHwcFrameGetLayerId(DvrHwcFrame* frame, size_t layer_index) {
+  return frame->frame.layers[layer_index].id;
+}
+
+AHardwareBuffer* dvrHwcFrameGetLayerBuffer(DvrHwcFrame* frame,
+                                           size_t layer_index) {
+  AHardwareBuffer* buffer = android::AHardwareBuffer_from_GraphicBuffer(
+      frame->frame.layers[layer_index].buffer.get());
+  AHardwareBuffer_acquire(buffer);
+  return buffer;
+}
+
+int dvrHwcFrameGetLayerFence(DvrHwcFrame* frame, size_t layer_index) {
+  return frame->frame.layers[layer_index].fence->dup();
+}
+
+Recti dvrHwcFrameGetLayerDisplayFrame(DvrHwcFrame* frame, size_t layer_index) {
+  return Recti{
+    frame->frame.layers[layer_index].display_frame.left,
+    frame->frame.layers[layer_index].display_frame.top,
+    frame->frame.layers[layer_index].display_frame.right,
+    frame->frame.layers[layer_index].display_frame.bottom,
+  };
+}
+
+Rectf dvrHwcFrameGetLayerCrop(DvrHwcFrame* frame, size_t layer_index) {
+  return Rectf{
+    frame->frame.layers[layer_index].crop.left,
+    frame->frame.layers[layer_index].crop.top,
+    frame->frame.layers[layer_index].crop.right,
+    frame->frame.layers[layer_index].crop.bottom,
+  };
+}
+
+BlendMode dvrHwcFrameGetLayerBlendMode(DvrHwcFrame* frame, size_t layer_index) {
+  return static_cast<BlendMode>(frame->frame.layers[layer_index].blend_mode);
+}
+
+float dvrHwcFrameGetLayerAlpha(DvrHwcFrame* frame, size_t layer_index) {
+  return frame->frame.layers[layer_index].alpha;
+}
+
+uint32_t dvrHwcFrameGetLayerType(DvrHwcFrame* frame, size_t layer_index) {
+  return frame->frame.layers[layer_index].type;
+}
+
+uint32_t dvrHwcFrameGetLayerApplicationId(DvrHwcFrame* frame,
+                                          size_t layer_index) {
+  return frame->frame.layers[layer_index].app_id;
+}
diff --git a/services/vr/hardware_composer/private/android/dvr_hardware_composer_client.h b/services/vr/hardware_composer/private/android/dvr_hardware_composer_client.h
new file mode 100644
index 0000000..063c16d
--- /dev/null
+++ b/services/vr/hardware_composer/private/android/dvr_hardware_composer_client.h
@@ -0,0 +1,62 @@
+#ifndef VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_DVR_HARDWARE_COMPOSER_CLIENT_H
+#define VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_DVR_HARDWARE_COMPOSER_CLIENT_H
+
+#include <android/dvr_hardware_composer_defs.h>
+#include <android/hardware_buffer.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct DvrHwcClient DvrHwcClient;
+typedef struct DvrHwcFrame DvrHwcFrame;
+
+// Called when a new frame has arrived.
+//
+// @param frame New frame. Owned by the client.
+// @return fence FD for the release of the last frame.
+typedef int(*DvrHwcOnFrameCallback)(DvrHwcFrame* frame);
+
+DvrHwcClient* dvrHwcCreateClient(DvrHwcOnFrameCallback callback);
+
+// Called to free the frame information.
+void dvrHwcFrameDestroy(DvrHwcFrame* frame);
+
+Display dvrHwcFrameGetDisplayId(DvrHwcFrame* frame);
+
+// @return Number of layers in the frame.
+size_t dvrHwcFrameGetLayerCount(DvrHwcFrame* frame);
+
+Layer dvrHwcFrameGetLayerId(DvrHwcFrame* frame, size_t layer_index);
+
+// Return the graphic buffer associated with the layer at |layer_index| in
+// |frame|.
+//
+// @return Graphic buffer. Caller owns the buffer and is responsible for freeing
+// it. (see AHardwareBuffer_release())
+AHardwareBuffer* dvrHwcFrameGetLayerBuffer(DvrHwcFrame* frame,
+                                           size_t layer_index);
+
+// Returns the fence FD for the layer at index |layer_index| in |frame|.
+//
+// @return Fence FD. Caller owns the FD and is responsible for closing it.
+int dvrHwcFrameGetLayerFence(DvrHwcFrame* frame, size_t layer_index);
+
+Recti dvrHwcFrameGetLayerDisplayFrame(DvrHwcFrame* frame, size_t layer_index);
+
+Rectf dvrHwcFrameGetLayerCrop(DvrHwcFrame* frame, size_t layer_index);
+
+BlendMode dvrHwcFrameGetLayerBlendMode(DvrHwcFrame* frame, size_t layer_index);
+
+float dvrHwcFrameGetLayerAlpha(DvrHwcFrame* frame, size_t layer_index);
+
+uint32_t dvrHwcFrameGetLayerType(DvrHwcFrame* frame, size_t layer_index);
+
+uint32_t dvrHwcFrameGetLayerApplicationId(DvrHwcFrame* frame,
+                                          size_t layer_index);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_DVR_HARDWARE_COMPOSER_CLIENT_H
diff --git a/services/vr/hardware_composer/private/android/dvr_hardware_composer_defs.h b/services/vr/hardware_composer/private/android/dvr_hardware_composer_defs.h
new file mode 100644
index 0000000..3186f82
--- /dev/null
+++ b/services/vr/hardware_composer/private/android/dvr_hardware_composer_defs.h
@@ -0,0 +1,50 @@
+#ifndef VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_VR_HARDWARE_COMPOSER_DEFS_H
+#define VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_VR_HARDWARE_COMPOSER_DEFS_H
+
+#include <inttypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// NOTE: These definitions must match the ones in
+// //hardware/libhardware/include/hardware/hwcomposer2.h. They are used by the
+// client side which does not have access to hwc2 headers.
+enum BlendMode {
+  BLEND_MODE_INVALID = 0,
+  BLEND_MODE_NONE = 1,
+  BLEND_MODE_PREMULTIPLIED = 2,
+  BLEND_MODE_COVERAGE = 3,
+};
+
+enum Composition {
+  COMPOSITION_INVALID = 0,
+  COMPOSITION_CLIENT = 1,
+  COMPOSITION_DEVICE = 2,
+  COMPOSITION_SOLID_COLOR = 3,
+  COMPOSITION_CURSOR = 4,
+  COMPOSITION_SIDEBAND = 5,
+};
+
+typedef uint64_t Display;
+typedef uint64_t Layer;
+
+struct Recti {
+  int32_t left;
+  int32_t top;
+  int32_t right;
+  int32_t bottom;
+};
+
+struct Rectf {
+  float left;
+  float top;
+  float right;
+  float bottom;
+};
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_DVR_HARDWARE_COMPOSER_DEFS_H
diff --git a/services/vr/hardware_composer/tests/vr_composer_test.cpp b/services/vr/hardware_composer/tests/vr_composer_test.cpp
new file mode 100644
index 0000000..cfc2708
--- /dev/null
+++ b/services/vr/hardware_composer/tests/vr_composer_test.cpp
@@ -0,0 +1,147 @@
+#include <android/dvr/BnVrComposerCallback.h>
+#include <binder/IServiceManager.h>
+#include <gtest/gtest.h>
+#include <sys/eventfd.h>
+#include <vr_composer.h>
+
+namespace android {
+namespace dvr {
+namespace {
+
+const char kVrDisplayName[] = "VrDisplay_Test";
+
+class TestComposerCallback : public BnVrComposerCallback {
+ public:
+  TestComposerCallback() {}
+  ~TestComposerCallback() override = default;
+
+  ComposerView::Frame last_frame() const { return last_frame_; }
+
+  binder::Status onNewFrame(
+      const ParcelableComposerFrame& frame,
+      ParcelableUniqueFd* /* fence */) override {
+    last_frame_ = frame.frame();
+    return binder::Status::ok();
+  }
+
+ private:
+  ComposerView::Frame last_frame_;
+
+  TestComposerCallback(const TestComposerCallback&) = delete;
+  void operator=(const TestComposerCallback&) = delete;
+};
+
+class TestComposerCallbackWithFence : public TestComposerCallback {
+ public:
+  ~TestComposerCallbackWithFence() override = default;
+
+  binder::Status onNewFrame(
+      const ParcelableComposerFrame& frame,
+      ParcelableUniqueFd* fence) override {
+    binder::Status status = TestComposerCallback::onNewFrame(frame, fence);
+
+    base::unique_fd fd(eventfd(0, 0));
+    EXPECT_LE(0, fd.get());
+    fence->set_fence(fd);
+
+    return status;
+  }
+};
+
+sp<GraphicBuffer> CreateBuffer() {
+  return new GraphicBuffer(600, 400, PIXEL_FORMAT_RGBA_8888,
+                           GraphicBuffer::USAGE_HW_TEXTURE);
+}
+
+}  // namespace
+
+class VrComposerTest : public testing::Test {
+ public:
+  VrComposerTest() : composer_(new VrComposer()) {}
+  ~VrComposerTest() override = default;
+
+  sp<IVrComposer> GetComposerProxy() const {
+    sp<IServiceManager> sm(defaultServiceManager());
+    return interface_cast<IVrComposer>(sm->getService(String16(kVrDisplayName)));
+  }
+
+  void SetUp() override {
+    sp<IServiceManager> sm(defaultServiceManager());
+    EXPECT_EQ(OK,
+              sm->addService(String16(kVrDisplayName), composer_, false));
+  }
+
+ protected:
+  sp<VrComposer> composer_;
+
+  VrComposerTest(const VrComposerTest&) = delete;
+  void operator=(const VrComposerTest&) = delete;
+};
+
+TEST_F(VrComposerTest, TestWithoutObserver) {
+  sp<IVrComposer> composer = GetComposerProxy();
+  ComposerView::Frame frame;
+
+  base::unique_fd fence = composer_->OnNewFrame(frame);
+  ASSERT_EQ(-1, fence.get());
+}
+
+TEST_F(VrComposerTest, TestWithObserver) {
+  sp<IVrComposer> composer = GetComposerProxy();
+  sp<TestComposerCallback> callback = new TestComposerCallback();
+  ASSERT_TRUE(composer->registerObserver(callback).isOk());
+
+  ComposerView::Frame frame;
+  base::unique_fd fence = composer_->OnNewFrame(frame);
+  ASSERT_EQ(-1, fence.get());
+}
+
+TEST_F(VrComposerTest, TestWithOneLayer) {
+  sp<IVrComposer> composer = GetComposerProxy();
+  sp<TestComposerCallback> callback = new TestComposerCallbackWithFence();
+  ASSERT_TRUE(composer->registerObserver(callback).isOk());
+
+  ComposerView::Frame frame;
+  frame.display_id = 1;
+  frame.removed = false;
+  frame.layers.push_back(ComposerView::ComposerLayer{
+    .id = 1,
+    .buffer = CreateBuffer(),
+    .fence = new Fence(eventfd(0, 0)),
+    .display_frame = {0, 0, 600, 400},
+    .crop = {0.0f, 0.0f, 600.0f, 400.0f},
+    .blend_mode = IComposerClient::BlendMode::NONE,
+    .alpha = 1.0f,
+    .type = 1,
+    .app_id = 1,
+  });
+  base::unique_fd fence = composer_->OnNewFrame(frame);
+  ASSERT_LE(0, fence.get());
+
+  ComposerView::Frame received_frame = callback->last_frame();
+  ASSERT_EQ(frame.display_id, received_frame.display_id);
+  ASSERT_EQ(frame.removed, received_frame.removed);
+  ASSERT_EQ(1u, received_frame.layers.size());
+  ASSERT_EQ(frame.layers[0].id, received_frame.layers[0].id);
+  ASSERT_NE(nullptr, received_frame.layers[0].buffer.get());
+  ASSERT_TRUE(received_frame.layers[0].fence->isValid());
+  ASSERT_EQ(frame.layers[0].display_frame.left,
+            received_frame.layers[0].display_frame.left);
+  ASSERT_EQ(frame.layers[0].display_frame.top,
+            received_frame.layers[0].display_frame.top);
+  ASSERT_EQ(frame.layers[0].display_frame.right,
+            received_frame.layers[0].display_frame.right);
+  ASSERT_EQ(frame.layers[0].display_frame.bottom,
+            received_frame.layers[0].display_frame.bottom);
+  ASSERT_EQ(frame.layers[0].crop.left, received_frame.layers[0].crop.left);
+  ASSERT_EQ(frame.layers[0].crop.top, received_frame.layers[0].crop.top);
+  ASSERT_EQ(frame.layers[0].crop.right, received_frame.layers[0].crop.right);
+  ASSERT_EQ(frame.layers[0].crop.bottom, received_frame.layers[0].crop.bottom);
+  ASSERT_EQ(frame.layers[0].blend_mode, received_frame.layers[0].blend_mode);
+  ASSERT_EQ(frame.layers[0].alpha, received_frame.layers[0].alpha);
+  ASSERT_EQ(frame.layers[0].type, received_frame.layers[0].type);
+  ASSERT_EQ(frame.layers[0].app_id, received_frame.layers[0].app_id);
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/services/vr/hardware_composer/vr_composer.cpp b/services/vr/hardware_composer/vr_composer.cpp
new file mode 100644
index 0000000..c15f8fd
--- /dev/null
+++ b/services/vr/hardware_composer/vr_composer.cpp
@@ -0,0 +1,46 @@
+#include "vr_composer.h"
+
+namespace android {
+namespace dvr {
+
+VrComposer::VrComposer() {}
+
+VrComposer::~VrComposer() {}
+
+binder::Status VrComposer::registerObserver(
+    const sp<IVrComposerCallback>& callback) {
+  std::lock_guard<std::mutex> guard(mutex_);
+
+  if (callback_.get()) {
+    ALOGE("Failed to register callback, already registered");
+    return binder::Status::fromStatusT(ALREADY_EXISTS);
+  }
+
+  callback_ = callback;
+  IInterface::asBinder(callback_)->linkToDeath(this);
+  return binder::Status::ok();
+}
+
+base::unique_fd VrComposer::OnNewFrame(const ComposerView::Frame& frame) {
+  std::lock_guard<std::mutex> guard(mutex_);
+
+  if (!callback_.get())
+    return base::unique_fd();
+
+  ParcelableComposerFrame parcelable_frame(frame);
+  ParcelableUniqueFd fence;
+  binder::Status ret = callback_->onNewFrame(parcelable_frame, &fence);
+  if (!ret.isOk())
+    ALOGE("Failed to send new frame: %s", ret.toString8().string());
+
+  return fence.fence();
+}
+
+void VrComposer::binderDied(const wp<IBinder>& /* who */) {
+  std::lock_guard<std::mutex> guard(mutex_);
+
+  callback_ = nullptr;
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/services/vr/hardware_composer/vr_composer.h b/services/vr/hardware_composer/vr_composer.h
new file mode 100644
index 0000000..93d1f2b
--- /dev/null
+++ b/services/vr/hardware_composer/vr_composer.h
@@ -0,0 +1,48 @@
+#ifndef ANDROID_DVR_HARDWARE_COMPOSER_VR_COMPOSER_H
+#define ANDROID_DVR_HARDWARE_COMPOSER_VR_COMPOSER_H
+
+#include <android/dvr/BnVrComposer.h>
+#include <impl/vr_hwc.h>
+
+namespace android {
+namespace dvr {
+
+class VrComposerCallback;
+
+// Implementation of the IVrComposer service used to notify VR Window Manager
+// when SurfaceFlinger presents 2D UI changes.
+//
+// VR HWC updates the presented frame via the ComposerView::Observer interface.
+// On notification |callback_| is called to update VR Window Manager.
+// NOTE: If VR Window Manager isn't connected, the notification is a no-op.
+class VrComposer
+    : public BnVrComposer,
+      public ComposerView::Observer,
+      public IBinder::DeathRecipient {
+ public:
+  VrComposer();
+  ~VrComposer() override;
+
+  // BnVrComposer:
+  binder::Status registerObserver(
+      const sp<IVrComposerCallback>& callback) override;
+
+  // ComposerView::Observer:
+  base::unique_fd OnNewFrame(const ComposerView::Frame& frame) override;
+
+ private:
+  // IBinder::DeathRecipient:
+  void binderDied(const wp<IBinder>& who) override;
+
+  std::mutex mutex_;
+
+  sp<IVrComposerCallback> callback_;
+
+  VrComposer(const VrComposer&) = delete;
+  void operator=(const VrComposer&) = delete;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  //  ANDROID_DVR_HARDWARE_COMPOSER_VR_COMPOSER_H
diff --git a/services/vr/hardware_composer/vr_hardware_composer_service.cpp b/services/vr/hardware_composer/vr_hardware_composer_service.cpp
new file mode 100644
index 0000000..9591748
--- /dev/null
+++ b/services/vr/hardware_composer/vr_hardware_composer_service.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright 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 <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+#include <hwbinder/IPCThreadState.h>
+#include <impl/vr_hwc.h>
+#include <inttypes.h>
+
+#include "vr_composer.h"
+
+int main() {
+  android::ProcessState::self()->startThreadPool();
+
+  // Register the hwbinder HWC HAL service used by SurfaceFlinger while in VR
+  // mode.
+  const char instance[] = "vr_hwcomposer";
+  android::sp<IComposer> service =
+      android::dvr::HIDL_FETCH_IComposer(instance);
+
+  LOG_ALWAYS_FATAL_IF(!service.get(), "Failed to get service");
+  LOG_ALWAYS_FATAL_IF(service->isRemote(), "Service is remote");
+
+  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());
+
+  android::sp<android::IServiceManager> sm(android::defaultServiceManager());
+
+  // Register the binder service used by VR Window Manager service to receive
+  // frame information from VR HWC HAL.
+  android::status_t status = sm->addService(
+      android::dvr::VrComposer::SERVICE_NAME(), composer.get(),
+      false /* allowIsolated */);
+  LOG_ALWAYS_FATAL_IF(status != android::OK,
+                      "VrDisplay service failed to start: %" PRId32, status);
+
+  android::hardware::ProcessState::self()->startThreadPool();
+  android::hardware::IPCThreadState::self()->joinThreadPool();
+
+  composer_view->UnregisterObserver(composer.get());
+
+  return 0;
+}
diff --git a/services/vr/hardware_composer/vr_hwc.rc b/services/vr/hardware_composer/vr_hwc.rc
new file mode 100644
index 0000000..5d3c4f7
--- /dev/null
+++ b/services/vr/hardware_composer/vr_hwc.rc
@@ -0,0 +1,6 @@
+service vr_hwc /system/bin/vr_hwc
+  class hal
+  user system
+  group system graphics
+  onrestart restart surfaceflinger
+  disabled
diff --git a/services/vr/performanced/performanced.rc b/services/vr/performanced/performanced.rc
index 754c97f..5042982 100644
--- a/services/vr/performanced/performanced.rc
+++ b/services/vr/performanced/performanced.rc
@@ -2,4 +2,4 @@
   class core
   user root
   group system readproc
-  cpuset /
+  writepid /dev/cpuset/tasks
diff --git a/services/vr/sensord/Android.mk b/services/vr/sensord/Android.mk
index f9a1cec..ba0821b 100644
--- a/services/vr/sensord/Android.mk
+++ b/services/vr/sensord/Android.mk
@@ -44,6 +44,7 @@
 	liblog \
 	libhardware \
 	libutils \
+        libui \
 	$(SENSORD_EXTEND) \
 
 cFlags := -DLOG_TAG=\"sensord\" \
diff --git a/services/vr/sensord/sensord.rc b/services/vr/sensord/sensord.rc
index d868a7e..f8d28fd 100644
--- a/services/vr/sensord/sensord.rc
+++ b/services/vr/sensord/sensord.rc
@@ -6,4 +6,4 @@
   class core
   user system
   group system camera sdcard_rw
-  cpuset /system
+  writepid /dev/cpuset/system/tasks
diff --git a/services/vr/virtual_touchpad/Android.bp b/services/vr/virtual_touchpad/Android.bp
index ad999b7..c8bc884 100644
--- a/services/vr/virtual_touchpad/Android.bp
+++ b/services/vr/virtual_touchpad/Android.bp
@@ -94,6 +94,7 @@
 
 client_src = [
     "VirtualTouchpadClient.cpp",
+    "DvrVirtualTouchpadClient.cpp",
     "aidl/android/dvr/VirtualTouchpadService.aidl",
 ]
 
diff --git a/services/vr/virtual_touchpad/DvrVirtualTouchpadClient.cpp b/services/vr/virtual_touchpad/DvrVirtualTouchpadClient.cpp
new file mode 100644
index 0000000..eb152ed
--- /dev/null
+++ b/services/vr/virtual_touchpad/DvrVirtualTouchpadClient.cpp
@@ -0,0 +1,45 @@
+#include "VirtualTouchpadClient.h"
+#include "dvr/virtual_touchpad_client.h"
+
+struct DvrVirtualTouchpad {};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+namespace {
+android::dvr::VirtualTouchpad* FromC(DvrVirtualTouchpad* client) {
+  return reinterpret_cast<android::dvr::VirtualTouchpad*>(client);
+}
+}  // namespace
+
+DvrVirtualTouchpad* dvrVirtualTouchpadCreate() {
+  return reinterpret_cast<DvrVirtualTouchpad*>(
+      android::dvr::VirtualTouchpadClient::Create().release());
+}
+
+void dvrVirtualTouchpadDestroy(DvrVirtualTouchpad* client) {
+  delete FromC(client);
+}
+
+int dvrVirtualTouchpadAttach(DvrVirtualTouchpad* client) {
+  return FromC(client)->Attach();
+}
+
+int dvrVirtualTouchpadDetach(DvrVirtualTouchpad* client) {
+  return FromC(client)->Detach();
+}
+
+int dvrVirtualTouchpadTouch(DvrVirtualTouchpad* client, int touchpad, float x,
+                            float y, float pressure) {
+  return FromC(client)->Touch(touchpad, x, y, pressure);
+}
+
+int dvrVirtualTouchpadButtonState(DvrVirtualTouchpad* client, int touchpad,
+                                  int buttons) {
+  return FromC(client)->ButtonState(touchpad, buttons);
+}
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp b/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp
index 782b19c..c7c8184 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp
@@ -72,8 +72,8 @@
 
 }  // anonymous namespace
 
-sp<VirtualTouchpad> VirtualTouchpadClient::Create() {
-  return new VirtualTouchpadClientImpl();
+std::unique_ptr<VirtualTouchpad> VirtualTouchpadClient::Create() {
+  return std::unique_ptr<VirtualTouchpad>(new VirtualTouchpadClientImpl());
 }
 
 }  // namespace dvr
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
index 92193d3..ee09d48 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
@@ -30,10 +30,10 @@
 
 }  // anonymous namespace
 
-sp<VirtualTouchpad> VirtualTouchpadEvdev::Create() {
-  VirtualTouchpadEvdev* const touchpad = new VirtualTouchpadEvdev();
+std::unique_ptr<VirtualTouchpad> VirtualTouchpadEvdev::Create() {
+  std::unique_ptr<VirtualTouchpadEvdev> touchpad(new VirtualTouchpadEvdev());
   touchpad->Reset();
-  return sp<VirtualTouchpad>(touchpad);
+  return touchpad;
 }
 
 void VirtualTouchpadEvdev::Reset() {
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
index dbaca9a..2fb8ff3 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
+++ b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
@@ -1,8 +1,6 @@
 #ifndef ANDROID_DVR_VIRTUAL_TOUCHPAD_EVDEV_H
 #define ANDROID_DVR_VIRTUAL_TOUCHPAD_EVDEV_H
 
-#include <memory>
-
 #include "EvdevInjector.h"
 #include "VirtualTouchpad.h"
 
@@ -15,7 +13,8 @@
 //
 class VirtualTouchpadEvdev : public VirtualTouchpad {
  public:
-  static sp<VirtualTouchpad> Create();
+  static std::unique_ptr<VirtualTouchpad> Create();
+  ~VirtualTouchpadEvdev() override {}
 
   // VirtualTouchpad implementation:
   status_t Attach() override;
@@ -28,7 +27,6 @@
   static constexpr int kTouchpads = 2;
 
   VirtualTouchpadEvdev() {}
-  ~VirtualTouchpadEvdev() override {}
   void Reset();
 
   // Must be called only between construction (or Detach()) and Attach().
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
index 2e2f622..191bcfb 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
@@ -45,6 +45,8 @@
     // reported when the previous client performs any touchpad action.
     ALOGE("pid=%ld replaces %ld", static_cast<long>(pid),
           static_cast<long>(client_pid_));
+    client_pid_ = pid;
+    return binder::Status::ok();
   }
   client_pid_ = pid;
   if (const status_t error = touchpad_->Attach()) {
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.h b/services/vr/virtual_touchpad/VirtualTouchpadService.h
index 194d787..cf236f9 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadService.h
+++ b/services/vr/virtual_touchpad/VirtualTouchpadService.h
@@ -13,8 +13,8 @@
 //
 class VirtualTouchpadService : public BnVirtualTouchpadService {
  public:
-  VirtualTouchpadService(sp<VirtualTouchpad> touchpad)
-      : touchpad_(touchpad), client_pid_(0) {}
+  VirtualTouchpadService(std::unique_ptr<VirtualTouchpad> touchpad)
+      : touchpad_(std::move(touchpad)), client_pid_(0) {}
   ~VirtualTouchpadService() override;
 
  protected:
@@ -31,7 +31,7 @@
   bool CheckPermissions();
   bool CheckTouchPermission(pid_t* out_pid);
 
-  sp<VirtualTouchpad> touchpad_;
+  std::unique_ptr<VirtualTouchpad> touchpad_;
 
   // Only one client at a time can use the virtual touchpad.
   pid_t client_pid_;
diff --git a/services/vr/virtual_touchpad/include/VirtualTouchpad.h b/services/vr/virtual_touchpad/include/VirtualTouchpad.h
index b1ee700..da3a0b7 100644
--- a/services/vr/virtual_touchpad/include/VirtualTouchpad.h
+++ b/services/vr/virtual_touchpad/include/VirtualTouchpad.h
@@ -1,31 +1,34 @@
 #ifndef ANDROID_DVR_VIRTUAL_TOUCHPAD_INTERFACE_H
 #define ANDROID_DVR_VIRTUAL_TOUCHPAD_INTERFACE_H
 
+#include "dvr/virtual_touchpad_client.h"
+
+#include <memory>
 #include <utils/Errors.h>
-#include <utils/RefBase.h>
 #include <utils/String8.h>
-#include <utils/StrongPointer.h>
 
 namespace android {
 namespace dvr {
 
 // Provides a virtual touchpad for injecting events into the input system.
 //
-class VirtualTouchpad : public RefBase {
+class VirtualTouchpad {
  public:
   enum : int {
-    PRIMARY = 0,
-    VIRTUAL = 1,
+    PRIMARY = DVR_VIRTUAL_TOUCHPAD_PRIMARY,
+    VIRTUAL = DVR_VIRTUAL_TOUCHPAD_VIRTUAL,
   };
 
+  virtual ~VirtualTouchpad() {}
+
   // Create a virtual touchpad.
   // Implementations should provide this, and hide their constructors.
   // For the user, switching implementations should be as simple as changing
   // the class whose |Create()| is called.
   // Implementations should be minimial; major resource allocation should
   // be performed in Attach().
-  static sp<VirtualTouchpad> Create() {
-    return sp<VirtualTouchpad>();
+  static std::unique_ptr<VirtualTouchpad> Create() {
+    return nullptr;
   }
 
   // Initialize a virtual touchpad.
@@ -63,7 +66,6 @@
 
  protected:
   VirtualTouchpad() {}
-  ~VirtualTouchpad() override {}
 
  private:
   VirtualTouchpad(const VirtualTouchpad&) = delete;
diff --git a/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h b/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h
index 471d9e0..23fb9f8 100644
--- a/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h
+++ b/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h
@@ -12,7 +12,7 @@
 class VirtualTouchpadClient : public VirtualTouchpad {
  public:
   // VirtualTouchpad implementation:
-  static sp<VirtualTouchpad> Create();
+  static std::unique_ptr<VirtualTouchpad> Create();
   status_t Attach() override;
   status_t Detach() override;
   status_t Touch(int touchpad, float x, float y, float pressure) override;
diff --git a/services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h b/services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h
new file mode 100644
index 0000000..08cca1b
--- /dev/null
+++ b/services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h
@@ -0,0 +1,71 @@
+#ifndef ANDROID_DVR_VIRTUAL_TOUCHPAD_C_CLIENT_H
+#define ANDROID_DVR_VIRTUAL_TOUCHPAD_C_CLIENT_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.
+//
+DvrVirtualTouchpad* dvrVirtualTouchpadCreate();
+
+// Destroys a virtual touchpad client.
+//
+// @param client Pointer to the virtual touchpad client to be destroyed.
+//
+void dvrVirtualTouchpadDestroy(DvrVirtualTouchpad* client);
+
+// Initialize the virtual touchpad.
+//
+// In the current server implementation, attachment creates and configures
+// the kernel virtual touchpad device(s). A single client may be attached
+// and detached repeatedly, e.g. on entering and leaving VR mode.
+//
+// @param client Pointer to the virtual touchpad client to be attached.
+// @return Zero on success, status_t-style error code on failure.
+//
+int dvrVirtualTouchpadAttach(DvrVirtualTouchpad* client);
+
+// Shut down the virtual touchpad.
+//
+// @param client Pointer to the virtual touchpad client to be detached.
+// @return Zero on success, status_t-style error code on failure.
+//
+int dvrVirtualTouchpadDetach(DvrVirtualTouchpad* client);
+
+// Generate a simulated touch event.
+//
+// @param client Pointer to the virtual touchpad client.
+// @param touchpad Selects touchpad.
+// @param x Horizontal touch position.
+// @param y Vertical touch position.
+// @param pressure Touch pressure; use 0.0 for no touch (lift or hover).
+// @return Zero on success, status_t-style error code on failure.
+//
+int dvrVirtualTouchpadTouch(DvrVirtualTouchpad* client, int touchpad, float x,
+                            float y, float pressure);
+
+// Generate a simulated touchpad button state event.
+//
+// @param client Pointer to the virtual touchpad client.
+// @param touchpad Selects touchpad.
+// @param buttons A union of MotionEvent BUTTON_* values.
+// @return Zero on success, status_t-style error code on failure.
+//
+int dvrVirtualTouchpadButtonState(DvrVirtualTouchpad* client, int touchpad,
+                                  int buttons);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // ANDROID_DVR_VIRTUAL_TOUCHPAD_CLIENT_H
diff --git a/services/vr/virtual_touchpad/main.cpp b/services/vr/virtual_touchpad/main.cpp
index e73f8b9..68f1d70 100644
--- a/services/vr/virtual_touchpad/main.cpp
+++ b/services/vr/virtual_touchpad/main.cpp
@@ -9,7 +9,7 @@
 int main() {
   ALOGI("Starting");
   android::dvr::VirtualTouchpadService touchpad_service(
-      android::dvr::VirtualTouchpadEvdev::Create());
+      std::move(android::dvr::VirtualTouchpadEvdev::Create()));
 
   signal(SIGPIPE, SIG_IGN);
   android::sp<android::ProcessState> ps(android::ProcessState::self());
diff --git a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
index bc34850..24cfdf8 100644
--- a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
+++ b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
@@ -95,7 +95,9 @@
 
 class VirtualTouchpadForTesting : public VirtualTouchpadEvdev {
  public:
-  static sp<VirtualTouchpad> Create() { return sp<VirtualTouchpad>(New()); }
+  static std::unique_ptr<VirtualTouchpad> Create() {
+    return std::unique_ptr<VirtualTouchpad>(New());
+  }
   static VirtualTouchpadForTesting* New() {
     VirtualTouchpadForTesting* const touchpad = new VirtualTouchpadForTesting();
     touchpad->Reset();
@@ -124,7 +126,8 @@
 class VirtualTouchpadTest : public testing::Test {};
 
 TEST_F(VirtualTouchpadTest, Goodness) {
-  sp<VirtualTouchpadForTesting> touchpad(VirtualTouchpadForTesting::New());
+  std::unique_ptr<VirtualTouchpadForTesting> touchpad(
+      VirtualTouchpadForTesting::New());
   UInputRecorder expect;
 
   status_t touch_status = touchpad->Attach();
@@ -284,7 +287,8 @@
 }
 
 TEST_F(VirtualTouchpadTest, Badness) {
-  sp<VirtualTouchpadForTesting> touchpad(VirtualTouchpadForTesting::New());
+  std::unique_ptr<VirtualTouchpadForTesting> touchpad(
+      VirtualTouchpadForTesting::New());
   UInputRecorder expect;
   UInputRecorder& record = touchpad->injector[VirtualTouchpad::PRIMARY].record;
 
diff --git a/services/vr/virtual_touchpad/virtual_touchpad.rc b/services/vr/virtual_touchpad/virtual_touchpad.rc
index b4f9f00..99315ef 100644
--- a/services/vr/virtual_touchpad/virtual_touchpad.rc
+++ b/services/vr/virtual_touchpad/virtual_touchpad.rc
@@ -2,4 +2,4 @@
   class core
   user system
   group system input
-  cpuset /system
+  writepid /dev/cpuset/system/tasks
diff --git a/services/vr/vr_window_manager/aidl/android/service/vr/IVrWindowManager.aidl b/services/vr/vr_window_manager/aidl/android/service/vr/IVrWindowManager.aidl
index b5dbb8b..67fd927 100644
--- a/services/vr/vr_window_manager/aidl/android/service/vr/IVrWindowManager.aidl
+++ b/services/vr/vr_window_manager/aidl/android/service/vr/IVrWindowManager.aidl
@@ -24,5 +24,6 @@
     void enterVrMode() = 2;
     void exitVrMode() = 3;
     void setDebugMode(int mode) = 4;
+    void set2DMode(int mode) = 5;
 }
 
diff --git a/services/vr/vr_window_manager/application.cpp b/services/vr/vr_window_manager/application.cpp
index eb9f407..c7d7d50 100644
--- a/services/vr/vr_window_manager/application.cpp
+++ b/services/vr/vr_window_manager/application.cpp
@@ -25,7 +25,7 @@
   sp<IVrManager> vrManagerService = interface_cast<IVrManager>(
       defaultServiceManager()->getService(String16("vrmanager")));
   if (vrManagerService.get()) {
-    vrManagerService->unregisterListener(vr_mode_listener_);
+    vrManagerService->unregisterPersistentVrStateListener(vr_mode_listener_);
   }
 }
 
@@ -39,7 +39,7 @@
   sp<IVrManager> vrManagerService = interface_cast<IVrManager>(
       defaultServiceManager()->getService(String16("vrmanager")));
   if (vrManagerService.get()) {
-    vrManagerService->registerListener(vr_mode_listener_);
+    vrManagerService->registerPersistentVrStateListener(vr_mode_listener_);
   }
   return 0;
 }
@@ -112,6 +112,7 @@
 void Application::DeallocateResources() {
   if (graphics_context_)
     dvrGraphicsContextDestroy(graphics_context_);
+  graphics_context_ = nullptr;
 
   if (pose_client_)
     dvrPoseDestroy(pose_client_);
@@ -274,15 +275,13 @@
     }
     controller_data_provider_->UnlockControllerData();
     if (shmem_controller_active_) {
-      // TODO(kpschoedel): change to ALOGV or remove.
-      ALOGI("Controller shmem orientation: %f %f %f %f",
+      ALOGV("Controller shmem orientation: %f %f %f %f",
             controller_orientation_.x(), controller_orientation_.y(),
             controller_orientation_.z(), controller_orientation_.w());
       if (shmem_controller_buttons_) {
-        ALOGI("Controller shmem buttons: %017" PRIX64,
+        ALOGV("Controller shmem buttons: %017" PRIX64,
             shmem_controller_buttons_);
       }
-      return;
     }
   }
 }
@@ -315,7 +314,7 @@
   wake_up_init_and_render_.notify_one();
 }
 
-void Application::VrModeListener::onVrStateChanged(bool enabled) {
+void Application::VrModeListener::onPersistentVrStateChanged(bool enabled) {
   if (!enabled)
     app_->QueueTask(MainThreadTask::ExitingVrMode);
 }
diff --git a/services/vr/vr_window_manager/application.h b/services/vr/vr_window_manager/application.h
index 6215561..4b36ecc 100644
--- a/services/vr/vr_window_manager/application.h
+++ b/services/vr/vr_window_manager/application.h
@@ -44,10 +44,10 @@
     Show,
   };
 
-  class VrModeListener : public BnVrStateCallbacks {
+  class VrModeListener : public BnPersistentVrStateCallbacks {
    public:
     VrModeListener(Application *app) : app_(app) {}
-    void onVrStateChanged(bool enabled) override;
+    void onPersistentVrStateChanged(bool enabled) override;
 
    private:
     Application *app_;
diff --git a/services/vr/vr_window_manager/composer/Android.bp b/services/vr/vr_window_manager/composer/Android.bp
index 4349269..f28818a 100644
--- a/services/vr/vr_window_manager/composer/Android.bp
+++ b/services/vr/vr_window_manager/composer/Android.bp
@@ -34,6 +34,14 @@
     "libutils",
   ],
 
+  export_static_lib_headers: [
+    "libhwcomposer-client",
+  ],
+
+  export_shared_lib_headers: [
+    "android.hardware.graphics.composer@2.1",
+  ],
+
   export_include_dirs: ["."],
 
   cflags: [
diff --git a/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
index 60ca818..8aa2fd5 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
+++ b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
@@ -240,12 +240,14 @@
   }
 }
 
-uint32_t VrHwc::getMaxVirtualDisplayCount() { return 0; }
+uint32_t VrHwc::getMaxVirtualDisplayCount() { return 1; }
 
 Error VrHwc::createVirtualDisplay(uint32_t width, uint32_t height,
                                   PixelFormat* format, Display* outDisplay) {
   *format = PixelFormat::RGBA_8888;
-  *outDisplay = 0;
+  *outDisplay = display_count_;
+  displays_[display_count_].reset(new HwcDisplay());
+  display_count_++;
   return Error::NONE;
 }
 
@@ -312,12 +314,35 @@
     return Error::BAD_CONFIG;
   }
 
+  int error = 0;
+  auto display_client = DisplayClient::Create(&error);
+  SystemDisplayMetrics metrics;
+
+  if (error) {
+    ALOGE("Could not connect to display service : %s(%d)", strerror(error),
+          error);
+  } else {
+    error = display_client->GetDisplayMetrics(&metrics);
+
+    if (error) {
+      ALOGE("Could not get display metrics from display service : %s(%d)",
+            strerror(error), error);
+    }
+  }
+
+  if (error) {
+    metrics.display_native_width = 1080;
+    metrics.display_native_height = 1920;
+    ALOGI("Setting display metrics to default : width=%d height=%d",
+          metrics.display_native_width, metrics.display_native_height);
+  }
+
   switch (attribute) {
     case IComposerClient::Attribute::WIDTH:
-      *outValue = 1080;
+      *outValue = metrics.display_native_width;
       break;
     case IComposerClient::Attribute::HEIGHT:
-      *outValue = 1920;
+      *outValue = metrics.display_native_height;
       break;
     case IComposerClient::Attribute::VSYNC_PERIOD:
       *outValue = 1000 * 1000 * 1000 / 30;  // 30fps
@@ -356,7 +381,11 @@
     return Error::BAD_DISPLAY;
   }
 
-  *outType = IComposerClient::DisplayType::PHYSICAL;
+  if (display == kDefaultDisplayId)
+    *outType = IComposerClient::DisplayType::PHYSICAL;
+  else
+    *outType = IComposerClient::DisplayType::VIRTUAL;
+
   return Error::NONE;
 }
 
@@ -443,8 +472,8 @@
   if (!display_ptr)
     return Error::BAD_DISPLAY;
 
-  ALOGE("Virtual display support not implemented");
-  return Error::UNSUPPORTED;
+  // TODO(dnicoara): Is it necessary to do anything here?
+  return Error::NONE;
 }
 
 Error VrHwc::validateDisplay(
diff --git a/services/vr/vr_window_manager/composer/impl/vr_hwc.h b/services/vr/vr_window_manager/composer/impl/vr_hwc.h
index b869d3e..3c76120 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_hwc.h
+++ b/services/vr/vr_window_manager/composer/impl/vr_hwc.h
@@ -248,6 +248,7 @@
   std::mutex mutex_;
 
   std::unordered_map<Display, std::unique_ptr<HwcDisplay>> displays_;
+  Display display_count_ = 2;
 
   Observer* observer_ = nullptr;
 
diff --git a/services/vr/vr_window_manager/composer_view/vr_composer_view.rc b/services/vr/vr_window_manager/composer_view/vr_composer_view.rc
index abb5265..bd9982b 100644
--- a/services/vr/vr_window_manager/composer_view/vr_composer_view.rc
+++ b/services/vr/vr_window_manager/composer_view/vr_composer_view.rc
@@ -2,4 +2,4 @@
   class core
   user system
   group system graphics
-  cpuset /system
+  writepid /dev/cpuset/system/tasks
diff --git a/services/vr/vr_window_manager/display_view.cpp b/services/vr/vr_window_manager/display_view.cpp
index 5f1e73e..e88e7d0 100644
--- a/services/vr/vr_window_manager/display_view.cpp
+++ b/services/vr/vr_window_manager/display_view.cpp
@@ -8,8 +8,8 @@
 namespace {
 
 constexpr float kLayerScaleFactor = 3.0f;
-constexpr unsigned int kVRAppLayerCount = 2;
 constexpr unsigned int kMaximumPendingFrames = 8;
+constexpr uint32_t kSystemId = 1000;
 
 // clang-format off
 const GLfloat kVertices[] = {
@@ -99,12 +99,9 @@
 
 // Determine if ths frame should be shown or hidden.
 ViewMode CalculateVisibilityFromLayerConfig(const HwcCallback::Frame& frame,
-                                            uint32_t vr_app) {
+                                            uint32_t* appid) {
   auto& layers = frame.layers();
 
-  // TODO(achaulk): Figure out how to identify the current VR app for 2D app
-  // detection.
-
   size_t index;
   // Skip all layers that we don't know about.
   for (index = 0; index < layers.size(); index++) {
@@ -120,6 +117,11 @@
     return ViewMode::Hidden;
   }
 
+  if (layers[index].appid != *appid) {
+    *appid = layers[index].appid;
+    return ViewMode::App;
+  }
+
   // This is the VR app, ignore it.
   index++;
 
@@ -136,6 +138,7 @@
     if (!layers[i].should_skip_layer())
       return ViewMode::VR;
   }
+
   return ViewMode::Hidden;
 }
 
@@ -197,17 +200,27 @@
 }
 
 base::unique_fd DisplayView::OnFrame(std::unique_ptr<HwcCallback::Frame> frame,
-                                     bool debug_mode, bool* showing) {
-  ViewMode visibility =
-      CalculateVisibilityFromLayerConfig(*frame.get(), current_vr_app_);
+                                     bool debug_mode, bool is_vr_active,
+                                     bool* showing) {
+  uint32_t app = current_vr_app_;
+  ViewMode visibility = CalculateVisibilityFromLayerConfig(*frame.get(), &app);
 
   if (visibility == ViewMode::Hidden && debug_mode)
     visibility = ViewMode::VR;
 
-  if (frame->layers().empty())
+  if (frame->layers().empty()) {
     current_vr_app_ = 0;
-  else
-    current_vr_app_ = frame->layers().front().appid;
+  } else if (visibility == ViewMode::App) {
+    // This is either a VR app switch or a 2D app launching.
+    // If we can have VR apps, update if it's 0.
+    if (!always_2d_ && is_vr_active && !use_2dmode_ && app != kSystemId) {
+      visibility = ViewMode::Hidden;
+      current_vr_app_ = app;
+    }
+  } else if (!current_vr_app_) {
+    // The VR app is running.
+    current_vr_app_ = app;
+  }
 
   pending_frames_.emplace_back(std::move(frame), visibility);
 
diff --git a/services/vr/vr_window_manager/display_view.h b/services/vr/vr_window_manager/display_view.h
index 0a27781..0d1355e 100644
--- a/services/vr/vr_window_manager/display_view.h
+++ b/services/vr/vr_window_manager/display_view.h
@@ -23,7 +23,7 @@
 
   // Calls to these 3 functions must be synchronized.
   base::unique_fd OnFrame(std::unique_ptr<HwcCallback::Frame> frame,
-                          bool debug_mode, bool* showing);
+                          bool debug_mode, bool is_vr_active, bool* showing);
   void AdvanceFrame();
   void UpdateReleaseFence();
 
@@ -44,6 +44,9 @@
   uint32_t id() const { return id_; }
   int touchpad_id() const { return touchpad_id_; }
 
+  void set_2dmode(bool mode) { use_2dmode_ = mode; }
+  void set_always_2d(bool mode) { always_2d_ = mode; }
+
  private:
   bool IsHit(const vec3& view_location, const vec3& view_direction,
              vec3* hit_location, vec2* hit_location_in_window_coord,
@@ -79,6 +82,8 @@
   vec2 ime_top_left_;
   vec2 ime_size_;
   bool has_ime_ = false;
+  bool use_2dmode_ = false;
+  bool always_2d_ = false;
 
   struct PendingFrame {
     PendingFrame() = default;
diff --git a/services/vr/vr_window_manager/shell_view.cpp b/services/vr/vr_window_manager/shell_view.cpp
index 72a2c26..67ef5d4 100644
--- a/services/vr/vr_window_manager/shell_view.cpp
+++ b/services/vr/vr_window_manager/shell_view.cpp
@@ -4,7 +4,9 @@
 #include <GLES3/gl3.h>
 #include <android/input.h>
 #include <binder/IServiceManager.h>
+#include <dvr/graphics.h>
 #include <hardware/hwcomposer2.h>
+#include <inttypes.h>
 #include <log/log.h>
 
 #include "controller_mesh.h"
@@ -15,6 +17,8 @@
 
 namespace {
 
+constexpr uint32_t kPrimaryDisplayId = 1;
+
 const std::string kVertexShader = SHADER0([]() {
   layout(location = 0) in vec4 aPosition;
   layout(location = 1) in vec4 aTexCoord;
@@ -95,7 +99,8 @@
 }
 
 int GetTouchIdForDisplay(uint32_t display) {
-  return display == 1 ? VirtualTouchpad::PRIMARY : VirtualTouchpad::VIRTUAL;
+  return display == kPrimaryDisplayId ? DVR_VIRTUAL_TOUCHPAD_PRIMARY
+                                      : DVR_VIRTUAL_TOUCHPAD_VIRTUAL;
 }
 
 }  // namespace
@@ -109,8 +114,9 @@
   if (ret)
     return ret;
 
-  virtual_touchpad_ = VirtualTouchpadClient::Create();
-  const status_t touchpad_status = virtual_touchpad_->Attach();
+  virtual_touchpad_.reset(dvrVirtualTouchpadCreate());
+  const status_t touchpad_status =
+      dvrVirtualTouchpadAttach(virtual_touchpad_.get());
   if (touchpad_status != OK) {
     ALOGE("Failed to connect to virtual touchpad");
     return touchpad_status;
@@ -120,6 +126,10 @@
   if (!surface_flinger_view_->Initialize(this))
     return 1;
 
+  // This is a temporary fix for now. These APIs will be changed when everything
+  // is moved into vrcore.
+  display_client_ = DisplayClient::Create();
+
   return 0;
 }
 
@@ -164,13 +174,11 @@
 }
 
 void ShellView::EnableDebug(bool debug) {
-  ALOGI("EnableDebug(%d)", (int)debug);  // XXX TODO delete
   QueueTask(debug ? MainThreadTask::EnableDebugMode
                   : MainThreadTask::DisableDebugMode);
 }
 
 void ShellView::VrMode(bool mode) {
-  ALOGI("VrMode(%d)", (int)mode);  // XXX TODO delete
   QueueTask(mode ? MainThreadTask::EnteringVrMode
                  : MainThreadTask::ExitingVrMode);
 }
@@ -180,6 +188,18 @@
   result.appendFormat("initialized = %s\n", initialized_ ? "true" : "false");
   result.appendFormat("is_visible = %s\n", is_visible_ ? "true" : "false");
   result.appendFormat("debug_mode = %s\n\n", debug_mode_ ? "true" : "false");
+
+  result.append("[displays]\n");
+  result.appendFormat("count = %zu\n", displays_.size());
+  for (size_t i = 0; i < displays_.size(); ++i)
+    result.appendFormat(" display_id = %" PRId32 "\n", displays_[i]->id());
+
+  result.append("\n");
+}
+
+void ShellView::Set2DMode(bool mode) {
+  if (!displays_.empty())
+    displays_[0]->set_2dmode(mode);
 }
 
 void ShellView::OnDrawFrame() {
@@ -245,6 +265,9 @@
   }
 
   auto display = new DisplayView(id, GetTouchIdForDisplay(id));
+  // Virtual displays only ever have 2D apps so force it.
+  if (id != kPrimaryDisplayId)
+    display->set_always_2d(true);
   new_displays_.emplace_back(display);
   return display;
 }
@@ -260,7 +283,11 @@
 
   bool showing = false;
 
-  base::unique_fd fd(display->OnFrame(std::move(frame), debug_mode_, &showing));
+  // TODO(achaulk): change when moved into vrcore.
+  bool vr_running = display_client_->IsVrAppRunning();
+
+  base::unique_fd fd(
+      display->OnFrame(std::move(frame), debug_mode_, vr_running, &showing));
 
   if (showing)
     QueueTask(MainThreadTask::Show);
@@ -419,7 +446,7 @@
 }
 
 void ShellView::Touch() {
-  if (!virtual_touchpad_.get()) {
+  if (!virtual_touchpad_) {
     ALOGE("missing virtual touchpad");
     return;
   }
@@ -431,8 +458,8 @@
 
   // Device is portrait, but in landscape when in VR.
   // Rotate touch input appropriately.
-  const android::status_t status = virtual_touchpad_->Touch(
-      active_display_->touchpad_id(),
+  const android::status_t status = dvrVirtualTouchpadTouch(
+      virtual_touchpad_.get(), active_display_->touchpad_id(),
       1.0f - hit_location.y() / size_.y(), hit_location.x() / size_.x(),
       is_touching_ ? 1.0f : 0.0f);
   if (status != OK) {
@@ -453,7 +480,7 @@
     return true;
   }
   touchpad_buttons_ = buttons;
-  if (!virtual_touchpad_.get()) {
+  if (!virtual_touchpad_) {
     ALOGE("missing virtual touchpad");
     return false;
   }
@@ -461,8 +488,9 @@
   if (!active_display_)
     return true;
 
-  const android::status_t status = virtual_touchpad_->ButtonState(
-      active_display_->touchpad_id(), touchpad_buttons_);
+  const android::status_t status = dvrVirtualTouchpadButtonState(
+      virtual_touchpad_.get(), active_display_->touchpad_id(),
+      touchpad_buttons_);
   if (status != OK) {
     ALOGE("touchpad button failed: %d %d", touchpad_buttons_, status);
   }
diff --git a/services/vr/vr_window_manager/shell_view.h b/services/vr/vr_window_manager/shell_view.h
index c10bd27..d265866 100644
--- a/services/vr/vr_window_manager/shell_view.h
+++ b/services/vr/vr_window_manager/shell_view.h
@@ -1,12 +1,13 @@
 #ifndef VR_WINDOW_MANAGER_SHELL_VIEW_H_
 #define VR_WINDOW_MANAGER_SHELL_VIEW_H_
 
+#include <dvr/virtual_touchpad_client.h>
+#include <private/dvr/display_client.h>
 #include <private/dvr/graphics/mesh.h>
 #include <private/dvr/graphics/shader_program.h>
 
 #include <deque>
 
-#include "VirtualTouchpadClient.h"
 #include "application.h"
 #include "display_view.h"
 #include "reticle.h"
@@ -32,6 +33,8 @@
   void EnableDebug(bool debug) override;
   void VrMode(bool mode) override;
   void dumpInternal(String8& result) override;
+  void Set2DMode(bool mode) override;
+
 
  protected:
   void DrawEye(EyeType eye, const mat4& perspective, const mat4& eye_matrix,
@@ -53,7 +56,6 @@
   DisplayView* FindActiveDisplay(const vec3& position, const quat& quaternion,
                                  vec3* hit_location);
 
-
   // HwcCallback::Client:
   base::unique_fd OnFrame(std::unique_ptr<HwcCallback::Frame> frame) override;
   DisplayView* FindOrCreateDisplay(uint32_t id);
@@ -64,7 +66,17 @@
 
   std::unique_ptr<SurfaceFlingerView> surface_flinger_view_;
   std::unique_ptr<Reticle> reticle_;
-  sp<VirtualTouchpad> virtual_touchpad_;
+
+  std::unique_ptr<DisplayClient> display_client_;
+
+  struct DvrVirtualTouchpadDeleter {
+    void operator()(DvrVirtualTouchpad* p) {
+      dvrVirtualTouchpadDetach(p);
+      dvrVirtualTouchpadDestroy(p);
+    }
+  };
+  std::unique_ptr<DvrVirtualTouchpad, DvrVirtualTouchpadDeleter>
+      virtual_touchpad_;
 
   std::unique_ptr<Mesh<vec3, vec3, vec2>> controller_mesh_;
 
diff --git a/services/vr/vr_window_manager/shell_view_binder_interface.h b/services/vr/vr_window_manager/shell_view_binder_interface.h
index b58e4bd..9f77e5a 100644
--- a/services/vr/vr_window_manager/shell_view_binder_interface.h
+++ b/services/vr/vr_window_manager/shell_view_binder_interface.h
@@ -12,6 +12,7 @@
   virtual void EnableDebug(bool debug) = 0;
   virtual void VrMode(bool mode) = 0;
   virtual void dumpInternal(String8& result) = 0;
+  virtual void Set2DMode(bool mode) = 0;
 };
 
 }  // namespace dvr
diff --git a/services/vr/vr_window_manager/surface_flinger_view.cpp b/services/vr/vr_window_manager/surface_flinger_view.cpp
index 8411806..46eb880 100644
--- a/services/vr/vr_window_manager/surface_flinger_view.cpp
+++ b/services/vr/vr_window_manager/surface_flinger_view.cpp
@@ -39,9 +39,29 @@
   vr_composer_view_->Initialize(GetComposerViewFromIComposer(
       vr_hwcomposer_.get()));
 
+  int error = 0;
+  auto display_client = DisplayClient::Create(&error);
+  SystemDisplayMetrics metrics;
+
+  if (error) {
+    ALOGE("Could not connect to display service : %s(%d)", strerror(error), error);
+  } else {
+    error = display_client->GetDisplayMetrics(&metrics);
+
+    if (error) {
+      ALOGE("Could not get display metrics from display service : %s(%d)", strerror(error), error);
+    }
+  }
+
+  if (error) {
+    metrics.display_native_height = 1920;
+    metrics.display_native_width = 1080;
+    ALOGI("Setting display metrics to default : width=%d height=%d", metrics.display_native_height, metrics.display_native_width);
+  }
+
   // TODO(alexst): Refactor ShellView to account for orientation and change this back.
-  width_ = 1920;
-  height_ = 1080;
+  width_ = metrics.display_native_height;
+  height_ = metrics.display_native_width;
   return true;
 }
 
diff --git a/services/vr/vr_window_manager/vr_window_manager_binder.cpp b/services/vr/vr_window_manager/vr_window_manager_binder.cpp
index bd3f3ee..8868588 100644
--- a/services/vr/vr_window_manager/vr_window_manager_binder.cpp
+++ b/services/vr/vr_window_manager/vr_window_manager_binder.cpp
@@ -133,6 +133,11 @@
   return binder::Status::ok();
 }
 
+binder::Status VrWindowManagerBinder::set2DMode(int32_t mode) {
+  app_.Set2DMode(static_cast<bool>(mode));
+  return binder::Status::ok();
+}
+
 status_t VrWindowManagerBinder::dump(
     int fd, const Vector<String16>& args [[gnu::unused]]) {
   String8 result;
diff --git a/services/vr/vr_window_manager/vr_window_manager_binder.h b/services/vr/vr_window_manager/vr_window_manager_binder.h
index 99ca27a..1915ffc 100644
--- a/services/vr/vr_window_manager/vr_window_manager_binder.h
+++ b/services/vr/vr_window_manager/vr_window_manager_binder.h
@@ -59,6 +59,7 @@
   ::android::binder::Status enterVrMode() override;
   ::android::binder::Status exitVrMode() override;
   ::android::binder::Status setDebugMode(int32_t mode) override;
+  ::android::binder::Status set2DMode(int32_t mode) override;
 
   // Implements BBinder::dump().
   status_t dump(int fd, const Vector<String16>& args) override;
diff --git a/services/vr/vr_window_manager/vr_wm.rc b/services/vr/vr_window_manager/vr_wm.rc
index 951515b..e515bb7 100644
--- a/services/vr/vr_window_manager/vr_wm.rc
+++ b/services/vr/vr_window_manager/vr_wm.rc
@@ -2,4 +2,4 @@
   class core
   user system
   group system graphics input
-  cpuset /system
+  writepid /dev/cpuset/system/tasks
diff --git a/services/vr/vr_window_manager/vr_wm_ctl.cpp b/services/vr/vr_window_manager/vr_wm_ctl.cpp
index c67b2eb..2e5c488 100644
--- a/services/vr/vr_window_manager/vr_wm_ctl.cpp
+++ b/services/vr/vr_window_manager/vr_wm_ctl.cpp
@@ -39,6 +39,8 @@
     exit(report(vrwm->exitVrMode()));
   } else if ((argc == 3) && (strcmp(argv[1], "debug") == 0)) {
     exit(report(vrwm->setDebugMode(atoi(argv[2]))));
+  } else if ((argc == 3) && (strcmp(argv[1], "2d") == 0)) {
+    exit(report(vrwm->set2DMode(atoi(argv[2]))));
   } else {
     usage();
     exit(2);
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index f7695ea..5017e14 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -314,7 +314,6 @@
             // supported, at startup time (since it may not be
             // supported):
             &actual_present_time,
-            NULL,  //&display_retire_time,
             NULL,  //&dequeue_ready_time,
             NULL /*&reads_done_time*/);