Merge "Add comment regarding keeping TRACE_DUMP_TIMEOUT_MS in sync"
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/cmds/installd/Android.mk b/cmds/installd/Android.mk
index f567a10..be1a434 100644
--- a/cmds/installd/Android.mk
+++ b/cmds/installd/Android.mk
@@ -23,10 +23,9 @@
 LOCAL_CFLAGS += -DART_BASE_ADDRESS_MIN_DELTA=$(LOCAL_LIBART_IMG_HOST_MIN_BASE_ADDRESS_DELTA)
 LOCAL_CFLAGS += -DART_BASE_ADDRESS_MAX_DELTA=$(LOCAL_LIBART_IMG_HOST_MAX_BASE_ADDRESS_DELTA)
 
-LOCAL_SRC_FILES := otapreopt.cpp InstalldNativeService.cpp globals.cpp utils.cpp dexopt.cpp binder/android/os/IInstalld.aidl
+LOCAL_SRC_FILES := otapreopt.cpp globals.cpp utils.cpp dexopt.cpp
 LOCAL_SHARED_LIBRARIES := \
     libbase \
-    libbinder \
     libcutils \
     liblog \
     liblogwrap \
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 5bb2ce7..f7e8d13 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -1564,7 +1564,7 @@
             ALOGV("DexInv: --- END '%s' (success) ---\n", dex_path);
         } else {
             ALOGE("DexInv: --- END '%s' --- status=0x%04x, process failed\n", dex_path, res);
-            return -1;
+            return res;
         }
     }
 
diff --git a/cmds/installd/globals.h b/cmds/installd/globals.h
index 8242eec..c90beec 100644
--- a/cmds/installd/globals.h
+++ b/cmds/installd/globals.h
@@ -20,8 +20,6 @@
 
 #include <inttypes.h>
 
