Merge "libpdx_uds: Add tests for Status<T> message handler return types."
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 1cf00f5..9434d56 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1536,7 +1536,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) {
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 bda3c5c..cbb4491 100644
--- a/include/gui/FrameTimestamps.h
+++ b/include/gui/FrameTimestamps.h
@@ -105,7 +105,7 @@
 struct CompositorTiming {
     nsecs_t deadline{0};
     nsecs_t interval{16666667};
-    nsecs_t presentLatency{0};
+    nsecs_t presentLatency{16666667};
 };
 
 // A short history of frames that are synchronized between the consumer and
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/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index da6f13d..58227e6 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -52,6 +52,8 @@
         mComposerClient = new SurfaceComposerClient;
         ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
 
+        // TODO(brianderson): The following sometimes fails and is a source of
+        //   test flakiness.
         mSurfaceControl = mComposerClient->createSurface(
                 String8("Test Surface"), 32, 32, PIXEL_FORMAT_RGBA_8888, 0);
 
@@ -526,7 +528,7 @@
 };
 
 
-class GetFrameTimestampsTest : public SurfaceTest {
+class GetFrameTimestampsTest : public ::testing::Test {
 protected:
     struct FenceAndFenceTime {
         explicit FenceAndFenceTime(FenceToFenceTimeMap& fenceMap)
@@ -616,11 +618,9 @@
         RefreshEvents mRefreshes[3];
     };
 
-    GetFrameTimestampsTest() : SurfaceTest() {}
+    GetFrameTimestampsTest() {}
 
     virtual void SetUp() {
-        SurfaceTest::SetUp();
-
         BufferQueue::createBufferQueue(&mProducer, &mConsumer);
         mFakeConsumer = new FakeConsumer;
         mCfeh = &mFakeConsumer->mFrameEventHistory;
diff --git a/libs/hwc2on1adapter/HWC2On1Adapter.cpp b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
index 5ad05c7..03297ca 100644
--- a/libs/hwc2on1adapter/HWC2On1Adapter.cpp
+++ b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
@@ -245,6 +245,11 @@
             return asFP<HWC2_PFN_VALIDATE_DISPLAY>(
                     displayHook<decltype(&Display::validate),
                     &Display::validate, uint32_t*, uint32_t*>);
+        case FunctionDescriptor::GetClientTargetSupport:
+            return asFP<HWC2_PFN_GET_CLIENT_TARGET_SUPPORT>(
+                    displayHook<decltype(&Display::getClientTargetSupport),
+                    &Display::getClientTargetSupport, uint32_t, uint32_t,
+                                                      int32_t, int32_t>);
 
         // Layer functions
         case FunctionDescriptor::SetCursorPosition:
@@ -1009,6 +1014,22 @@
     return Error::None;
 }
 
+Error HWC2On1Adapter::Display::getClientTargetSupport(uint32_t width, uint32_t height,
+                                      int32_t format, int32_t dataspace){
+    if (mActiveConfig == nullptr) {
+        return Error::Unsupported;
+    }
+
+    if (width == mActiveConfig->getAttribute(Attribute::Width) &&
+            height == mActiveConfig->getAttribute(Attribute::Height) &&
+            format == HAL_PIXEL_FORMAT_RGBA_8888 &&
+            dataspace == HAL_DATASPACE_UNKNOWN) {
+        return Error::None;
+    }
+
+    return Error::Unsupported;
+}
+
 static constexpr uint32_t ATTRIBUTES_WITH_COLOR[] = {
     HWC_DISPLAY_VSYNC_PERIOD,
     HWC_DISPLAY_WIDTH,
diff --git a/libs/hwc2on1adapter/include/hwc2on1adapter/HWC2On1Adapter.h b/libs/hwc2on1adapter/include/hwc2on1adapter/HWC2On1Adapter.h
index a1d2c88..3badfce 100644
--- a/libs/hwc2on1adapter/include/hwc2on1adapter/HWC2On1Adapter.h
+++ b/libs/hwc2on1adapter/include/hwc2on1adapter/HWC2On1Adapter.h
@@ -248,6 +248,9 @@
 
             HWC2::Error updateLayerZ(hwc2_layer_t layerId, uint32_t z);
 
+            HWC2::Error getClientTargetSupport(uint32_t width, uint32_t height,
+                     int32_t format, int32_t dataspace);
+
             // Read configs from HWC1 device
             void populateConfigs();
 
diff --git a/libs/vr/libbufferhub/buffer_hub_client.cpp b/libs/vr/libbufferhub/buffer_hub_client.cpp
index e2413bd..7268b76 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>();
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..b976097 100644
--- a/libs/vr/libbufferhubqueue/Android.bp
+++ b/libs/vr/libbufferhubqueue/Android.bp
@@ -45,6 +45,7 @@
     cflags = [ "-DLOGTAG=\"libbufferhubqueue\"" ],
     srcs: sourceFiles,
     export_include_dirs: includeFiles,
+    export_static_lib_headers: staticLibraries,
     static_libs: staticLibraries,
     shared_libs: sharedLibraries,
 }
diff --git a/libs/vr/libdisplay/display_client.cpp b/libs/vr/libdisplay/display_client.cpp
index 54098e8..dcdd994 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() {
diff --git a/libs/vr/libdisplay/include/private/dvr/display_client.h b/libs/vr/libdisplay/include/private/dvr/display_client.h
index 034b7b4..e1471c3 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;
 };
diff --git a/libs/vr/libdisplay/include/private/dvr/display_rpc.h b/libs/vr/libdisplay/include/private/dvr/display_rpc.h
index d37aed7..465fbae 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_rpc.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_rpc.h
@@ -212,7 +212,7 @@
     kOpGetMetrics = 0,
     kOpGetEdsCapture,
     kOpCreateSurface,
-    kOpAllocateBuffer,
+    kOpCreateBufferQueue,
     kOpSetAttributes,
     kOpGetMetadataBuffer,
     kOpCreateVideoMeshSurface,
@@ -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,
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/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/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_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index bb70c5c..fdb84c5 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -90,7 +90,7 @@
       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:
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
index b207e4d..9d116c1 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 {
@@ -99,7 +98,6 @@
   DisplayService(const DisplayService&) = delete;
   void operator=(const DisplayService&) = delete;
 
-  EpollEventDispatcher dispatcher_;
   HardwareComposer hardware_composer_;
   DisplayConfigurationUpdateNotifier update_notifier_;
 };
diff --git a/libs/vr/libvrflinger/display_surface.cpp b/libs/vr/libvrflinger/display_surface.cpp
index d427ea6..66808ca 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,7 +40,6 @@
       manager_visible_(false),
       manager_z_order_(0),
       manager_blur_(0.0f),
-      allocated_buffer_index_(0),
       layer_order_(0) {}
 
 DisplaySurface::~DisplaySurface() {
@@ -84,71 +83,107 @@
   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;
+    }
+
+    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 {
+bool DisplaySurface::IsBufferAvailable() {
   std::lock_guard<std::mutex> autolock(lock_);
-  return !posted_buffers_.IsEmpty() && posted_buffers_.Front().IsAvailable();
+  DequeueBuffersLocked();
+
+  return !acquired_buffers_.IsEmpty() &&
+         acquired_buffers_.Front().IsAvailable();
 }
 
-bool DisplaySurface::IsBufferPosted() const {
+bool DisplaySurface::IsBufferPosted() {
   std::lock_guard<std::mutex> autolock(lock_);
-  return !posted_buffers_.IsEmpty();
-}
+  DequeueBuffersLocked();
 
-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();
-  }
-  AcquiredBuffer buffer = std::move(posted_buffers_.Front());
-  posted_buffers_.PopFront();
-  return buffer;
-}
-
-int DisplaySurface::GetConsumers(std::vector<LocalChannelHandle>* consumers) {
-  std::lock_guard<std::mutex> autolock(lock_);
-  std::vector<LocalChannelHandle> items;
-
-  for (auto pair : buffers_) {
-    const auto& buffer = pair.second;
-
-    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();
-    }
-
-    items.push_back(consumer_channel.take());
-  }
-
-  *consumers = std::move(items);
-  return 0;
+  return !acquired_buffers_.IsEmpty();
 }
 
 int DisplaySurface::HandleMessage(pdx::Message& message) {
@@ -158,9 +193,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 +261,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 +316,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..feb173e 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"
 
@@ -65,19 +64,8 @@
     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;
+  bool IsBufferAvailable();
+  bool IsBufferPosted();
   AcquiredBuffer AcquireCurrentBuffer();
 
   // Get the newest buffer. Up to one buffer will be skipped. If a buffer is
@@ -119,12 +107,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 +115,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 +140,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,8 +170,6 @@
   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_;
 
   // Maps from the buffer id to the corresponding allocated buffer 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..53c2ac2 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -1485,6 +1485,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/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/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 1b13ea9..a6ea750 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -69,10 +69,6 @@
     LOCAL_CFLAGS += -DNUM_FRAMEBUFFER_SURFACE_BUFFERS=$(NUM_FRAMEBUFFER_SURFACE_BUFFERS)
 endif
 
-ifeq ($(TARGET_RUNNING_WITHOUT_SYNC_FRAMEWORK),true)
-    LOCAL_CFLAGS += -DRUNNING_WITHOUT_SYNC_FRAMEWORK
-endif
-
 LOCAL_CFLAGS += -fvisibility=hidden -Werror=format
 
 LOCAL_HEADER_LIBRARIES := \
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index d7654f1..bd9b8aa 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -216,7 +216,8 @@
         return BAD_VALUE;
     }
 
-    // This method is only here to handle the kIgnorePresentFences case.
+    // This method is only here to handle the !SurfaceFlinger::hasSyncFramework
+    // case.
     bool hasAnyEventListeners() {
         if (kTraceDetailedInfo) ATRACE_CALL();
         Mutex::Autolock lock(mMutex);
@@ -376,7 +377,8 @@
 DispSync::DispSync(const char* name) :
         mName(name),
         mRefreshSkipCount(0),
-        mThread(new DispSyncThread(name)) {
+        mThread(new DispSyncThread(name)),
+        mIgnorePresentFences(!SurfaceFlinger::hasSyncFramework){
 
     mPresentTimeOffset = SurfaceFlinger::dispSyncPresentTimeOffset;
     mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
@@ -397,7 +399,7 @@
         // Even if we're just ignoring the fences, the zero-phase tracing is
         // not needed because any time there is an event registered we will
         // turn on the HW vsync events.
-        if (!kIgnorePresentFences && kEnableZeroPhaseTracer) {
+        if (!mIgnorePresentFences && kEnableZeroPhaseTracer) {
             addEventListener("ZeroPhaseTracer", 0, new ZeroPhaseTracer());
         }
     }
@@ -476,7 +478,7 @@
         resetErrorLocked();
     }
 
-    if (kIgnorePresentFences) {
+    if (mIgnorePresentFences) {
         // If we don't have the sync framework we will never have
         // addPresentFence called.  This means we have no way to know whether
         // or not we're synchronized with the HW vsyncs, so we just request
@@ -641,7 +643,7 @@
 void DispSync::dump(String8& result) const {
     Mutex::Autolock lock(mMutex);
     result.appendFormat("present fences are %s\n",
-            kIgnorePresentFences ? "ignored" : "used");
+            mIgnorePresentFences ? "ignored" : "used");
     result.appendFormat("mPeriod: %" PRId64 " ns (%.3f fps; skipCount=%d)\n",
             mPeriod, 1000000000.0 / mPeriod, mRefreshSkipCount);
     result.appendFormat("mPhase: %" PRId64 " ns\n", mPhase);
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index 5b7083d..82ae795 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -25,15 +25,6 @@
 
 namespace android {
 
-// Ignore present (retire) fences if the device doesn't have support for the
-// sync framework
-#if defined(RUNNING_WITHOUT_SYNC_FRAMEWORK)
-static const bool kIgnorePresentFences = true;
-#else
-static const bool kIgnorePresentFences = false;
-#endif
-
-
 class String8;
 class Fence;
 class DispSyncThread;
@@ -186,6 +177,10 @@
     // This is the offset from the present fence timestamps to the corresponding
     // vsync event.
     int64_t mPresentTimeOffset;
+
+    // Ignore present (retire) fences if the device doesn't have support for the
+    // sync framework
+    bool mIgnorePresentFences;
 };
 
 }
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 295b229..861a7d9 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -760,9 +760,7 @@
 
     mHwcLayers[hwcId].forceClientComposition = true;
 }
-#endif
 
-#ifdef USE_HWC2
 void Layer::setPerFrameData(const sp<const DisplayDevice>& displayDevice) {
     // Apply this display's projection's viewport to the visible region
     // before giving it to the HWC HAL.
@@ -865,6 +863,10 @@
                 static_cast<int32_t>(error));
     }
 }
+
+android_dataspace Layer::getDataSpace() const {
+    return mCurrentState.dataSpace;
+}
 #else
 void Layer::setPerFrameData(const sp<const DisplayDevice>& hw,
         HWComposer::HWCLayerInterface& layer) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 6b228b0..afe6074 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -261,6 +261,8 @@
     void forceClientComposition(int32_t hwcId);
     void setPerFrameData(const sp<const DisplayDevice>& displayDevice);
 
+    android_dataspace getDataSpace() const;
+
     // callIntoHwc exists so we can update our local state and call
     // acceptDisplayChanges without unnecessarily updating the device's state
     void setCompositionType(int32_t hwcId, HWC2::Composition type,
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index cfde375..06dd903 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -117,6 +117,7 @@
 int64_t SurfaceFlinger::dispSyncPresentTimeOffset;
 bool SurfaceFlinger::useHwcForRgbToYuv;
 uint64_t SurfaceFlinger::maxVirtualDisplaySize;
+bool SurfaceFlinger::hasSyncFramework;
 
 SurfaceFlinger::SurfaceFlinger()
     :   BnSurfaceComposer(),
@@ -160,6 +161,7 @@
         ,mEnterVrMode(false)
 #endif
 {
+    ALOGI("SurfaceFlinger is starting");
 
     vsyncPhaseOffsetNs = getInt64< ISurfaceFlingerConfigs,
             &ISurfaceFlingerConfigs::vsyncEventPhaseOffsetNs>(1000000);
@@ -167,7 +169,8 @@
     sfVsyncPhaseOffsetNs = getInt64< ISurfaceFlingerConfigs,
             &ISurfaceFlingerConfigs::vsyncSfEventPhaseOffsetNs>(1000000);
 
-    ALOGI("SurfaceFlinger is starting");
+    hasSyncFramework = getBool< ISurfaceFlingerConfigs,
+            &ISurfaceFlingerConfigs::hasSyncFramework>(true);
 
     useContextPriority = getBool< ISurfaceFlingerConfigs,
             &ISurfaceFlingerConfigs::useContextPriority>(false);
@@ -1126,7 +1129,7 @@
 }
 
 void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) {
-    std::lock_guard<std::mutex> lock(mCompositeTimingLock);
+    std::lock_guard<std::mutex> lock(mCompositorTimingLock);
     *compositorTiming = mCompositorTiming;
 }
 
@@ -1423,34 +1426,39 @@
         mCompositePresentTimes.pop();
     }
 