-#include "InstalldNativeService.h"
-
 namespace android {
 namespace installd {
 
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index c74c65b..82b8cc2 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -36,7 +36,6 @@
 #include <log/log.h>
 #include <private/android_filesystem_config.h>
 
-#include "InstalldNativeService.h"
 #include "dexopt.h"
 #include "file_parsing.h"
 #include "globals.h"
diff --git a/data/etc/car_core_hardware.xml b/data/etc/car_core_hardware.xml
index ab89ef5..835504f 100644
--- a/data/etc/car_core_hardware.xml
+++ b/data/etc/car_core_hardware.xml
@@ -23,6 +23,9 @@
      devices.
 -->
 <permissions>
+    <!-- This is Android and fully CTS compatible.  Basically this is for CTS tests to use. -->
+    <feature name="android.software.cts" />
+
     <feature name="android.hardware.audio.output" />
     <feature name="android.hardware.location" />
     <feature name="android.hardware.location.network" />
diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
index ed3db5c..2607d58 100644
--- a/data/etc/handheld_core_hardware.xml
+++ b/data/etc/handheld_core_hardware.xml
@@ -23,6 +23,9 @@
      devices.
 -->
 <permissions>
+    <!-- This is Android and fully CTS compatible.  Basically this is for CTS tests to use. -->
+    <feature name="android.software.cts" />
+
     <feature name="android.hardware.audio.output" />
     <feature name="android.hardware.camera" />
     <feature name="android.hardware.location" />
diff --git a/data/etc/tablet_core_hardware.xml b/data/etc/tablet_core_hardware.xml
index 7f545e6..f0ca067 100644
--- a/data/etc/tablet_core_hardware.xml
+++ b/data/etc/tablet_core_hardware.xml
@@ -23,6 +23,9 @@
      devices.
 -->
 <permissions>
+    <!-- This is Android and fully CTS compatible.  Basically this is for CTS tests to use. -->
+    <feature name="android.software.cts" />
+
     <feature name="android.hardware.audio.output" />
     <feature name="android.hardware.location" />
     <feature name="android.hardware.location.network" />
diff --git a/data/etc/wearable_core_hardware.xml b/data/etc/wearable_core_hardware.xml
index 84230da..a7955e9 100644
--- a/data/etc/wearable_core_hardware.xml
+++ b/data/etc/wearable_core_hardware.xml
@@ -21,6 +21,9 @@
      Wearable devices include watches, glasses, backpacks, and sweaters.
 -->
 <permissions>
+    <!-- This is Android and fully CTS compatible.  Basically this is for CTS tests to use. -->
+    <feature name="android.software.cts" />
+
     <feature name="android.hardware.location" />
     <!-- devices supporting compass/magnitometer sensor must include
 	 android.hardware.sensor.compass.xml -->
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 4492a08..3a99147 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -8,6 +8,7 @@
     clang: true,
 
     srcs: [
+        "BufferItemConsumer_test.cpp",
         "BufferQueue_test.cpp",
         "CpuConsumer_test.cpp",
         "FillBuffer.cpp",
diff --git a/libs/gui/tests/BufferItemConsumer_test.cpp b/libs/gui/tests/BufferItemConsumer_test.cpp
new file mode 100644
index 0000000..d64e530
--- /dev/null
+++ b/libs/gui/tests/BufferItemConsumer_test.cpp
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BufferItemConsumer_test"
+//#define LOG_NDEBUG 0
+
+#include <gtest/gtest.h>
+#include <gui/BufferItemConsumer.h>
+#include <gui/IProducerListener.h>
+#include <gui/Surface.h>
+
+namespace android {
+
+static constexpr int kWidth = 100;
+static constexpr int kHeight = 100;
+static constexpr int kMaxLockedBuffers = 3;
+static constexpr int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+static constexpr int kFrameSleepUs = 30 * 1000;
+
+class BufferItemConsumerTest : public ::testing::Test {
+   protected:
+    struct BufferFreedListener
+        : public BufferItemConsumer::BufferFreedListener {
+        explicit BufferFreedListener(BufferItemConsumerTest* test)
+            : mTest(test) {}
+        void onBufferFreed(const wp<GraphicBuffer>& /* gBuffer */) override {
+            mTest->HandleBufferFreed();
+        }
+        BufferItemConsumerTest* mTest;
+    };
+
+    void SetUp() override {
+        BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+        mBIC =
+            new BufferItemConsumer(mConsumer, kFormat, kMaxLockedBuffers, true);
+        String8 name("BufferItemConsumer_Under_Test");
+        mBIC->setName(name);
+        mBFL = new BufferFreedListener(this);
+        mBIC->setBufferFreedListener(mBFL);
+
+        sp<IProducerListener> producerListener = new DummyProducerListener();
+        IGraphicBufferProducer::QueueBufferOutput bufferOutput;
+        ASSERT_EQ(NO_ERROR,
+                  mProducer->connect(producerListener, NATIVE_WINDOW_API_CPU,
+                                     true, &bufferOutput));
+        ASSERT_EQ(NO_ERROR,
+                  mProducer->setMaxDequeuedBufferCount(kMaxLockedBuffers));
+    }
+
+    int GetFreedBufferCount() {
+        std::lock_guard<std::mutex> lock(mMutex);
+        return mFreedBufferCount;
+    }
+
+    void HandleBufferFreed() {
+        std::lock_guard<std::mutex> lock(mMutex);
+        mFreedBufferCount++;
+        ALOGV("HandleBufferFreed, mFreedBufferCount=%d", mFreedBufferCount);
+    }
+
+    void DequeueBuffer(int* outSlot) {
+        ASSERT_NE(outSlot, nullptr);
+
+        int slot;
+        sp<Fence> outFence;
+        status_t ret = mProducer->dequeueBuffer(&slot, &outFence, kWidth,
+                                                kHeight, 0, 0, nullptr);
+        ASSERT_GE(ret, 0);
+
+        ALOGV("dequeueBuffer: slot=%d", slot);
+        if (ret & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
+            ret = mProducer->requestBuffer(slot, &mBuffers[slot]);
+            ASSERT_EQ(NO_ERROR, ret);
+        }
+        *outSlot = slot;
+    }
+
+    void QueueBuffer(int slot) {
+        ALOGV("enqueueBuffer: slot=%d", slot);
+        IGraphicBufferProducer::QueueBufferInput bufferInput(
+            0ULL, true, HAL_DATASPACE_UNKNOWN, Rect::INVALID_RECT,
+            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
+        IGraphicBufferProducer::QueueBufferOutput bufferOutput;
+        status_t ret = mProducer->queueBuffer(slot, bufferInput, &bufferOutput);
+        ASSERT_EQ(NO_ERROR, ret);
+    }
+
+    void AcquireBuffer(int* outSlot) {
+        ASSERT_NE(outSlot, nullptr);
+        BufferItem buffer;
+        status_t ret = mBIC->acquireBuffer(&buffer, 0, false);
+        ASSERT_EQ(NO_ERROR, ret);
+
+        ALOGV("acquireBuffer: slot=%d", buffer.mSlot);
+        *outSlot = buffer.mSlot;
+    }
+
+    void ReleaseBuffer(int slot) {
+        ALOGV("releaseBuffer: slot=%d", slot);
+        BufferItem buffer;
+        buffer.mSlot = slot;
+        buffer.mGraphicBuffer = mBuffers[slot];
+        status_t ret = mBIC->releaseBuffer(buffer, Fence::NO_FENCE);
+        ASSERT_EQ(NO_ERROR, ret);
+    }
+
+
+    std::mutex mMutex;
+    int mFreedBufferCount{0};
+
+    sp<BufferItemConsumer> mBIC;
+    sp<BufferFreedListener> mBFL;
+    sp<IGraphicBufferProducer> mProducer;
+    sp<IGraphicBufferConsumer> mConsumer;
+    sp<GraphicBuffer> mBuffers[BufferQueueDefs::NUM_BUFFER_SLOTS];
+};
+
+// Test that detaching buffer from consumer side triggers onBufferFreed.
+TEST_F(BufferItemConsumerTest, TriggerBufferFreed_DetachBufferFromConsumer) {
+    int slot;
+    // Producer: generate a dummy buffer.
+    DequeueBuffer(&slot);
+    QueueBuffer(slot);
+
+    ASSERT_EQ(0, GetFreedBufferCount());
+    // Consumer: acquire the buffer and then detach it.
+    AcquireBuffer(&slot);
+    status_t ret = mBIC->detachBuffer(slot);
+    ASSERT_EQ(NO_ERROR, ret);
+
+    // Sleep to give some time for callbacks to happen.
+    usleep(kFrameSleepUs);
+    ASSERT_EQ(1, GetFreedBufferCount());
+}
+
+// Test that detaching buffer from producer side triggers onBufferFreed.
+TEST_F(BufferItemConsumerTest, TriggerBufferFreed_DetachBufferFromProducer) {
+    int slot;
+    // Let buffer go through the cycle at least once.
+    DequeueBuffer(&slot);
+    QueueBuffer(slot);
+    AcquireBuffer(&slot);
+    ReleaseBuffer(slot);
+
+    ASSERT_EQ(0, GetFreedBufferCount());
+
+    // Producer: generate the buffer again.
+    DequeueBuffer(&slot);
+
+    // Producer: detach the buffer.
+    status_t ret = mProducer->detachBuffer(slot);
+    ASSERT_EQ(NO_ERROR, ret);
+
+    // Sleep to give some time for callbacks to happen.
+    usleep(kFrameSleepUs);
+    ASSERT_EQ(1, GetFreedBufferCount());
+}
+
+// Test that abandoning BufferItemConsumer triggers onBufferFreed.
+TEST_F(BufferItemConsumerTest, TriggerBufferFreed_AbandonBufferItemConsumer) {
+    int slot;
+    // Let buffer go through the cycle at least once.
+    DequeueBuffer(&slot);
+    QueueBuffer(slot);
+    AcquireBuffer(&slot);
+    ReleaseBuffer(slot);
+
+    // Abandon the BufferItemConsumer.
+    mBIC->abandon();
+
+    // Sleep to give some time for callbacks to happen.
+    usleep(kFrameSleepUs);
+    ASSERT_EQ(1, GetFreedBufferCount());
+}
+
+// Test that delete BufferItemConsumer triggers onBufferFreed.
+TEST_F(BufferItemConsumerTest, TriggerBufferFreed_DeleteBufferItemConsumer) {
+    int slot;
+    // Let buffer go through the cycle at least once.
+    DequeueBuffer(&slot);
+    QueueBuffer(slot);
+    AcquireBuffer(&slot);
+    ReleaseBuffer(slot);
+
+    // Delete the BufferItemConsumer.
+    mBIC.clear();
+
+    // Sleep to give some time for callbacks to happen.
+    usleep(kFrameSleepUs);
+    ASSERT_EQ(1, GetFreedBufferCount());
+}
+
+}  // namespace android
diff --git a/libs/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 b976097..1c8f2c0 100644
--- a/libs/vr/libbufferhubqueue/Android.bp
+++ b/libs/vr/libbufferhubqueue/Android.bp
@@ -42,7 +42,10 @@
 
 cc_library {
     name: "libbufferhubqueue",
-    cflags = [ "-DLOGTAG=\"libbufferhubqueue\"" ],
+    cflags = [
+        "-DLOGTAG=\"libbufferhubqueue\"",
+        "-DTRACE=0",
+    ],
     srcs: sourceFiles,
     export_include_dirs: includeFiles,
     export_static_lib_headers: staticLibraries,
@@ -50,3 +53,4 @@
     shared_libs: sharedLibraries,
 }
 
+subdirs = ["tests"]
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index a8077b9..bd6511d 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -1,7 +1,5 @@
 #include "include/private/dvr/buffer_hub_queue_client.h"
 
-//#define LOG_NDEBUG 0
-
 #include <inttypes.h>
 #include <log/log.h>
 #include <sys/epoll.h>
@@ -73,7 +71,8 @@
 
   auto return_value = status.take();
 
-  ALOGD("CreateConsumerQueue: meta_size_bytes=%zu", return_value.second);
+  ALOGD_IF(TRACE, "BufferHubQueue::CreateConsumerQueue: meta_size_bytes=%zu",
+           return_value.second);
   return ConsumerQueue::Create(std::move(return_value.first),
                                return_value.second);
 }
@@ -85,7 +84,7 @@
     int ret = epoll_fd_.Wait(events.data(), events.size(), timeout);
 
     if (ret == 0) {
-      ALOGD("Wait on epoll returns nothing before timeout.");
+      ALOGD_IF(TRACE, "Wait on epoll returns nothing before timeout.");
       return false;
     }
 
@@ -102,7 +101,7 @@
     for (int i = 0; i < num_events; i++) {
       int64_t index = static_cast<int64_t>(events[i].data.u64);
 
-      ALOGD("New BufferHubQueue event %d: index=%" PRId64, i, index);
+      ALOGD_IF(TRACE, "New BufferHubQueue event %d: index=%" PRId64, i, index);
 
       if (is_buffer_event_index(index)) {
         HandleBufferEvent(static_cast<size_t>(index), events[i]);
@@ -255,7 +254,7 @@
                                                          size_t* slot,
                                                          void* meta,
                                                          LocalHandle* fence) {
-  ALOGD("Dequeue: count=%zu, timeout=%d", count(), timeout);
+  ALOGD_IF(TRACE, "Dequeue: count=%zu, timeout=%d", count(), timeout);
 
   if (count() == 0 && !WaitForBuffers(timeout))
     return nullptr;
@@ -341,8 +340,9 @@
   // We only allocate one buffer at a time.
   auto& buffer_handle = buffer_handle_slots[0].first;
   size_t buffer_slot = buffer_handle_slots[0].second;
-  ALOGD("ProducerQueue::AllocateBuffer, new buffer, channel_handle: %d",
-        buffer_handle.value());
+  ALOGD_IF(TRACE,
+           "ProducerQueue::AllocateBuffer, new buffer, channel_handle: %d",
+           buffer_handle.value());
 
   *out_slot = buffer_slot;
   return AddBuffer(BufferProducer::Import(std::move(buffer_handle)),
@@ -414,8 +414,9 @@
 
   auto buffer_handle_slots = status.take();
   for (auto& buffer_handle_slot : buffer_handle_slots) {
-    ALOGD("ConsumerQueue::ImportBuffers, new buffer, buffer_handle: %d",
-          buffer_handle_slot.first.value());
+    ALOGD_IF(TRACE,
+             "ConsumerQueue::ImportBuffers, new buffer, buffer_handle: %d",
+             buffer_handle_slot.first.value());
 
     std::unique_ptr<BufferConsumer> buffer_consumer =
         BufferConsumer::Import(std::move(buffer_handle_slot.first));
@@ -473,7 +474,7 @@
   } else if (ret < 0) {
     ALOGE("Failed to import buffers on buffer allocated event.");
   }
-  ALOGD("Imported %d consumer buffers.", ret);
+  ALOGD_IF(TRACE, "Imported %d consumer buffers.", ret);
   return ret;
 }
 
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_consumer.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_consumer.cpp
index 02bca09..1ea3994 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_consumer.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_consumer.cpp
@@ -1,7 +1,5 @@
 #include "include/private/dvr/buffer_hub_queue_consumer.h"
 
-//#define LOG_NDEBUG 0
-
 namespace android {
 namespace dvr {
 
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_core.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_core.cpp
index b013c85..a108042 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_core.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_core.cpp
@@ -1,8 +1,5 @@
 #include "include/private/dvr/buffer_hub_queue_core.h"
 
-//#define LOG_NDEBUG 0
-#define LOG_TAG "BufferHubQueueCore"
-
 #include <log/log.h>
 
 namespace android {
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
index 0deb764..ddf7fd2 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
@@ -1,7 +1,5 @@
 #include "include/private/dvr/buffer_hub_queue_producer.h"
 
-//#define LOG_NDEBUG 0
-
 #include <inttypes.h>
 #include <log/log.h>
 
@@ -14,7 +12,7 @@
 
 status_t BufferHubQueueProducer::requestBuffer(int slot,
                                                sp<GraphicBuffer>* buf) {
-  ALOGD("requestBuffer: slot=%d", slot);
+  ALOGD_IF(TRACE, "requestBuffer: slot=%d", slot);
 
   std::unique_lock<std::mutex> lock(core_->mutex_);
 
@@ -35,8 +33,8 @@
 
 status_t BufferHubQueueProducer::setMaxDequeuedBufferCount(
     int max_dequeued_buffers) {
-  ALOGD("setMaxDequeuedBufferCount: max_dequeued_buffers=%d",
-        max_dequeued_buffers);
+  ALOGD_IF(TRACE, "setMaxDequeuedBufferCount: max_dequeued_buffers=%d",
+           max_dequeued_buffers);
 
   std::unique_lock<std::mutex> lock(core_->mutex_);
 
@@ -63,8 +61,8 @@
                                                PixelFormat format,
                                                uint32_t usage,
                                                FrameEventHistoryDelta* /* outTimestamps */) {
-  ALOGD("dequeueBuffer: w=%u, h=%u, format=%d, usage=%u", width, height, format,
-        usage);
+  ALOGD_IF(TRACE, "dequeueBuffer: w=%u, h=%u, format=%d, usage=%u", width,
+           height, format, usage);
 
   status_t ret;
   std::unique_lock<std::mutex> lock(core_->mutex_);
@@ -134,7 +132,7 @@
 
   core_->buffers_[slot].mBufferState.freeQueued();
   core_->buffers_[slot].mBufferState.dequeue();
-  ALOGD("dequeueBuffer: slot=%zu", slot);
+  ALOGD_IF(TRACE, "dequeueBuffer: slot=%zu", slot);
 
   // TODO(jwcai) Handle fence properly. |BufferHub| has full fence support, we
   // just need to exopose that through |BufferHubQueue| once we need fence.
@@ -173,7 +171,7 @@
 status_t BufferHubQueueProducer::queueBuffer(int slot,
                                              const QueueBufferInput& input,
                                              QueueBufferOutput* /* output */) {
-  ALOGD("queueBuffer: slot %d", slot);
+  ALOGD_IF(TRACE, "queueBuffer: slot %d", slot);
 
   int64_t timestamp;
   sp<Fence> fence;
@@ -220,7 +218,7 @@
 
 status_t BufferHubQueueProducer::cancelBuffer(int slot,
                                               const sp<Fence>& fence) {
-  ALOGD(__FUNCTION__);
+  ALOGD_IF(TRACE, __FUNCTION__);
 
   std::unique_lock<std::mutex> lock(core_->mutex_);
 
@@ -241,13 +239,13 @@
   core_->producer_->Enqueue(buffer_producer, slot);
   core_->buffers_[slot].mBufferState.cancel();
   core_->buffers_[slot].mFence = fence;
-  ALOGD("cancelBuffer: slot %d", slot);
+  ALOGD_IF(TRACE, "cancelBuffer: slot %d", slot);
 
   return NO_ERROR;
 }
 
 status_t BufferHubQueueProducer::query(int what, int* out_value) {
-  ALOGD(__FUNCTION__);
+  ALOGD_IF(TRACE, __FUNCTION__);
 
   std::unique_lock<std::mutex> lock(core_->mutex_);
 
@@ -278,7 +276,7 @@
       return BAD_VALUE;
   }
 
-  ALOGD("query: key=%d, v=%d", what, value);
+  ALOGD_IF(TRACE, "query: key=%d, v=%d", what, value);
   *out_value = value;
   return NO_ERROR;
 }
@@ -288,14 +286,14 @@
     bool /* producer_controlled_by_app */, QueueBufferOutput* /* output */) {
   // Consumer interaction are actually handled by buffer hub, and we need
   // to maintain consumer operations here. Hence |connect| is a NO-OP.
-  ALOGD(__FUNCTION__);
+  ALOGD_IF(TRACE, __FUNCTION__);
   return NO_ERROR;
 }
 
 status_t BufferHubQueueProducer::disconnect(int /* api */, DisconnectMode /* mode */) {
   // Consumer interaction are actually handled by buffer hub, and we need
   // to maintain consumer operations here. Hence |disconnect| is a NO-OP.
-  ALOGD(__FUNCTION__);
+  ALOGD_IF(TRACE, __FUNCTION__);
   return NO_ERROR;
 }
 
@@ -327,7 +325,7 @@
 
 status_t BufferHubQueueProducer::setGenerationNumber(
     uint32_t generation_number) {
-  ALOGD(__FUNCTION__);
+  ALOGD_IF(TRACE, __FUNCTION__);
 
   std::unique_lock<std::mutex> lock(core_->mutex_);
   core_->generation_number_ = generation_number;
@@ -354,7 +352,7 @@
 }
 
 status_t BufferHubQueueProducer::setDequeueTimeout(nsecs_t timeout) {
-  ALOGD(__FUNCTION__);
+  ALOGD_IF(TRACE, __FUNCTION__);
 
   std::unique_lock<std::mutex> lock(core_->mutex_);
   core_->dequeue_timeout_ms_ = static_cast<int>(timeout / (1000 * 1000));
@@ -374,7 +372,7 @@
 }
 
 status_t BufferHubQueueProducer::getUniqueId(uint64_t* out_id) const {
-  ALOGD(__FUNCTION__);
+  ALOGD_IF(TRACE, __FUNCTION__);
 
   *out_id = core_->unique_id_;
   return NO_ERROR;
diff --git a/libs/vr/libeds/Android.bp b/libs/vr/libeds/Android.bp
index 7838c4d..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",
 ]
 
diff --git a/libs/vr/libpdx/private/pdx/rpc/function_traits.h b/libs/vr/libpdx/private/pdx/rpc/function_traits.h
index 5fdad72..7641b0a 100644
--- a/libs/vr/libpdx/private/pdx/rpc/function_traits.h
+++ b/libs/vr/libpdx/private/pdx/rpc/function_traits.h
@@ -43,6 +43,12 @@
       SignatureType<ConditionalRewrite<Return_, ReturnType>(
           ConditionalRewrite<Args_, Params>...)>;
 
+  template <template <typename> class Wrapper, typename ReturnType,
+            typename... Params>
+  using RewriteSignatureWrapReturn =
+      SignatureType<Wrapper<ConditionalRewrite<Return_, ReturnType>>(
+          ConditionalRewrite<Args_, Params>...)>;
+
   template <typename ReturnType>
   using RewriteReturn =
       SignatureType<ConditionalRewrite<Return_, ReturnType>(Args_...)>;
diff --git a/libs/vr/libpdx/private/pdx/rpc/remote_method.h b/libs/vr/libpdx/private/pdx/rpc/remote_method.h
index 679503c..e5c6616 100644
--- a/libs/vr/libpdx/private/pdx/rpc/remote_method.h
+++ b/libs/vr/libpdx/private/pdx/rpc/remote_method.h
@@ -10,6 +10,7 @@
 #include <pdx/rpc/payload.h>
 #include <pdx/rpc/remote_method_type.h>
 #include <pdx/service.h>
+#include <pdx/status.h>
 
 namespace android {
 namespace pdx {
@@ -157,6 +158,25 @@
            strerror(-ret));
 }
 
+// Overload for Status<void> return types.
+template <typename RemoteMethodType>
+void RemoteMethodReturn(Message& message, const Status<void>& return_value) {
+  if (return_value)
+    RemoteMethodReturn<RemoteMethodType>(message, 0);
+  else
+    RemoteMethodError(message, return_value.error());
+}
+
+// Overload for Status<T> return types. This overload forwards the underlying
+// value or error within the Status<T>.
+template <typename RemoteMethodType, typename Return>
+void RemoteMethodReturn(Message& message, const Status<Return>& return_value) {
+  if (return_value)
+    RemoteMethodReturn<RemoteMethodType, Return>(message, return_value.get());
+  else
+    RemoteMethodError(message, return_value.error());
+}
+
 // Dispatches a method by deserializing arguments from the given Message, with
 // compile-time interface check. Overload for void return types.
 template <typename RemoteMethodType, typename Class, typename... Args,
@@ -340,6 +360,46 @@
     RemoteMethodReturn<RemoteMethodType>(message, return_value);
 }
 
+// Dispatches a method by deserializing arguments from the given Message, with
+// compile-time interface signature check. Overload for Status<T> return types.
+template <typename RemoteMethodType, typename Class, typename Return,
+          typename... Args, typename = EnableIfNotVoidMethod<RemoteMethodType>>
+void DispatchRemoteMethod(Class& instance,
+                          Status<Return> (Class::*method)(Message&, Args...),
+                          Message& message,
+                          std::size_t max_capacity = InitialBufferCapacity) {
+  using Signature =
+      typename RemoteMethodType::template RewriteSignature<Return, Args...>;
+  using InvokeSignature =
+      typename RemoteMethodType::template RewriteSignatureWrapReturn<
+          Status, Return, Args...>;
+  rpc::ServicePayload<ReceiveBuffer> payload(message);
+  payload.Resize(max_capacity);
+
+  auto size = message.Read(payload.Data(), payload.Size());
+  if (size < 0) {
+    RemoteMethodError(message, -size);
+    return;
+  }
+
+  payload.Resize(size);
+
+  ErrorType error;
+  auto decoder = MakeArgumentDecoder<Signature>(&payload);
+  auto arguments = decoder.DecodeArguments(&error);
+  if (error) {
+    RemoteMethodError(message, EIO);
+    return;
+  }
+
+  auto return_value = UnpackArguments<Class, InvokeSignature>(
+                          instance, method, message, arguments)
+                          .Invoke();
+  // Return the value to the caller unless the message was moved.
+  if (message)
+    RemoteMethodReturn<RemoteMethodType>(message, return_value);
+}
+
 #ifdef __clang__
 // Overloads to handle Void argument type without exploding clang.
 
@@ -399,6 +459,18 @@
   if (message)
     RemoteMethodReturn<RemoteMethodType>(message, return_value);
 }
+
+// Overload for Status<T> return type.
+template <typename RemoteMethodType, typename Class, typename Return,
+          typename = EnableIfVoidMethod<RemoteMethodType>>
+void DispatchRemoteMethod(Class& instance,
+                          Status<Return> (Class::*method)(Message&),
+                          Message& message) {
+  auto return_value = (instance.*method)(message);
+  // Return the value to the caller unless the message was moved.
+  if (message)
+    RemoteMethodReturn<RemoteMethodType>(message, return_value);
+}
 #endif
 
 }  // namespace rpc
diff --git a/libs/vr/libpdx/private/pdx/rpc/remote_method_type.h b/libs/vr/libpdx/private/pdx/rpc/remote_method_type.h
index de9a3cc..cf9a189 100644
--- a/libs/vr/libpdx/private/pdx/rpc/remote_method_type.h
+++ b/libs/vr/libpdx/private/pdx/rpc/remote_method_type.h
@@ -31,6 +31,12 @@
   using RewriteSignature =
       typename Traits::template RewriteSignature<ReturnType, Params...>;
 
+  template <template <typename> class Wrapper, typename ReturnType,
+            typename... Params>
+  using RewriteSignatureWrapReturn =
+      typename Traits::template RewriteSignatureWrapReturn<Wrapper, ReturnType,
+                                                           Params...>;
+
   template <typename ReturnType>
   using RewriteReturn = typename Traits::template RewriteReturn<ReturnType>;
 };
diff --git a/libs/vr/libpdx/thread_local_buffer_tests.cpp b/libs/vr/libpdx/thread_local_buffer_tests.cpp
index c6a7b0b..1747d79 100644
--- a/libs/vr/libpdx/thread_local_buffer_tests.cpp
+++ b/libs/vr/libpdx/thread_local_buffer_tests.cpp
@@ -89,8 +89,9 @@
   EXPECT_NE(id1, id2);
 }
 
+// TODO(b/36456321): Fix this and enable it again.
 // Tests that thread-local buffers are allocated at the first buffer request.
-TEST(ThreadLocalBufferTest, InitialValue) {
+TEST(ThreadLocalBufferTest, DISABLED_InitialValue) {
   struct TypeTagX;
   using SendSlotX = ThreadLocalSlot<TypeTagX, kSendBufferIndex>;
 
diff --git a/libs/vr/libpdx_uds/remote_method_tests.cpp b/libs/vr/libpdx_uds/remote_method_tests.cpp
index 299910c..9050500 100644
--- a/libs/vr/libpdx_uds/remote_method_tests.cpp
+++ b/libs/vr/libpdx_uds/remote_method_tests.cpp
@@ -23,6 +23,7 @@
 using android::pdx::BorrowedHandle;
 using android::pdx::Channel;
 using android::pdx::ClientBase;
+using android::pdx::ErrorStatus;
 using android::pdx::LocalChannelHandle;
 using android::pdx::LocalHandle;
 using android::pdx::Message;
@@ -36,6 +37,20 @@
 
 namespace {
 
+std::string Rot13(const std::string& s) {
+  std::string text = s;
+  std::transform(std::begin(text), std::end(text), std::begin(text),
+                 [](char c) -> char {
+                   if (!std::isalpha(c)) {
+                     return c;
+                   } else {
+                     const char pivot = std::isupper(c) ? 'A' : 'a';
+                     return (c - pivot + 13) % 26 + pivot;
+                   }
+                 });
+  return text;
+}
+
 // Defines a serializable user type that may be transferred between client and
 // service.
 struct TestType {
@@ -134,6 +149,7 @@
     kOpOpenFiles,
     kOpReadFile,
     kOpPushChannel,
+    kOpPositive,
   };
 
   // Methods.
@@ -161,10 +177,11 @@
                     std::pair<int, BufferWrapper<std::uint8_t*>>(
                         const std::string&, int, std::size_t));
   PDX_REMOTE_METHOD(PushChannel, kOpPushChannel, LocalChannelHandle(Void));
+  PDX_REMOTE_METHOD(Positive, kOpPositive, void(int));
 
   PDX_REMOTE_API(API, Add, Foo, Concatenate, SumVector, StringLength,
                  SendTestType, SendVector, Rot13, NoArgs, SendFile, GetFile,
-                 GetTestFdType, OpenFiles, PushChannel);
+                 GetTestFdType, OpenFiles, PushChannel, Positive);
 };
 
 constexpr char TestInterface::kClientPath[];
@@ -301,6 +318,11 @@
     return status ? 0 : -status.error();
   }
 
+  bool Positive(int test_value) {
+    auto status = InvokeRemoteMethod<TestInterface::Positive>(test_value);
+    return status.ok();
+  }
+
   int GetFd() const { return event_fd(); }
 
  private:
@@ -397,6 +419,11 @@
             *this, &TestService::OnPushChannel, message);
         return 0;
 
+      case TestInterface::Positive::Opcode:
+        DispatchRemoteMethod<TestInterface::Positive>(
+            *this, &TestService::OnPositive, message);
+        return 0;
+
       default:
         return Service::DefaultHandleMessage(message);
     }
@@ -438,18 +465,8 @@
     return return_value;
   }
 