+    setCompositorTimingSnapped(
+            vsyncPhase, vsyncInterval, compositeToPresentLatency);
+}
+
+void SurfaceFlinger::setCompositorTimingSnapped(nsecs_t vsyncPhase,
+        nsecs_t vsyncInterval, nsecs_t compositeToPresentLatency) {
     // Integer division and modulo round toward 0 not -inf, so we need to
     // treat negative and positive offsets differently.
-    nsecs_t idealLatency = (sfVsyncPhaseOffsetNs >= 0) ?
+    nsecs_t idealLatency = (sfVsyncPhaseOffsetNs > 0) ?
             (vsyncInterval - (sfVsyncPhaseOffsetNs % vsyncInterval)) :
             ((-sfVsyncPhaseOffsetNs) % vsyncInterval);
 
+    // Just in case sfVsyncPhaseOffsetNs == -vsyncInterval.
+    if (idealLatency <= 0) {
+        idealLatency = vsyncInterval;
+    }
+
     // Snap the latency to a value that removes scheduling jitter from the
     // composition and present times, which often have >1ms of jitter.
     // Reducing jitter is important if an app attempts to extrapolate
     // something (such as user input) to an accurate diasplay time.
     // Snapping also allows an app to precisely calculate sfVsyncPhaseOffsetNs
     // with (presentLatency % interval).
-    nsecs_t snappedCompositeToPresentLatency = -1;
-    if (compositeToPresentLatency >= 0) {
-        nsecs_t bias = vsyncInterval / 2;
-        int64_t extraVsyncs =
-                (compositeToPresentLatency - idealLatency + bias) /
-                vsyncInterval;
-        nsecs_t extraLatency = extraVsyncs * vsyncInterval;
-        snappedCompositeToPresentLatency = idealLatency + extraLatency;
-    }
+    nsecs_t bias = vsyncInterval / 2;
+    int64_t extraVsyncs =
+            (compositeToPresentLatency - idealLatency + bias) / vsyncInterval;
+    nsecs_t snappedCompositeToPresentLatency = (extraVsyncs > 0) ?
+            idealLatency + (extraVsyncs * vsyncInterval) : idealLatency;
 
-    std::lock_guard<std::mutex> lock(mCompositeTimingLock);
+    std::lock_guard<std::mutex> lock(mCompositorTimingLock);
     mCompositorTiming.deadline = vsyncPhase - idealLatency;
     mCompositorTiming.interval = vsyncInterval;
-    if (snappedCompositeToPresentLatency >= 0) {
-        mCompositorTiming.presentLatency = snappedCompositeToPresentLatency;
-    }
+    mCompositorTiming.presentLatency = snappedCompositeToPresentLatency;
 }
 
 void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