-  std::string OnRot13(Message&, const std::string& s) {
-    std::string text = s;
-    std::transform(std::begin(text), std::end(text), std::begin(text),
-                   [](char c) -> char {
-                     if (!std::isalpha(c)) {
-                       return c;
-                     } else {
-                       const char pivot = std::isupper(c) ? 'A' : 'a';
-                       return (c - pivot + 13) % 26 + pivot;
-                     }
-                   });
-    return text;
+  Status<std::string> OnRot13(Message&, const std::string& s) {
+    return {Rot13(s)};
   }
 
   int OnNoArgs(Message&) { return 1; }
@@ -514,6 +531,13 @@
     return status.take();
   }
 
+  Status<void> OnPositive(Message& /*message*/, int test_value) {
+    if (test_value >= 0)
+      return {};
+    else
+      return ErrorStatus(EINVAL);
+  }
+
   TestService(const TestService&) = delete;
   void operator=(const TestService&) = delete;
 };
@@ -575,6 +599,10 @@
   const auto cat = client->Concatenate("This is a string", ", that it is.");
   EXPECT_EQ("This is a string, that it is.", cat);
 
+  std::string alphabet = "abcdefghijklmnopqrstuvwxyz";
+  const auto rot13_alphabet = client->Rot13(alphabet);
+  EXPECT_EQ(Rot13(alphabet), rot13_alphabet);
+
   const auto length = client->Foo(10, "123");
   EXPECT_EQ(13, length);
 