@@ -1497,10 +1505,15 @@
     // since updateCompositorTiming has snapping logic.
     updateCompositorTiming(
         vsyncPhase, vsyncInterval, refreshStartTime, displayFenceTime);
+    CompositorTiming compositorTiming;
+    {
+        std::lock_guard<std::mutex> lock(mCompositorTimingLock);
+        compositorTiming = mCompositorTiming;
+    }
 
     mDrawingState.traverseInZOrder([&](Layer* layer) {
         bool frameLatched = layer->onPostComposition(glCompositionDoneFenceTime,
-                *presentFenceTime, *retireFenceTime, mCompositorTiming);
+                *presentFenceTime, *retireFenceTime, compositorTiming);
         if (frameLatched) {
             recordBufferingStats(layer->getName().string(),
                     layer->getOccupancyHistory(false));
@@ -1515,7 +1528,7 @@
         }
     }
 
-    if (kIgnorePresentFences) {
+    if (!hasSyncFramework) {
         if (hw->isDisplayOn()) {
             enableHardwareVsync();
         }
@@ -2979,10 +2992,9 @@
     const nsecs_t period = activeConfig->getVsyncPeriod();
     mAnimFrameTracker.setDisplayRefreshPeriod(period);
 
-    {
-        std::lock_guard<std::mutex> lock(mCompositeTimingLock);
-        mCompositorTiming.interval = period;
-    }
+    // Use phase of 0 since phase is not known.
+    // Use latency of 0, which will snap to the ideal latency.
+    setCompositorTimingSnapped(0, period, 0);
 }
 
 void SurfaceFlinger::initializeDisplays() {
@@ -3249,6 +3261,7 @@
     result.appendFormat(" PRESENT_TIME_OFFSET=%" PRId64 , dispSyncPresentTimeOffset);
     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.append("]");
 }
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 85b6f2a..921ecf6 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -128,6 +128,9 @@
     static int64_t vsyncPhaseOffsetNs;
     static int64_t sfVsyncPhaseOffsetNs;
 
+    // If fences from sync Framework are supported.
+    static bool hasSyncFramework;
+
     // Instruct the Render Engine to use EGL_IMG_context_priority is available.
     static bool useContextPriority;
 
@@ -463,6 +466,9 @@
     void updateCompositorTiming(
             nsecs_t vsyncPhase, nsecs_t vsyncInterval, nsecs_t compositeTime,
             std::shared_ptr<FenceTime>& presentFenceTime);
+    void setCompositorTimingSnapped(
+            nsecs_t vsyncPhase, nsecs_t vsyncInterval,
+            nsecs_t compositeToPresentLatency);
     void rebuildLayerStacks();
     void setUpHWComposer();
     void doComposition();
@@ -633,7 +639,7 @@
     bool mHWVsyncAvailable;
 
     // protected by mCompositorTimingLock;
-    mutable std::mutex mCompositeTimingLock;
+    mutable std::mutex mCompositorTimingLock;
     CompositorTiming mCompositorTiming;
 
     // Only accessed from the main thread.
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index c184cd2..e8147cf 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -115,6 +115,7 @@
 int64_t SurfaceFlinger::dispSyncPresentTimeOffset;
 bool SurfaceFlinger::useHwcForRgbToYuv;
 uint64_t SurfaceFlinger::maxVirtualDisplaySize;
+bool SurfaceFlinger::hasSyncFramework;
 
 SurfaceFlinger::SurfaceFlinger()
     :   BnSurfaceComposer(),
@@ -151,7 +152,6 @@
         mLastSwapTime(0),
         mNumLayers(0)
 {
-
     ALOGI("SurfaceFlinger is starting");
 
     vsyncPhaseOffsetNs = getInt64< ISurfaceFlingerConfigs,
@@ -163,6 +163,9 @@
     maxVirtualDisplaySize = getUInt64<ISurfaceFlingerConfigs,
             &ISurfaceFlingerConfigs::maxVirtualDisplaySize>(0);
 
+    hasSyncFramework = getBool< ISurfaceFlingerConfigs,
+            &ISurfaceFlingerConfigs::hasSyncFramework>(true);
+
     useContextPriority = getBool< ISurfaceFlingerConfigs,
             &ISurfaceFlingerConfigs::useContextPriority>(false);
 
@@ -1045,7 +1048,7 @@
 }
 
 void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) {
-    std::lock_guard<std::mutex> lock(mCompositeTimingLock);
+    std::lock_guard<std::mutex> lock(mCompositorTimingLock);
     *compositorTiming = mCompositorTiming;
 }
 
@@ -1208,34 +1211,39 @@
         mCompositePresentTimes.pop();
     }
 
+    setCompositorTimingSnapped(
+            vsyncPhase, vsyncInterval, compositeToPresentLatency);
+}
+
+void SurfaceFlinger::setCompositorTimingSnapped(nsecs_t vsyncPhase,
+        nsecs_t vsyncInterval, nsecs_t compositeToPresentLatency) {
     // Integer division and modulo round toward 0 not -inf, so we need to
     // treat negative and positive offsets differently.
-    nsecs_t idealLatency = (sfVsyncPhaseOffsetNs >= 0) ?
+    nsecs_t idealLatency = (sfVsyncPhaseOffsetNs > 0) ?
             (vsyncInterval - (sfVsyncPhaseOffsetNs % vsyncInterval)) :
             ((-sfVsyncPhaseOffsetNs) % vsyncInterval);
 
+    // Just in case sfVsyncPhaseOffsetNs == -vsyncInterval.
+    if (idealLatency <= 0) {
+        idealLatency = vsyncInterval;
+    }
+
     // Snap the latency to a value that removes scheduling jitter from the
     // composition and present times, which often have >1ms of jitter.
     // Reducing jitter is important if an app attempts to extrapolate
     // something (such as user input) to an accurate diasplay time.
     // Snapping also allows an app to precisely calculate sfVsyncPhaseOffsetNs
     // with (presentLatency % interval).
-    nsecs_t snappedCompositeToPresentLatency = -1;
-    if (compositeToPresentLatency >= 0) {
-        nsecs_t bias = vsyncInterval / 2;
-        int64_t extraVsyncs =
-                (compositeToPresentLatency - idealLatency + bias) /
-                vsyncInterval;
-        nsecs_t extraLatency = extraVsyncs * vsyncInterval;
-        snappedCompositeToPresentLatency = idealLatency + extraLatency;
-    }
+    nsecs_t bias = vsyncInterval / 2;
+    int64_t extraVsyncs =
+            (compositeToPresentLatency - idealLatency + bias) / vsyncInterval;
+    nsecs_t snappedCompositeToPresentLatency = (extraVsyncs > 0) ?
+            idealLatency + (extraVsyncs * vsyncInterval) : idealLatency;
 
-    std::lock_guard<std::mutex> lock(mCompositeTimingLock);
+    std::lock_guard<std::mutex> lock(mCompositorTimingLock);
     mCompositorTiming.deadline = vsyncPhase - idealLatency;
     mCompositorTiming.interval = vsyncInterval;
-    if (snappedCompositeToPresentLatency >= 0) {
-        mCompositorTiming.presentLatency = snappedCompositeToPresentLatency;
-    }
+    mCompositorTiming.presentLatency = snappedCompositeToPresentLatency;
 }
 
 void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