@@ -677,6 +705,21 @@
   EXPECT_GE(35, sum);
 }
 
+TEST_F(RemoteMethodTest, Positive) {
+  // Create a test service and add it to the dispatcher.
+  auto service = TestService::Create();
+  ASSERT_NE(nullptr, service);
+  ASSERT_EQ(0, dispatcher_->AddService(service));
+
+  // Create a client to service.
+  auto client = TestClient::Create();
+  ASSERT_NE(nullptr, client);
+
+  ASSERT_TRUE(client->Positive(0));
+  ASSERT_TRUE(client->Positive(1));
+  ASSERT_FALSE(client->Positive(-1));
+}
+
 TEST_F(RemoteMethodTest, AggregateLocalHandle) {
   // Create a test service and add it to the dispatcher.
   auto service = TestService::Create();
diff --git a/libs/vr/libpdx_uds/service_framework_tests.cpp b/libs/vr/libpdx_uds/service_framework_tests.cpp
index 8891600..9e31e82 100644
--- a/libs/vr/libpdx_uds/service_framework_tests.cpp
+++ b/libs/vr/libpdx_uds/service_framework_tests.cpp
@@ -26,6 +26,7 @@
 using android::pdx::Channel;
 using android::pdx::ChannelReference;
 using android::pdx::ClientBase;
+using android::pdx::ErrorStatus;
 using android::pdx::LocalChannelHandle;
 using android::pdx::LocalHandle;
 using android::pdx::Message;
@@ -379,6 +380,14 @@
                         data_array.size() * sizeof(int), nullptr, 0));
   }
 