@@ -1267,10 +1275,15 @@
     // since updateCompositorTiming has snapping logic.
     updateCompositorTiming(
         vsyncPhase, vsyncInterval, refreshStartTime, retireFenceTime);
+    CompositorTiming compositorTiming;
+    {
+        std::lock_guard<std::mutex> lock(mCompositorTimingLock);
+        compositorTiming = mCompositorTiming;
+    }
 
     mDrawingState.traverseInZOrder([&](Layer* layer) {
         bool frameLatched = layer->onPostComposition(glCompositionDoneFenceTime,
-                presentFenceTime, retireFenceTime, mCompositorTiming);
+                presentFenceTime, retireFenceTime, compositorTiming);
         if (frameLatched) {
             recordBufferingStats(layer->getName().string(),
                     layer->getOccupancyHistory(false));
@@ -1285,7 +1298,7 @@
         }
     }
 
-    if (kIgnorePresentFences) {
+    if (!hasSyncFramework) {
         if (hw->isDisplayOn()) {
             enableHardwareVsync();
         }
@@ -2755,6 +2768,10 @@
     const nsecs_t period =
             getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
     mAnimFrameTracker.setDisplayRefreshPeriod(period);
+
+    // Use phase of 0 since phase is not known.
+    // Use latency of 0, which will snap to the ideal latency.
+    setCompositorTimingSnapped(0, period, 0);
 }
 
 void SurfaceFlinger::initializeDisplays() {
@@ -3021,6 +3038,7 @@
     result.appendFormat(" PRESENT_TIME_OFFSET=%" PRId64, dispSyncPresentTimeOffset);
     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.append("]");
 }
 
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/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\" \