+  Status<int> GetEventMask(int events) {
+    if (auto* client_channel = GetChannel()) {
+      return client_channel->GetEventMask(events);
+    } else {
+      return ErrorStatus(EINVAL);
+    }
+  }
+
   using ClientBase<TestClient>::event_fd;
 
   enum : size_t { kMaxPayload = MAX_IMPULSE_LENGTH };
@@ -634,7 +643,9 @@
 
   count = epoll_wait(client->event_fd(), &event, 1, -1);
   ASSERT_EQ(1, count);
-  ASSERT_TRUE((EPOLLHUP & event.events) != 0);
+  auto event_status = client->GetEventMask(event.events);
+  ASSERT_TRUE(event_status.ok());
+  ASSERT_TRUE((EPOLLHUP & event_status.get()) != 0);
 }
 
 TEST_F(ServiceFrameworkTest, LargeDataSum) {
diff --git a/libs/vr/libvrsensor/Android.bp b/libs/vr/libvrsensor/Android.bp
index f201ea6..6d48f18 100644
--- a/libs/vr/libvrsensor/Android.bp
+++ b/libs/vr/libvrsensor/Android.bp
@@ -34,6 +34,7 @@
     "libhardware",
     "liblog",
     "libutils",
+    "libui",
 ]
 
 cc_library {
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\" \
diff --git a/services/vr/virtual_touchpad/Android.bp b/services/vr/virtual_touchpad/Android.bp
index ad999b7..c8bc884 100644
--- a/services/vr/virtual_touchpad/Android.bp
+++ b/services/vr/virtual_touchpad/Android.bp
@@ -94,6 +94,7 @@
 
 client_src = [
     "VirtualTouchpadClient.cpp",
+    "DvrVirtualTouchpadClient.cpp",
     "aidl/android/dvr/VirtualTouchpadService.aidl",
 ]
 
diff --git a/services/vr/virtual_touchpad/DvrVirtualTouchpadClient.cpp b/services/vr/virtual_touchpad/DvrVirtualTouchpadClient.cpp
new file mode 100644
index 0000000..eb152ed
--- /dev/null
+++ b/services/vr/virtual_touchpad/DvrVirtualTouchpadClient.cpp
@@ -0,0 +1,45 @@
+#include "VirtualTouchpadClient.h"
+#include "dvr/virtual_touchpad_client.h"
+
+struct DvrVirtualTouchpad {};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+namespace {
+android::dvr::VirtualTouchpad* FromC(DvrVirtualTouchpad* client) {
+  return reinterpret_cast<android::dvr::VirtualTouchpad*>(client);
+}
+}  // namespace
+
+DvrVirtualTouchpad* dvrVirtualTouchpadCreate() {
+  return reinterpret_cast<DvrVirtualTouchpad*>(
+      android::dvr::VirtualTouchpadClient::Create().release());
+}
+
+void dvrVirtualTouchpadDestroy(DvrVirtualTouchpad* client) {
+  delete FromC(client);
+}
+
+int dvrVirtualTouchpadAttach(DvrVirtualTouchpad* client) {
+  return FromC(client)->Attach();
+}
+
+int dvrVirtualTouchpadDetach(DvrVirtualTouchpad* client) {
+  return FromC(client)->Detach();
+}
+
+int dvrVirtualTouchpadTouch(DvrVirtualTouchpad* client, int touchpad, float x,
+                            float y, float pressure) {
+  return FromC(client)->Touch(touchpad, x, y, pressure);
+}
+
+int dvrVirtualTouchpadButtonState(DvrVirtualTouchpad* client, int touchpad,
+                                  int buttons) {
+  return FromC(client)->ButtonState(touchpad, buttons);
+}
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp b/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp
index 782b19c..c7c8184 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp
@@ -72,8 +72,8 @@
 
 }  // anonymous namespace
 
-sp<VirtualTouchpad> VirtualTouchpadClient::Create() {
-  return new VirtualTouchpadClientImpl();
+std::unique_ptr<VirtualTouchpad> VirtualTouchpadClient::Create() {
+  return std::unique_ptr<VirtualTouchpad>(new VirtualTouchpadClientImpl());
 }
 
 }  // namespace dvr
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
index 92193d3..ee09d48 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
@@ -30,10 +30,10 @@
 
 }  // anonymous namespace
 
-sp<VirtualTouchpad> VirtualTouchpadEvdev::Create() {
-  VirtualTouchpadEvdev* const touchpad = new VirtualTouchpadEvdev();
+std::unique_ptr<VirtualTouchpad> VirtualTouchpadEvdev::Create() {
+  std::unique_ptr<VirtualTouchpadEvdev> touchpad(new VirtualTouchpadEvdev());
   touchpad->Reset();
-  return sp<VirtualTouchpad>(touchpad);
+  return touchpad;
 }
 
 void VirtualTouchpadEvdev::Reset() {
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
index dbaca9a..2fb8ff3 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
+++ b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
@@ -1,8 +1,6 @@
 #ifndef ANDROID_DVR_VIRTUAL_TOUCHPAD_EVDEV_H
 #define ANDROID_DVR_VIRTUAL_TOUCHPAD_EVDEV_H
 
-#include <memory>
-
 #include "EvdevInjector.h"
 #include "VirtualTouchpad.h"
 
@@ -15,7 +13,8 @@
 //
 class VirtualTouchpadEvdev : public VirtualTouchpad {
  public:
-  static sp<VirtualTouchpad> Create();
+  static std::unique_ptr<VirtualTouchpad> Create();
+  ~VirtualTouchpadEvdev() override {}
 
   // VirtualTouchpad implementation:
   status_t Attach() override;
@@ -28,7 +27,6 @@
   static constexpr int kTouchpads = 2;
 
   VirtualTouchpadEvdev() {}
-  ~VirtualTouchpadEvdev() override {}
   void Reset();
 
   // Must be called only between construction (or Detach()) and Attach().
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.h b/services/vr/virtual_touchpad/VirtualTouchpadService.h
index 194d787..cf236f9 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadService.h
+++ b/services/vr/virtual_touchpad/VirtualTouchpadService.h
@@ -13,8 +13,8 @@
 //
 class VirtualTouchpadService : public BnVirtualTouchpadService {
  public:
-  VirtualTouchpadService(sp<VirtualTouchpad> touchpad)
-      : touchpad_(touchpad), client_pid_(0) {}
+  VirtualTouchpadService(std::unique_ptr<VirtualTouchpad> touchpad)
+      : touchpad_(std::move(touchpad)), client_pid_(0) {}
   ~VirtualTouchpadService() override;
 
  protected:
@@ -31,7 +31,7 @@
   bool CheckPermissions();
   bool CheckTouchPermission(pid_t* out_pid);
 
-  sp<VirtualTouchpad> touchpad_;
+  std::unique_ptr<VirtualTouchpad> touchpad_;
 
   // Only one client at a time can use the virtual touchpad.
   pid_t client_pid_;
diff --git a/services/vr/virtual_touchpad/include/VirtualTouchpad.h b/services/vr/virtual_touchpad/include/VirtualTouchpad.h
index b1ee700..da3a0b7 100644
--- a/services/vr/virtual_touchpad/include/VirtualTouchpad.h
+++ b/services/vr/virtual_touchpad/include/VirtualTouchpad.h
@@ -1,31 +1,34 @@
 #ifndef ANDROID_DVR_VIRTUAL_TOUCHPAD_INTERFACE_H
 #define ANDROID_DVR_VIRTUAL_TOUCHPAD_INTERFACE_H
 
+#include "dvr/virtual_touchpad_client.h"
+
+#include <memory>
 #include <utils/Errors.h>
-#include <utils/RefBase.h>
 #include <utils/String8.h>
-#include <utils/StrongPointer.h>
 
 namespace android {
 namespace dvr {
 
 // Provides a virtual touchpad for injecting events into the input system.
 //
-class VirtualTouchpad : public RefBase {
+class VirtualTouchpad {
  public:
   enum : int {
-    PRIMARY = 0,
-    VIRTUAL = 1,
+    PRIMARY = DVR_VIRTUAL_TOUCHPAD_PRIMARY,
+    VIRTUAL = DVR_VIRTUAL_TOUCHPAD_VIRTUAL,
   };
 
+  virtual ~VirtualTouchpad() {}
+
   // Create a virtual touchpad.
   // Implementations should provide this, and hide their constructors.
   // For the user, switching implementations should be as simple as changing
   // the class whose |Create()| is called.
   // Implementations should be minimial; major resource allocation should
   // be performed in Attach().
-  static sp<VirtualTouchpad> Create() {
-    return sp<VirtualTouchpad>();
+  static std::unique_ptr<VirtualTouchpad> Create() {
+    return nullptr;
   }
 
   // Initialize a virtual touchpad.
@@ -63,7 +66,6 @@
 
  protected:
   VirtualTouchpad() {}
-  ~VirtualTouchpad() override {}
 
  private:
   VirtualTouchpad(const VirtualTouchpad&) = delete;
diff --git a/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h b/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h
index 471d9e0..23fb9f8 100644
--- a/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h
+++ b/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h
@@ -12,7 +12,7 @@
 class VirtualTouchpadClient : public VirtualTouchpad {
  public:
   // VirtualTouchpad implementation:
-  static sp<VirtualTouchpad> Create();
+  static std::unique_ptr<VirtualTouchpad> Create();
   status_t Attach() override;
   status_t Detach() override;
   status_t Touch(int touchpad, float x, float y, float pressure) override;
diff --git a/services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h b/services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h
new file mode 100644
index 0000000..08cca1b
--- /dev/null
+++ b/services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h
@@ -0,0 +1,71 @@
+#ifndef ANDROID_DVR_VIRTUAL_TOUCHPAD_C_CLIENT_H
+#define ANDROID_DVR_VIRTUAL_TOUCHPAD_C_CLIENT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct DvrVirtualTouchpad DvrVirtualTouchpad;
+
+enum {
+  DVR_VIRTUAL_TOUCHPAD_PRIMARY = 0,
+  DVR_VIRTUAL_TOUCHPAD_VIRTUAL = 1,
+};
+
+// Creates a new virtual touchpad client.
+//
+// @return Pointer to the created virtual touchpad client; nullptr on failure.
+//
+DvrVirtualTouchpad* dvrVirtualTouchpadCreate();
+
+// Destroys a virtual touchpad client.
+//
+// @param client Pointer to the virtual touchpad client to be destroyed.
+//
+void dvrVirtualTouchpadDestroy(DvrVirtualTouchpad* client);
+
+// Initialize the virtual touchpad.
+//
+// In the current server implementation, attachment creates and configures
+// the kernel virtual touchpad device(s). A single client may be attached
+// and detached repeatedly, e.g. on entering and leaving VR mode.
+//
+// @param client Pointer to the virtual touchpad client to be attached.
+// @return Zero on success, status_t-style error code on failure.
+//
+int dvrVirtualTouchpadAttach(DvrVirtualTouchpad* client);
+
+// Shut down the virtual touchpad.
+//
+// @param client Pointer to the virtual touchpad client to be detached.
+// @return Zero on success, status_t-style error code on failure.
+//
+int dvrVirtualTouchpadDetach(DvrVirtualTouchpad* client);
+
+// Generate a simulated touch event.
+//
+// @param client Pointer to the virtual touchpad client.
+// @param touchpad Selects touchpad.
+// @param x Horizontal touch position.
+// @param y Vertical touch position.
+// @param pressure Touch pressure; use 0.0 for no touch (lift or hover).
+// @return Zero on success, status_t-style error code on failure.
+//
+int dvrVirtualTouchpadTouch(DvrVirtualTouchpad* client, int touchpad, float x,
+                            float y, float pressure);
+
+// Generate a simulated touchpad button state event.
+//
+// @param client Pointer to the virtual touchpad client.
+// @param touchpad Selects touchpad.
+// @param buttons A union of MotionEvent BUTTON_* values.
+// @return Zero on success, status_t-style error code on failure.
+//
+int dvrVirtualTouchpadButtonState(DvrVirtualTouchpad* client, int touchpad,
+                                  int buttons);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // ANDROID_DVR_VIRTUAL_TOUCHPAD_CLIENT_H
diff --git a/services/vr/virtual_touchpad/main.cpp b/services/vr/virtual_touchpad/main.cpp
index e73f8b9..68f1d70 100644
--- a/services/vr/virtual_touchpad/main.cpp
+++ b/services/vr/virtual_touchpad/main.cpp
@@ -9,7 +9,7 @@
 int main() {
   ALOGI("Starting");
   android::dvr::VirtualTouchpadService touchpad_service(
-      android::dvr::VirtualTouchpadEvdev::Create());
+      std::move(android::dvr::VirtualTouchpadEvdev::Create()));
 
   signal(SIGPIPE, SIG_IGN);
   android::sp<android::ProcessState> ps(android::ProcessState::self());
diff --git a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
index bc34850..24cfdf8 100644
--- a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
+++ b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
@@ -95,7 +95,9 @@
 
 class VirtualTouchpadForTesting : public VirtualTouchpadEvdev {
  public:
-  static sp<VirtualTouchpad> Create() { return sp<VirtualTouchpad>(New()); }
+  static std::unique_ptr<VirtualTouchpad> Create() {
+    return std::unique_ptr<VirtualTouchpad>(New());
+  }
   static VirtualTouchpadForTesting* New() {
     VirtualTouchpadForTesting* const touchpad = new VirtualTouchpadForTesting();
     touchpad->Reset();
@@ -124,7 +126,8 @@
 class VirtualTouchpadTest : public testing::Test {};
 
 TEST_F(VirtualTouchpadTest, Goodness) {
-  sp<VirtualTouchpadForTesting> touchpad(VirtualTouchpadForTesting::New());
+  std::unique_ptr<VirtualTouchpadForTesting> touchpad(
+      VirtualTouchpadForTesting::New());
   UInputRecorder expect;
 
   status_t touch_status = touchpad->Attach();
@@ -284,7 +287,8 @@
 }
 
 TEST_F(VirtualTouchpadTest, Badness) {
-  sp<VirtualTouchpadForTesting> touchpad(VirtualTouchpadForTesting::New());
+  std::unique_ptr<VirtualTouchpadForTesting> touchpad(
+      VirtualTouchpadForTesting::New());
   UInputRecorder expect;
   UInputRecorder& record = touchpad->injector[VirtualTouchpad::PRIMARY].record;
 
diff --git a/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
index 60ca818..684d15b 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
+++ b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
@@ -240,12 +240,14 @@
   }
 }
 
-uint32_t VrHwc::getMaxVirtualDisplayCount() { return 0; }
+uint32_t VrHwc::getMaxVirtualDisplayCount() { return 1; }
 
 Error VrHwc::createVirtualDisplay(uint32_t width, uint32_t height,
                                   PixelFormat* format, Display* outDisplay) {
   *format = PixelFormat::RGBA_8888;
-  *outDisplay = 0;
+  *outDisplay = display_count_;
+  displays_[display_count_].reset(new HwcDisplay());
+  display_count_++;
   return Error::NONE;
 }
 
@@ -356,7 +358,11 @@
     return Error::BAD_DISPLAY;
   }
 
-  *outType = IComposerClient::DisplayType::PHYSICAL;
+  if (display == kDefaultDisplayId)
+    *outType = IComposerClient::DisplayType::PHYSICAL;
+  else
+    *outType = IComposerClient::DisplayType::VIRTUAL;
+
   return Error::NONE;
 }
 
@@ -443,8 +449,8 @@
   if (!display_ptr)
     return Error::BAD_DISPLAY;
 
-  ALOGE("Virtual display support not implemented");
-  return Error::UNSUPPORTED;
+  // TODO(dnicoara): Is it necessary to do anything here?
+  return Error::NONE;
 }
 
 Error VrHwc::validateDisplay(
diff --git a/services/vr/vr_window_manager/composer/impl/vr_hwc.h b/services/vr/vr_window_manager/composer/impl/vr_hwc.h
index b869d3e..3c76120 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_hwc.h
+++ b/services/vr/vr_window_manager/composer/impl/vr_hwc.h
@@ -248,6 +248,7 @@
   std::mutex mutex_;
 
   std::unordered_map<Display, std::unique_ptr<HwcDisplay>> displays_;
+  Display display_count_ = 2;
 
   Observer* observer_ = nullptr;
 
diff --git a/services/vr/vr_window_manager/shell_view.cpp b/services/vr/vr_window_manager/shell_view.cpp
index 72a2c26..a21e883 100644
--- a/services/vr/vr_window_manager/shell_view.cpp
+++ b/services/vr/vr_window_manager/shell_view.cpp
@@ -5,6 +5,7 @@
 #include <android/input.h>
 #include <binder/IServiceManager.h>
 #include <hardware/hwcomposer2.h>
+#include <inttypes.h>
 #include <log/log.h>
 
 #include "controller_mesh.h"
@@ -95,7 +96,8 @@
 }
 
 int GetTouchIdForDisplay(uint32_t display) {
-  return display == 1 ? VirtualTouchpad::PRIMARY : VirtualTouchpad::VIRTUAL;
+  return display == 1 ? DVR_VIRTUAL_TOUCHPAD_PRIMARY
+                      : DVR_VIRTUAL_TOUCHPAD_VIRTUAL;
 }
 
 }  // namespace
@@ -109,8 +111,9 @@
   if (ret)
     return ret;
 
-  virtual_touchpad_ = VirtualTouchpadClient::Create();
-  const status_t touchpad_status = virtual_touchpad_->Attach();
+  virtual_touchpad_.reset(dvrVirtualTouchpadCreate());
+  const status_t touchpad_status =
+      dvrVirtualTouchpadAttach(virtual_touchpad_.get());
   if (touchpad_status != OK) {
     ALOGE("Failed to connect to virtual touchpad");
     return touchpad_status;
@@ -164,13 +167,11 @@
 }
 
 void ShellView::EnableDebug(bool debug) {
-  ALOGI("EnableDebug(%d)", (int)debug);  // XXX TODO delete
   QueueTask(debug ? MainThreadTask::EnableDebugMode
                   : MainThreadTask::DisableDebugMode);
 }
 
 void ShellView::VrMode(bool mode) {
-  ALOGI("VrMode(%d)", (int)mode);  // XXX TODO delete
   QueueTask(mode ? MainThreadTask::EnteringVrMode
                  : MainThreadTask::ExitingVrMode);
 }
@@ -180,6 +181,13 @@
   result.appendFormat("initialized = %s\n", initialized_ ? "true" : "false");
   result.appendFormat("is_visible = %s\n", is_visible_ ? "true" : "false");
   result.appendFormat("debug_mode = %s\n\n", debug_mode_ ? "true" : "false");
+
+  result.append("[displays]\n");
+  result.appendFormat("count = %zu\n", displays_.size());
+  for (size_t i = 0; i < displays_.size(); ++i)
+    result.appendFormat(" display_id = %" PRId32 "\n", displays_[i]->id());
+
+  result.append("\n");
 }
 
 void ShellView::OnDrawFrame() {
@@ -419,7 +427,7 @@
 }
 
 void ShellView::Touch() {
-  if (!virtual_touchpad_.get()) {
+  if (!virtual_touchpad_) {
     ALOGE("missing virtual touchpad");
     return;
   }
@@ -431,8 +439,8 @@
 
   // Device is portrait, but in landscape when in VR.
   // Rotate touch input appropriately.
-  const android::status_t status = virtual_touchpad_->Touch(
-      active_display_->touchpad_id(),
+  const android::status_t status = dvrVirtualTouchpadTouch(
+      virtual_touchpad_.get(), active_display_->touchpad_id(),
       1.0f - hit_location.y() / size_.y(), hit_location.x() / size_.x(),
       is_touching_ ? 1.0f : 0.0f);
   if (status != OK) {
@@ -453,7 +461,7 @@
     return true;
   }
   touchpad_buttons_ = buttons;
-  if (!virtual_touchpad_.get()) {
+  if (!virtual_touchpad_) {
     ALOGE("missing virtual touchpad");
     return false;
   }
@@ -461,8 +469,9 @@
   if (!active_display_)
     return true;
 
-  const android::status_t status = virtual_touchpad_->ButtonState(
-      active_display_->touchpad_id(), touchpad_buttons_);
+  const android::status_t status = dvrVirtualTouchpadButtonState(
+      virtual_touchpad_.get(), active_display_->touchpad_id(),
+      touchpad_buttons_);
   if (status != OK) {
     ALOGE("touchpad button failed: %d %d", touchpad_buttons_, status);
   }
diff --git a/services/vr/vr_window_manager/shell_view.h b/services/vr/vr_window_manager/shell_view.h
index c10bd27..856c8b8 100644
--- a/services/vr/vr_window_manager/shell_view.h
+++ b/services/vr/vr_window_manager/shell_view.h
@@ -1,12 +1,12 @@
 #ifndef VR_WINDOW_MANAGER_SHELL_VIEW_H_
 #define VR_WINDOW_MANAGER_SHELL_VIEW_H_
 
+#include <dvr/virtual_touchpad_client.h>
 #include <private/dvr/graphics/mesh.h>
 #include <private/dvr/graphics/shader_program.h>
 
 #include <deque>
 
-#include "VirtualTouchpadClient.h"
 #include "application.h"
 #include "display_view.h"
 #include "reticle.h"
@@ -53,7 +53,6 @@
   DisplayView* FindActiveDisplay(const vec3& position, const quat& quaternion,
                                  vec3* hit_location);
 
-
   // HwcCallback::Client:
   base::unique_fd OnFrame(std::unique_ptr<HwcCallback::Frame> frame) override;
   DisplayView* FindOrCreateDisplay(uint32_t id);
@@ -64,7 +63,15 @@
 
   std::unique_ptr<SurfaceFlingerView> surface_flinger_view_;
   std::unique_ptr<Reticle> reticle_;
-  sp<VirtualTouchpad> virtual_touchpad_;
+
+  struct DvrVirtualTouchpadDeleter {
+    void operator()(DvrVirtualTouchpad* p) {
+      dvrVirtualTouchpadDetach(p);
+      dvrVirtualTouchpadDestroy(p);
+    }
+  };
+  std::unique_ptr<DvrVirtualTouchpad, DvrVirtualTouchpadDeleter>
+      virtual_touchpad_;
 
   std::unique_ptr<Mesh<vec3, vec3, vec2>> controller_mesh_;